Skip to content

Chapter 1 - Working with Golden Images

Build the demo base image for RHEL

The first steps we will build our base SOE (golden) image that we are going to use within the workshop. We will start with RHEL 9 and during the workshop update to RHEL 10.

We will name our SOE (Standard Operating Environment/Golden) image soe-rhel:9 and also tag it as our latest rhel base image as soe-rhel:latest.

  1. Use podman to build our soe base RHEL "golden image". Change to the directory where you have cloned this repo and use podman build to build the image from the Containerfile. The following command will work if you cloned it into your home directory.

    cd $HOME/redhat-image-mode-demo/use-cases/image-mode-way-of-working/soe-rhel9
    

    Review soe-rhel9/Containerfile
    FROM registry.redhat.io/rhel9/rhel-bootc:latest
    
    RUN dnf -y install mkpasswd
    RUN pass=$(mkpasswd --method=SHA-512 --rounds=4096 redhat) && useradd -m -G wheel bootc-user -p $pass
    
    ADD etc/ /etc
    

    podman build -t quay.io/$QUAY_USER/soe-rhel:latest -t quay.io/$QUAY_USER/soe-rhel:9.7 -f Containerfile
    
  2. If we want to test our image we can run it in a container. You can log in with user bootc-user and password redhat and run curl localhost to test if the httpd service is running and you can see the base image welcome page. You can stop and exit the container with sudo halt. We are going to run our container in the next step to check that the httpd service is running and that we can see our homepage before deploying it to a VM.

    podman run -it --rm --name soe-rhel9 -p 8080:80 quay.io/$QUAY_USER/soe-rhel:9
    
  3. Push the base rhel image to our registry.

    podman push quay.io/$QUAY_USER/soe-rhel:latest && podman push quay.io/$QUAY_USER/soe-rhel:9
    

Tip

We could base the initial image on an older release of RHEL, such as rhel:9.6, or a specific timestamp version of RHEL such as rhel:9.6-1747275992, or fix it at a certain release such as rhel:9.7, instead of pulling the latest release by specifying the release number in the Containerfile FROM statement.

Deploying the Homepage Virtual Machine

We need to create an image for our httpd service based on the RHEL 9 base image we created in the previous step. We will name our httpd service image httpd:rhel9 and also tag it as our latest rhel base image as httpd:latest.

  1. Use podman to build httpd service image. Change to the httpd-service folder.

    cd ../httpd-service
    

    Review httpd-service/Containerfile
    FROM quay.io/$QUAY_USER/soe-rhel:latest
    
    RUN dnf -y install httpd
    
    ADD etc/ /etc
    
    RUN <<EOF 
        set -euxo pipefail
        mv /var/www /usr/share/www
        sed -i 's-/var/www-/usr/share/www-' /etc/httpd/conf/httpd.conf
    EOF
    
    ADD html/ /usr/share/www/html
    
    RUN cp /etc/redhat-release /usr/share/www/html/redhat-release
    RUN cp /etc/os-release /usr/share/www/html/os-release
    RUN uname -sr > /usr/share/www/html/uname.txt
    
    RUN systemctl enable httpd 
    
    EXPOSE 80
    

  2. Change the $QUAY_USER in the Containerfile to your Quay userid or your registry.

  3. Use podman build to build the image from the Containerfile.

    podman build -t quay.io/$QUAY_USER/httpd:latest -t quay.io/$QUAY_USER/httpd:rhel9 -f Containerfile
    
  4. Push the httpd service image to our registry.

    podman push quay.io/$QUAY_USER/httpd:latest && podman push quay.io/$QUAY_USER/httpd:rhel9
    
  5. If we want to test our image we can run it in a container.

    podman run -it --rm --name httpd-rhel9 -p 8080:80 quay.io/$QUAY_USER/httpd:rhel9
    

  6. You can log in with user bootc-user and password redhat and run curl localhost to test if the httpd service is running and you can see the base image welcome page. You can test the homepage in a browser on the local machine by using the URL http://localhost:8080. You can stop and exit the container with sudo halt.

