Image mode for Red Hat Enterprise Linux (RHEL) represents a container-native way to build, configure, install, deploy, and manage RHEL. With Red Hat Satellite, systems administrators can manage fleets of image mode machines just like traditional RHEL machines. This tutorial teaches you how to provision image mode machines using Satellite's network and image-based provisioning features.
Image mode for Red Hat Enterprise Linux provides a method to build a complete system from a single file (also known as a Containerfile). Updates to image mode systems are downloaded and stored on the system before they are applied simultaneously in a single operation. If required, updates can be completely reversed to the previous state, without restoring data from backups.
There are three image mode RHEL provisioning strategies. This article focuses on using Anaconda to automate installation using existing Satellite provisioning features.
Image mode and kickstart
Kickstart scripts automate RHEL installations with Anaconda. In Satellite, kickstart scripts are stored as provisioning templates of the type "provisioning template". By default, Anaconda uses the "kickstart default" template, which performs tasks such as setting the root password, registering the host to the Red Hat CDN, and configuring remote execution SSH keys.
The combination of Anaconda's support for the ostreecontainer command and Satellite's provisioning template feature means that image mode provisioning is possible without changes to Satellite's code.
The ostreecontainer kickstart command only requires one argument: A pullable path to a container image. The path format is the same that podman accepts for podman pull:
ostreecontainer --url satellite.example.com/path/to/container:latestWith this command in place, Anaconda installs the machine in image mode.
Image mode provisioning with Anaconda kickstart follows these steps:
- A base RHEL operating system boots up and launches Anaconda.
- Anaconda executes the kickstart script
- The kickstart script installs the image mode container image to disk through
ostreecontainer - The kickstart script finishes
- The machine reboots in image mode with the contents of the container image
It is recommended that the major version of Anaconda used to provision the machine matches the major version of Anaconda within the container image.
Creating an image mode kickstart template in Satellite
Satellite provisioning templates are embedded Ruby (ERB) files. Administrators can use one provisioning template for different hosts because Ruby variables are injected into the script through ERB tags. To apply this to image mode provisioning, machines can share a template that provides a unique ostreecontainer command by using variables in the kickstart provisioning template.
The variables that populate provisioning templates come from either the host in Satellite or parameters configured at a higher scope. For example, all hosts in a Satellite host group could provision with the same container image after a parameter linked to an image mode provisioning template is created.
Because it's not officially compatible with all other kickstart commands, ostreecontainer cannot simply be added to any kickstart file. The documentation for ostreecontainer describes which commands can be used alongside it. For example, at the time of writing, RHEL 9 does not support the repo kickstart command, but the default kickstart template in Satellite uses the repo command to ensure BaseOS and AppStream are both available in the installation environment. To provision image mode with Satellite, you must create a new image mode kickstart template:
<%#
kind: provision
name: Kickstart Default bootc - Trimmed
model: ProvisioningTemplate
oses:
- RedHat
-%>
<%
# Variable setup for post scripts and container URL
ostreecontainer = host_param('ostreecontainer')
-%>
# This kickstart file was rendered from the Foreman provisioning template "<%= @template_name %>".
lang <%= host_param('lang') || 'en_US.UTF-8' %>
selinux --<%= host_param('selinux-mode') || 'enforcing' %>
keyboard <%= host_param('keyboard') || 'us' %>
<%
# Network setup is essential for pulling the container and reporting to Foreman
@host.interfaces.reject{ |iface| iface.bmc? }.sort_by { |iface| (iface.bond? || iface.bridge?) ? 0 : iface.provision? ? 20 : 10 }.each do |iface|
-%>
<%= snippet(
'kickstart_network_interface',
variables: {
iface: iface,
host: @host,
static: @static,
static6: @static6
}
) -%>
<%
end
-%>
# --- Core Installation ---
# 1. Set the container image as the installation source
ostreecontainer --url <%= ostreecontainer %>
# 2. Set the root password to make the system login-able
rootpw --iscrypted <%= root_pass %>
# 3. Allow SSH for remote login; assumes firewall is installed in container
firewall --service=ssh
# --- Time ---
timezone --utc <%= host_param('time-zone') || 'UTC' %>
<% if host_param('ntp-pools') -%>
<% host_param('ntp-pools').each do |ntppool| -%>
timesource --ntp-pool <%= ntppool %>
<% end -%>
<% elsif host_param('ntp-server') -%>
timesource --ntp-server <%= host_param('ntp-server') %>
<% end -%>
# --- Bootloader and Partitioning ---
# This assumes you are assigning a partition table in Foreman.
bootloader --location=mbr --append="<%= host_param('bootloader-append') || 'nofb quiet splash=quiet' %>" <%= grub_pass %>
<%= @host.diskLayout %>
# --- Finalize ---
text
skipx
reboot
# --- Post-Install Scripts ---
<%#
This section injects SSH keys for Foreman, registers the system,
and signals the build is done.
%>
%post
exec < /dev/tty3 > /dev/tty4
chvt 3
(
if [ ! -f /etc/resolv.conf ] || [ ! -s /etc/resolv.conf ]; then
cat > /etc/resolv.conf << 'RESOLV_EOF'
<% if @host.domain -%>
search <%= @host.domain.name %>
<% end -%>
<% if @host.subnet -%>
<% [@host.subnet.dns_primary, @host.subnet.dns_secondary].compact.each do |nameserver| -%>
nameserver <%= nameserver %>
<% end -%>
<% end -%>
RESOLV_EOF
fi
# A debug section in case of DNS issues
# echo "=== DNS Configuration ==="
# cat /etc/resolv.conf
# echo "=== Testing DNS Resolution ==="
# nslookup cdn.redhat.com || echo "WARNING: Cannot resolve cdn.redhat.com"
# echo "=========================="
<%= snippet 'redhat_register' -%>
<%= snippet('remote_execution_ssh_keys') %>
touch /tmp/foreman_built
chvt 1
) 2>&1 | tee /root/install.post.log
%end
<%#
The last post section tells Foreman the build is complete.
%>
%post --erroronfail --log=/root/install-callhome.post.log
if test -f /tmp/foreman_built; then
echo "calling home: build is done!"
<%= indent(2, skip1: true, skip_content: 'EOF') { snippet('built', :variables => { :endpoint => 'built', :method => 'POST', :body_file => '/root/install.post.log' }) } -%>
else
echo "calling home: build failed!"
<%= indent(2, skip1: true, skip_content: 'EOF') { snippet('built', :variables => { :endpoint => 'failed', :method => 'POST', :body_file => '/root/install.post.log' }) } -%>
fi
sync
%endThe new kickstart template above is a shortened version of the default Satellite kickstart template. Incompatible commands have been removed. The ostreecontainer command receives an argument called ostreecontainer that can be specified on the host in Satellite or through any higher-scope parameter source (like host group). Foreman remote execution keys and subscription-manager registration are included as well for convenience.
Use this template as a starting point, and customize it to suit the needs of your environment. To install this new provisioning template:
- Decide which Satellite operating system should become associated with the new provisioning template.
- The chosen operating system will serve as the base system that runs Anaconda. After the machine is provisioned, it reports the correct operating system that matches the container image back to Satellite.
- An operating system in Satellite can use one provisioning template of a certain type at a time. If you need to provision package mode and image mode machines of the same OS version, consider creating a new Satellite operating system just for image mode machines.
- Navigate to Hosts > Templates > Provisioning Templates and click Create Template.
- Paste the template into the editor and provide a name for the template, such as Image mode kickstart default.
- Navigate to the Association tab and select the Satellite operating systems that you want to use with the template during provisioning.
- Navigate to Hosts > Provisioning Setup > Operating Systems and select the target operating system.
- Navigate to Templates and select the new Image mode kickstart default template.
Now, when the operating system is selected during provisioning, Satellite renders Image mode kickstart default and serves it to provisioning hosts.
Secured registries
Using a container registry that requires authentication to provision an image mode machine is supported. Satellite servers without Unauthenticated Pull configured for its lifecycle environments do require authentication. Configure the pull secrets in the %pre section of the kickstart script:
%pre
mkdir -p /etc/ostree
cat > /etc/ostree/auth.json << 'EOF'
{
"auths": {
"registry.redhat.io": {
"auth": "<your secret here>"
}
}
}
EOF
%end
Kernel options
The url command is not compatible with ostreecontainer, so you must set inst.stage2 in the kernel options. To do so, populate the host's kickstart_kernel_custom_options parameter with a path to the kickstart repository, which can be found on the repository in Satellite. Edit the path as necessary if using a content view.
Parameter name: kickstart_kernel_custom_options
Parameter type: json
Parameter value (for example): ["inst.stage2=http://satellite.example.com/pulp/content/Demo/Development/RHEL_10/content/dist/rhel10/10.0/x86_64/baseos/kickstart/"]Consider setting this on a host group to avoid setting it for each host individually.
Advanced options for inst.stage2
There are a few more advanced options for setting the inst.stage2 repository where the medium_uri is calculated automatically:
- Query the repository path to avoid manually writing in the kickstart repository path:
Parameter name: kickstart_kernel_custom_options
Parameter type: json
Parameter value: ["inst.stage2=<%= medium_uri >"]- Alternatively, create a new
kickstart_kernel_optionsprovisioning template that includesinst.stage2automatically. Pair with a new PXE template (such as Kickstart default PXELinux) that uses the updated kernel options template. - Or set the
kickstart_liveimgparameter on the host totrue.
Network provisioning
If your environment has the following configured:
- Satellite configured with managed DHCP, TFTP, and DNS
- RHEL 9 or 10 AppStream and BaseOS kickstart repositories synced
- The ability to PXE provision normal RHEL hosts
- An image mode kickstart template configured as discussed above
You are now nearly set to provision image mode RHEL machines.
The image mode provisioning strategy discussed here relies heavily on the kickstart script. Otherwise, the provisioning process is nearly identical for traditional package mode RHEL.
First, consider the registry source for the host's container image. Satellite's container registry is a good choice for keeping network traffic within your infrastructure and for content lifecycle management. Satellite also has support for certificate authentication via containers-certs.d, which might be useful in future kickstart image mode provisioning strategies. Satellite is not required to be the registry, however. Any container registry can be used within the kickstart file. Keep in mind how Anaconda authenticates with the chosen container registry. If authentication credentials are needed, see the Secured registries section.
Once the registry source is chosen, it's time to build the host. Proceed with the regular inputs you'd use for package mode RHEL host provisioning, with these changes:
- The provisioning templates must resolve to the image mode provisioning ones created earlier. Be sure to choose the operating system associated with the image mode provisioning template.
- Create the necessary host parameters for provisioning following the examples:
ostreecontainer:- Type: string
sat.example.com/org/testing/bootc/rhel10-bootc:10.0
kickstart_kernel_custom_options:- Type: json
["inst.stage2=http://sat.example.com/pulp/content/Demo/Development/RHEL_10/content/dist/rhel10/10.0/x86_64/baseos/kickstart/"]
Create the host and enable the rendered kickstart and PXE templates in the Details tab for the new host. The kickstart template must include the ostreecontainer command, and the PXE template must include the kickstart repository in the kernel options as inst.stage2.
Monitor the provisioning process. Once it's complete, you have an image mode machine that's ready for use. To verify, after logging in, run bootc status. Verify that the booted image is set to the same path as the host's ostreecontainer parameter.
Image-based provisioning
This image-based provisioning tutorial for virtual machines uses the same Satellite environment as described in the network provisioning section.
There are multiple ways to create image mode disk images. To take advantage of Satellite's kickstart templates, these tutorial steps result in a reusable base image that can deploy any bootc container as an image mode machine.
To start, download a RHEL installation image for a version that supports image mode. For this tutorial, the image name is rhel-10.0-x86_64-dvd.iso.
Install mkksiso from the lorax RPM package available in RHEL's default AppStream repository. Then, as root, use mkksiso to append kickstart kernel options to the RHEL disk image:
$ mkksiso -c "inst.ks.sendmac inst.ks=http://katello.foreman-nuc1.example.com/unattended/provision" rhel-10.0-x86_64-dvd.iso rhel-10.0-satellite-ks-x86_64.iso
...
xorriso : UPDATE : Writing: 3956736s 95.7% fifo 100% buf 50% 882.9xD
ISO image produced: 4132704 sectors
Written to medium : 4132880 sectors at LBA 48
Writing to 'rhel-10.0-satellite-ks-x86_64.iso' completed successfully.
...
Once the new RHEL installation image is created, it needs to be added as an image to a compute resource. For example, if using the libvirt compute resource:
- Copy the disk image to the default libvirt volume directory,
/var/lib/libvirt/images/ - Navigate to Compute Resources > libvirt > Images and select Create Image
- Complete the image creation form
Now Satellite hosts can be created using the new image. As long as the Satellite host's MAC address matches the MAC address of its provisioning network interface, the kickstart template associated with the host's operating system is used by Anaconda at provisioning time.
If you don't require Anaconda automation for setting up your new image mode RHEL virtual machine, consider using bootc-image-builder directly from a bootc container image. The disk image can be used to create virtual machines in the same manner as above.
The value of deploying image mode systems with Satellite
Image mode enables a consistent and automatable approach for managing the operating system lifecycle. RHEL systems running in Image mode are updated by downloading all the updates, which are applied in a single reboot operation. If the updates cause unforeseen problems, they can be reversed without resorting to restoring from backups.
Red Hat Satellite provides ready-made tooling to facilitate the management lifecycle of image mode systems. As we've seen in this article, Satellite can save you time in provisioning and updating image mode systems.
The combination of image mode and Satellite removes many steps required to provision and manage large fleets of systems, providing you with speed and flexibility when managing the lifecycle of operating systems.