Chapter 4. Creating bootc compatible base disk images with bootc-image-builder The bootc-image-builder , available as a Technology Preview, is a containerized tool to create disk images from bootc images. You can use the images that you build to deploy disk images in different environments, such as the edge, server, and clouds. 4.1. Introducing image mode for RHEL for bootc-image-builder With the bootc-image-builder tool, you can convert bootc images into disk images for a variety of different platforms and formats. Converting bootc images into disk images is equivalent to installing a bootc. After you deploy these disk images to the target environment, you can update them directly from the container registry. Note The bootc-image-builder can only pull and use images from public container repositories. Building base disk images which come from private registries by using bootc-image-builder is not supported in this release. If your container image is stored in a private repository, bootc-image-builder cannot pull the image because it is not able to authenticate to the registry. If you need to use an image from a private repository, you must authenticate to the registry first and then pull the container image before you use it with bootc-image-builder . After pulling the image, you can run the bootc-image-builder command using the --local option. The bootc-image-builder tool supports generating the following image types: Disk image formats, such as ISO, suitable for disconnected installations. Virtual disk images formats, such as: QEMU copy-on-write (QCOW2) Amazon Machine Image (AMI)/ - Raw Virtual Machine Image (VMI) Deploying from a container image is beneficial when you run VMs or servers because you can achieve the same installation result. That consistency extends across multiple different image types and platforms when you build them from the same container image. Consequently, you can minimize the effort in maintaining operating system images across platforms. You can also update systems that you deploy from these disk images by using the bootc tool, instead of re-creating and uploading new disk images with bootc-image-builder . Note Generic base container images do not include any default passwords or SSH keys. Also, the disk images that you create by using the bootc-image-builder tool do not contain the tools that are available in common disk images, such as cloud-init . These disk images are transformed container images only. Although you can deploy a rhel-9-bootc image directly, you can also create your own customized images that are derived from this bootc image. The bootc-image-builder tool takes the rhel-9-bootc OCI container image as an input. Additional resources Red Hat products that use cloud-init 4.2. Installing bootc-image-builder The bootc-image-builder is intended to be used as a container and it is not available as an RPM package in RHEL. To access it, follow the procedure. Prerequisites The container-tools meta-package is installed. The meta-package contains all container tools, such as Podman, Buildah, and Skopeo. You are authenticated to registry.redhat.io . For details, see Red Hat Container Registry Authentication . Procedure Login to authenticate to registry.redhat.io : Install the bootc-image-builder tool: Verification List all images pulled to your local system: Additional resources Red Hat Container Registry Authentication Pulling images from registries 4.3. Creating QCOW2 images by using bootc-image-builder Build a RHEL bootc image into a QEMU Disk Images (QCOW2) image for the architecture that you are running the commands on. The RHEL base image does not include a default user. Optionally, you can inject a user configuration with the --config option to run the bootc-image-builder container. Alternatively, you can configure the base image with cloud-init to inject users and SSH keys on first boot. See Users and groups configuration - Injecting users and SSH keys by using cloud-init . Prerequisites You have Podman installed on your host machine. You have virt-install installed on your host machine. You have root access to run the bootc-image-builder tool, and run the containers in --privileged mode, to build the images. Procedure Optional: Create a config.toml to configure user access, for example: Run bootc-image-builder . Optionally, if you want to use user access configuration, pass the config.toml as an argument. Note If you do not have the container storage mount and --local image options, your image must be public. The following is an example of creating a public QCOW2 image: The following is an example of creating a private QCOW2 image: You can find the .qcow2 image in the output folder. steps You can deploy your image. See Deploying a container image using KVM with a QCOW2 disk image . You can make updates to the image and push the changes to a registry. See Managing RHEL bootc images . 4.4. Creating VMDK images by using bootc-image-builder Create a Virtual Machine Disk (VMDK) from a bootc image and use it within VMware's virtualization platforms, such as vSphere, or use the Virtual Machine Disk (VMDK) in VirtualBox. Prerequisites You have Podman installed on your host machine. You have authenticated to the Red Hat Registry by using the podman login registry.redhat.io . You have pulled the rhel9/bootc-image-builder container image. Procedure Create a Containerfile with the following content: Build the bootc image: Create a VMDK file from the previously created bootc image: Note If you do not have the container storage mount and --local image options, your image must be public. The following is an example of creating a public VMDK image: The following is an example of creating a private VMDK image: The --local option uses the local container storage to source the originating image to produce the VMDK instead of a remote repository. A VMDK disk file for the bootc image is stored in the output/vmdk directory. steps You can make updates to the image and push the changes to a registry. See Managing RHEL bootc images . 4.5. Creating GCE images by using bootc-image-builder Build a RHEL bootc image into a gce image for the architecture that you are running the commands on. The RHEL base image does not include a default user. Optionally, you can inject a user configuration with the --config option to run the bootc-image-builder container. Alternatively, you can configure the base image with cloud-init to inject users and SSH keys on first boot. See Users and groups configuration - Injecting users and SSH keys by using cloud-init . Prerequisites You have Podman installed on your host machine. You have root access to run the bootc-image-builder tool, and run the containers in --privileged mode, to build the images. Procedure Optional: Create a config.toml to configure user access, for example: Run bootc-image-builder . Optionally, if you want to use user access configuration, pass the config.toml as an argument. Note If you do not have the container storage mount and --local image options, your image must be public. The following is an example of creating a gce image: The following is an example of creating a private gce image: You can find the gce image in the output folder. steps You can deploy your image. See Deploying a container image using KVM with a QCOW2 disk image . You can make updates to the image and push the changes to a registry. See Managing RHEL bootc images . 4.6. Creating AMI images by using bootc-image-builder and uploading it to AWS Create an Amazon Machine Image (AMI) from a bootc image and use it to launch an Amazon Web Service EC2 (Amazon Elastic Compute Cloud) instance. Prerequisites You have Podman installed on your host machine. You have an existing AWS S3 bucket within your AWS account. You have root access to run the bootc-image-builder tool, and run the containers in --privileged mode, to build the images. You have the vmimport service role configured on your account to import an AMI into your AWS account. Procedure Create a disk image from the bootc image. Configure the user details in the Containerfile. Make sure that you assign it with sudo access. Build a customized operating system image with the configured user from the Containerfile. It creates a default user with passwordless sudo access. Optional: Configure the machine image with cloud-init . See Users and groups configuration - Injecting users and SSH keys by using cloud-init . The following is an example: Note You can also use cloud-init to add users and additional configuration by using instance metadata. Build the bootc image. For example, to deploy the image to an x86_64 AWS machine, use the following commands: Use the bootc-image-builder tool to create an AMI from the bootc container image. Note If you do not have the container storage mount and --local image options, your image must be public. The following is an example of creating a public AMI image: The following is an example of creating a private AMI image: You can also inject all your AWS configuration parameters by using --env AWS_* . Important The following flags must be specified all together. If you do not specify any flag, the AMI is exported to your output directory. --aws-ami-name - The name of the AMI image in AWS --aws-bucket - The target S3 bucket name for intermediate storage when you are creating the AMI --aws-region - The target region for AWS uploads The bootc-image-builder tool builds an AMI image and uploads it to your AWS s3 bucket by using your AWS credentials to push and register an AMI image after building it. steps You can deploy your image. See Deploying a container image to AWS with an AMI disk image . You can make updates to the image and push the changes to a registry. See Managing RHEL bootc images . Additional resources AWS CLI documentation 4.7. Creating raw disk images by using bootc-image-builder You can convert a bootc image to a Raw image with an MBR or GPT partition table by using bootc-image-builder . The RHEL base image does not include a default user, so optionally, you can inject a user configuration with the --config option to run the bootc-image-builder container. Alternatively, you can configure the base image with cloud-init to inject users and SSH keys on first boot. See Users and groups configuration - Injecting users and SSH keys by using cloud-init . Prerequisites You have Podman installed on your host machine. You have root access to run the bootc-image-builder tool, and run the containers in --privileged mode, to build the images. You have pulled your target container image in the container storage. Procedure Optional: Create a config.toml to configure user access, for example: Run bootc-image-builder . If you want to use user access configuration, pass the config.toml as an argument: Note If you do not have the container storage mount and --local image options, your image must be public. The following is an example of creating a public RAW image: The following is an example of creating a private RAW image: You can find the .raw image in the output folder. steps You can deploy your image. See Deploying a container image by using KVM with a QCOW2 disk image . You can make updates to the image and push the changes to a registry. See Managing RHEL bootc images . 4.8. Creating ISO images by using bootc-image-builder You can use bootc-image-builder to create an ISO from which you can perform an offline deployment of a bootable container. Prerequisites You have Podman installed on your host machine. You have root access to run the bootc-image-builder tool, and run the containers in --privileged mode, to build the images. Procedure Optional: Create a config.toml to configure user access, for example: Run bootc-image-builder . If you do not want to add any configuration, omit the -v USD(pwd)/config.toml:/config.toml argument. Note If you do not have the container storage mount and --local image options, your image must be public. The following is an example of creating a public ISO image: The following is an example of creating a private ISO image: You can find the .iso image in the output folder. steps You can use the ISO image on unattended installation methods, such as USB sticks or Install-on-boot. The installable boot ISO contains a configured Kickstart file. See Deploying a container image by using Anaconda and Kickstart . Warning Booting the ISO on a machine with an existing operating system or data can be destructive, because the Kickstart is configured to automatically reformat the first disk on the system. You can make updates to the image and push the changes to a registry. See Managing RHEL bootable images . 4.9. Using bootc-image-builder to build ISO images with a Kickstart file You can use a Kickstart file to configure various parts of the installation process, such as setting up users, customizing partitioning, and adding an SSH key. You can include the Kickstart file in an ISO build to configure any part of the installation process, except the deployment of the base image. For ISOs with bootc container base images, you can use a Kickstart file to configure anything except the ostreecontainer command. For example, you can use a Kickstart to perform either a partial installation, a full installation, or even omit the user creation. Use bootc-image-builder to build an ISO image that contains the custom Kickstart to configure your installation process. Prerequisites You have Podman installed on your host machine. You have root access to run the bootc-image-builder tool, and run the containers in --privileged mode, to build the images. Procedure Create your Kickstart file. The following Kickstart file is an example of a fully unattended Kickstart file configuration that contains user creation, and partition instructions. Save the Kickstart configuration in the toml format to inject the Kickstart content. For example, config.toml . Run bootc-image-builder , and include the Kickstart file configuration that you want to add to the ISO build. The bootc-image-builder automatically adds the ostreecontainer command that installs the container image. Note If you do not have the container storage mount and --local image options, your image must be public. The following is an example of creating a public ISO image: The following is an example of creating a private ISO image: You can find the .iso image in the output folder. steps You can use the ISO image on unattended installation methods, such as USB sticks or Install-on-boot. The installable boot ISO contains a configured Kickstart file. See Deploying a container image by using Anaconda and Kickstart . Warning Booting the ISO on a machine with an existing operating system or data can be destructive, because the Kickstart is configured to automatically reformat the first disk on the system. You can make updates to the image and push the changes to a registry. See Managing RHEL bootable images . 4.10. Verification and troubleshooting If you have any issues configuring the requirements for your AWS image, see the following documentation AWS IAM account manager Using high-level (s3) commands with the AWS CLI . S3 buckets . Regions and Zones . Launching a customized RHEL image on AWS . For more details on users, groups, SSH keys, and secrets, see Managing users, groups, SSH keys, and secrets in image mode for RHEL