Now we are ready to create the virtual machine disk image that we are going to import into our new VM.

Since we need to run the Image Builder convert tool as superuser we need to pull the image from the registry using sudo to add it to sudo's image repository.

  1. Since we need to run podman as root to build the virtual machine qcow2 image file, we need to pull the image as root.

    Tip

    You may also get an error Error: unable to copy from source. You need to go to your repository, in our example, Quay, and make the repositories public.

    sudo podman pull quay.io/$QUAY_USER/httpd:latest
    
  2. We need to use podman to run the Image Mode virtual machine disk builder to pull the image from the registry and create the virtual machine disk file. You can edit the config.tomlfile to change it to add or replace the user, password, ssh key and more. Refer to Supported image customizations for a configuration file.

    Tip

    If you get an error Error: unable to copy from source you may have to do a sudo podman login registry.redhat.io -u $REDHAT_USER -p $REDHAT_PASSWORD.

    sudo podman run \
    --rm \
    -it \
    --privileged \
    --pull=newer \
    --security-opt label=type:unconfined_t \
    -v $(pwd)/config.toml:/config.toml:ro \
    -v $(pwd):/output \
    -v /var/lib/containers/storage:/var/lib/containers/storage registry.redhat.io/rhel9/bootc-image-builder:latest \
    --type qcow2 \
    quay.io/$QUAY_USER/httpd:latest
    
  3. We will copy the new disk image to the libvirt images pool.

    Tip

    You can move the disk image if you don't plan to use it for another VM using the mv command.

    sudo cp ./qcow2/disk.qcow2 /var/lib/libvirt/images/homepage.qcow2
    
  4. Create the VM from the copied virtual machine image qcow2 file. We will give it 4GB of RAM and set the boot option to UEFI.

    sudo virt-install \
    --connect qemu:///system \
    --name homepage \
    --import \
    --boot uefi \
    --memory 4096 \
    --graphics none \
    --osinfo rhel9-unknown \
    --noautoconsole \
    --noreboot \
    --disk /var/lib/libvirt/images/homepage.qcow2
    
  5. Start the VM.

    sudo virsh start homepage
    
  6. Login via ssh. You can use the following command that will get the IP address from virsh and log you in.

    VM_IP=$(sudo virsh -q domifaddr homepage | awk '{ print $4 }' | cut -d"/" -f1) && ssh bootc-user@$VM_IP
    
  7. You can run a curl localhost to check if the httpd service with our base image homepage is working. Exit the VM with exit, logout or Ctrl-d.

  8. Since we are going to refer to the quay.io registry, let us add $QUAY_USER to our .bashrc file.

    sed -i '/unset rc[^\n]*/,$!b;//{x;//p;g};//!H;$!d;x;iQUAY_USER="your quay.io username not the email address"' .bashrc
    
  9. and reload the .bashrc file to bring QUAY_USER into the variables.

    source .bashrc
    
  10. Finally for this section run the bootc status command to view the booted image registry source and the RHEL version.

    sudo bootc status
    
        Booted image: quay.io/$QUAY_USER/httpd:rhel9 \
        Digest: sha256:a48811e05........... \
        Version: 9.7 (2025-07-21 13:10:35.887718188 UTC)
    

Our virtual machine based on Image Mode is now running and we are ready to make updates to the web page.

Update the Homepage VM to our Image Mode web page

The next steps we will update the web page in our homepage VM from the basic RHEL webpage that we created to an more updated web page showing the advantages of using Image Mode.

On our image builder server we will build a new Image Mode for RHEL 9 homepage image that we will deploy to the VM.

  1. Change directory to the new web page Container file and the RHEL 9 Image Mode web page at homepage-rhel9. You can open the index.html file in the html directory to see the updates to the homepage.

    cd ../homepage-rhel9
    
  2. Build the new homepage images from the Containerfile.

    Review homepage-rhel9/Containerfile
    FROM quay.io/$QUAY_USER/soe-rhel:latest
    
    ADD html/ /usr/share/www/html
    
    ADD etc/ /etc
    
    RUN cp /etc/redhat-release /usr/share/www/html/redhat-release
    RUN cp /etc/os-release /usr/share/www/html/os-release
    RUN uname -sr > /usr/share/www/html/uname.txt
    
    EXPOSE 80
    

    Tip

    Remeber to change the $QUAY_USER in the Containerfile to your repository userid. Remeber to make the homepage repository on your Quay registry public.

    podman build -t quay.io/$QUAY_USER/homepage:rhel9 -t quay.io/$QUAY_USER/homepage:latest -f Containerfile
    
  3. Push the image to the registry using the homepage:rhel9 and homepage:latest tags.

    podman push quay.io/$QUAY_USER/homepage:latest && podman push quay.io/$QUAY_USER/homepage:rhel9
    
  4. Switch to the Homepage virtual machine and login to the homepage VM using ssh.

    VM_IP=$(sudo virsh -q domifaddr homepage | awk '{ print $4 }' | cut -d"/" -f1) && ssh bootc-user@$VM_IP
    
  5. We are now going to use the bootc switch command to switch the virtual machine to the homepage image in the registry.

    Tip

    If you didn't add the $QUAY_USER to the .bashrc file then run the following

    QUAY_USER="your quay.io username not the email address"
    
    sudo bootc switch quay.io/$QUAY_USER/homepage:latest
    
  6. Let us check the we have staged the new homepage image in the virtual machine.

    sudo bootc status
    
        Staged image: quay.io/$QUAY_USER/homepage:latest \
                Digest:  sha256:2be7b1...... \
            Version: 9.7 (2025-07-21 15:43:03.624175287 UTC) \
            \
        ● Booted image: quay.io/$QUAY_USER/soe-rhel:9.7 \
                Digest: sha256:a48811...... \
            Version: 9.7 (2025-07-21 13:10:35.887718188 UTC)
    
  7. and we check that we have the old RHEL 9 homepage without our new Image Mode content.

    curl localhost
    
  8. We need to reboot the virtual machine to activate the new layers and have our new home page.

    sudo reboot
    
  9. Login to the virtual machine to verify that we have a new updated Image Mode homepage.

    VM_IP=$(sudo virsh -q domifaddr homepage | awk '{ print $4 }' | cut -d"/" -f1) && ssh bootc-user@$VM_IP
    curl localhost
    
  10. Something went wrong! Our httpd service has failed during the update! Let us check the service.

    sudo systemctl status httpd
    
  11. There is no httpd service. We will rollback in the next section and fix the problem.

Rollback and fix our homepage

In the previous section the httpd service wasn't in the image. This is due to a mistake we made in the Containerfile. First we will rollback so that we have the old homepage up and running and then we will fix the problem.

On our image builder server we will build a new Image Mode for RHEL 9 homepage image that we will deploy to the VM.

  1. If you aren't in the homepage-rhel9 directory then change directory to the new web page Container file and the updated web page at homepage-rhel9. You can open the index.html file in the html directory to see the updates to the homepage.

    cd ../homepage-rhel9
    
  2. We need to fix the Containerfile to pull the correct image from the registry. Use an editor to change the following line to

    Tip

    Remeber to change the $QUAY_USER in the Containerfile to your repository userid.

    FROM quay.io/$QUAY_USER/soe-rhel:latest
    

    change to

    FROM quay.io/$QUAY_USER/httpd:latest
    
  3. Build the new homepage images from the Containerfile and tag to a new version homepage:rhel9-fix.

    podman build -t quay.io/$QUAY_USER/homepage:rhel9-fix -t quay.io/$QUAY_USER/homepage:latest -f Containerfile
    
  4. Push the image to the registry using the homepage:rhel9-fix and homepage:latest tags.

    podman push quay.io/$QUAY_USER/homepage:latest && podman push quay.io/$QUAY_USER/homepage:rhel9-fix
    
  5. Switch to the Homepage virtual machine and login to the homepage VM using ssh.

    VM_IP=$(sudo virsh -q domifaddr homepage | awk '{ print $4 }' | cut -d"/" -f1) && ssh bootc-user@$VM_IP
    
  6. We are going to use the bootc switch command to switch the virtual machine to the homepage image in the registry.

    Tip

    If you didn't add the $QUAY_USER to the .bashrc file then run the following

    QUAY_USER="your quay.io username not the email address"
    
    sudo bootc switch quay.io/$QUAY_USER/homepage:latest
    
  7. Let us check the we have staged the new homepage image in the virtual machine.

    sudo bootc status
    
        Staged image: quay.io/$QUAY_USER/homepage:latest \
                Digest:  sha256:2be7b1...... \
            Version: 9.7 (2025-07-21 15:43:03.624175287 UTC) \
            \
        ● Booted image: quay.io/$QUAY_USER/soe-rhel:9.7 \
                Digest: sha256:a48811...... \
            Version: 9.7 (2025-07-21 13:10:35.887718188 UTC)
    
  8. and we check that we have the old RHEL 9 homepage without our new Image Mode content.

    curl localhost
    
  9. We need to reboot the virtual machine to activate the new layers and have our new home page.

    sudo reboot
    
  10. Login to the virtual machine to verify that we have a new updated Image Mode homepage.

    VM_IP=$(sudo virsh -q domifaddr homepage | awk '{ print $4 }' | cut -d"/" -f1) && ssh bootc-user@$VM_IP
    
    curl localhost
    