Commands:
sudo podman login registry.redhat.io
sudo podman pull registry.redhat.io/rhel9/bootc-image-builder
sudo podman images REPOSITORY TAG IMAGE ID CREATED SIZE registry.redhat.io/rhel9/bootc-image-builder latest b361f3e845ea 24 hours ago 676 MB
[[customizations.user]] name = "user" password = "pass" key = "ssh-rsa AAA ... user@email.com" groups = ["wheel"]
sudo podman run --rm -it --privileged --pull=newer --security-opt label=type:unconfined_t -v ./config.toml:/config.toml -v ./output:/output registry.redhat.io/rhel9/bootc-image-builder:latest --type qcow2 --config /config.toml quay.io/ <namespace> / <image> : <tag>
sudo podman run --rm -it --privileged --pull=newer --security-opt label=type:unconfined_t -v USD(pwd)/config.toml:/config.toml:ro -v USD(pwd)/output:/output -v /var/lib/containers/storage:/var/lib/containers/storage registry.redhat.io/rhel9/bootc-image-builder:latest --local --type qcow2 quay.io/ <namespace> / <image> : <tag>
FROM registry.redhat.io/rhel9/rhel-bootc:9.4 RUN dnf -y install cloud-init open-vm-tools && ln -s ../cloud-init.target /usr/lib/systemd/system/default.target.wants && rm -rf /var/{cache,log} /var/lib/{dnf,rhsm} && systemctl enable vmtoolsd.service
podman build . -t localhost/rhel-bootc-vmdk
podman run --rm -it --privileged -v /var/lib/containers/storage:/var/lib/containers/storage -v ./output:/output --security-opt label=type:unconfined_t --pull newer registry.redhat.io/rhel9/bootc-image-builder:9.4 --local --type vmdk quay.io/ <namespace> / <image> : <tag>
podman run --rm -it --privileged --pull=newer --security-opt label=type:unconfined_t -v USD(pwd)/config.toml:/config.toml:ro -v USD(pwd)/output:/output -v /var/lib/containers/storage:/var/lib/containers/storage registry.redhat.io/rhel9/bootc-image-builder:latest --local --type vmdk quay.io/ <namespace> / <image> : <tag>
[[customizations.user]] name = "user" password = "pass" key = "ssh-rsa AAA ... user@email.com" groups = ["wheel"]
sudo podman run --rm -it --privileged --pull=newer --security-opt label=type:unconfined_t -v ./config.toml:/config.toml -v ./output:/output registry.redhat.io/rhel9/bootc-image-builder:latest --type gce --config /config.toml quay.io/ <namespace> / <image> : <tag>
sudo podman run --rm -it --privileged --pull=newer --security-opt label=type:unconfined_t -v USD(pwd)/config.toml:/config.toml:ro -v USD(pwd)/output:/output -v /var/lib/containers/storage:/var/lib/containers/storage registry.redhat.io/rhel9/bootc-image-builder:latest --local --type gce quay.io/ <namespace> / <image> : <tag>
FROM registry.redhat.io/rhel9/rhel-bootc:9.4 RUN dnf -y install cloud-init && ln -s ../cloud-init.target /usr/lib/systemd/system/default.target.wants && rm -rf /var/{cache,log} /var/lib/{dnf,rhsm}
podman build -t quay.io/ <namespace> / <image> : <tag> . podman push quay.io/ <namespace> / <image> : <tag> .
sudo podman run --rm -it --privileged --pull=newer -v USDHOME/.aws:/root/.aws:ro --env AWS_PROFILE=default registry.redhat.io/rhel9/bootc-image-builder:latest --type ami --aws-ami-name rhel-bootc-x86 --aws-bucket rhel-bootc-bucket --aws-region us-east-1 quay.io/ <namespace> / <image> : <tag>
sudo podman run --rm -it --privileged --pull=newer -v USDHOME/.aws:/root/.aws:ro --env AWS_PROFILE=default registry.redhat.io/rhel9/bootc-image-builder:latest --type ami --aws-ami-name rhel-bootc-x86 --aws-bucket rhel-bootc-bucket --local quay.io/ <namespace> / <image> : <tag>
[[customizations.user]] name = "user" password = "pass" key = "ssh-rsa AAA ... user@email.com" groups = ["wheel"]
sudo podman run --rm -it --privileged --pull=newer --security-opt label=type:unconfined_t -v /var/lib/containers/storage:/var/lib/containers/storage -v ./config.toml:/config.toml -v ./output:/output registry.redhat.io/rhel9/bootc-image-builder:latest --local --type raw --config /config.toml quay.io/ <namespace> / <image> : <tag>
sudo podman run --rm -it --privileged --pull=newer --security-opt label=type:unconfined_t -v USD(pwd)/config.toml:/config.toml:ro -v USD(pwd)/output:/output -v /var/lib/containers/storage:/var/lib/containers/storage registry.redhat.io/rhel9/bootc-image-builder:latest --local --type raw quay.io/ <namespace> / <image> : <tag>
[[customizations.user]] name = "user" password = "pass" key = "ssh-rsa AAA ... user@email.com" groups = ["wheel"]
sudo podman run --rm -it --privileged --pull=newer --security-opt label=type:unconfined_t -v /var/lib/containers/storage:/var/lib/containers/storage -v USD(pwd)/config.toml:/config.toml -v USD(pwd)/output:/output registry.redhat.io/rhel9/bootc-image-builder:latest --type iso --config /config.toml quay.io/ <namespace> / <image> : <tag>
sudo podman run --rm -it --privileged --pull=newer --security-opt label=type:unconfined_t -v USD(pwd)/config.toml:/config.toml:ro -v USD(pwd)/output:/output -v /var/lib/containers/storage:/var/lib/containers/storage registry.redhat.io/rhel9/bootc-image-builder:latest --local --type iso quay.io/ <namespace> / <image> : <tag>
[customizations.installer.kickstart] contents = """ lang en_GB.UTF-8 keyboard uk timezone CET user --name <user> --password <password> --plaintext --groups <groups> sshkey --username <user> ssh- <type> <public key> rootpw --lock zerombr clearpart --all --initlabel autopart --type=plain reboot --eject """
sudo podman run --rm -it --privileged --pull=newer --security-opt label=type:unconfined_t -v /var/lib/containers/storage:/var/lib/containers/storage -v USD(pwd)/config.toml:/config.toml -v USD(pwd)/output:/output registry.redhat.io/rhel9/bootc-image-builder:latest --type iso --config /config.toml quay.io/ <namespace> / <image> : <tag>
sudo podman run --rm -it --privileged --pull=newer --security-opt label=type:unconfined_t -v USD(pwd)/config.toml:/config.toml:ro -v USD(pwd)/output:/output -v /var/lib/containers/storage:/var/lib/containers/storage registry.redhat.io/rhel9/bootc-image-builder:latest --local --type iso quay.io/ <namespace> / <image> : <tag>