Build the database virtual machine

We will then deploy a new virtual machine named database as this will be our new demo database server. We will build the two images in one linked command and push it as the version 1 and latest images to our registry.

We are following a less complex deployment for the database server than the deployment we did for the homepage. We are going to deploy the mariadb service using a bash script to automate the deployment.

In the mariadb_service directory update the QUAY_USER variable in the mariadb-deploy-rhel9.sh file and the Containerfile with your quay user id.

Review mariadb-service/mariadb-deploy-rhel9.sh
#! /bin/bash
# This script deploys a MariaDB database using Podman.

QUAY_USER="your quay username"

podman build -t quay.io/$QUAY_USER/database:latest -t quay.io/$QUAY_USER/database:rhel9.6 -f Containerfile
podman push quay.io/$QUAY_USER/database:latest && podman push quay.io/$QUAY_USER/database:rhel9.6

sudo podman pull quay.io/$QUAY_USER/database:latest
sudo podman run \
--rm \
-it \
--privileged \
--pull=newer \
--security-opt label=type:unconfined_t \
-v $(pwd)/config.toml:/config.toml:ro \
-v $(pwd):/output \
-v /var/lib/containers/storage:/var/lib/containers/storage registry.redhat.io/rhel9/bootc-image-builder:latest \
--type qcow2 \
--tls-verify=false \
quay.io/$QUAY_USER/database:latest

sudo mv qcow2/disk.qcow2 /var/lib/libvirt/images/database.qcow2

sudo virt-install \
  --connect qemu:///system \
  --name database \
  --import \
  --boot uefi \
  --memory 4096 \
  --graphics none \
  --osinfo rhel9-unknown \
  --noautoconsole \
  --noreboot \
  --disk /var/lib/libvirt/images/database.qcow2

sudo virsh start database

and the Containerfile

Review mariadb-service/Containerfile
FROM quay.io/$QUAY_USER/soe-rhel:latest

ADD etc/ /etc

RUN dnf -y install mariadb mariadb-server vim && dnf clean all && rm -rf /var/cache /var/log/dnf && systemctl enable mariadb

COPY ./files/00-mariadb-tmpfile.conf /usr/lib/tmpfiles.d/

EXPOSE 3306
  1. Change to the mariadb-service directory.

    cd ../mariadb-service
    
  2. Ensure that the mariadb-deploy.sh file is executable.

    chmod +x mariadb-deploy.sh
    
  3. Edit the mariadb-deploy.sh file and change the entry for the QUAY_USER to your quay.io user name.

  4. Run the bash script mariadb-deploy.sh to create the database images and the database VM.

    ./mariadb_deploy.sh
    

This will build and push the mariadb service image and deploy the VM from the image.