Lab: Prepare to Build and Deploy Bootc Container Images

Estimated reading time: 6 minutes.

Objective

Prepare for air-gapped building of bootc container images and disconnected deployment of edge devices.

Before you Begin

You need a development machine running Red Hat Enterprise Liunux (RHEL), to which you have unrestricted sudo rights, and access to RHEL package repositories. That machine must have plenty of disk space to store multiple container images and multiple virtual machine (VM) images.

These instructions were tested on RHEL 10.0 but should work with minimal or no changes on newer and older RHEL releases, since 9.6.

If you are using the course classroom, log in on the workstation VM as the user student with password student. If not, please adapt the instructions to your test environment.

Instructions

You will verify that you have access to mirrors of RHEL package repositories and bootc container images from RHEL. You will also configure your development machine with RHEL virtualization tools, based on libvirt, to perform system testing of your bootc container images.

As a bonus, you will verify that bootc container images have, by convention, a label key that differentiates them from application container images.

  1. Verify that your development machine has access to the RHEL package repositories from a DNF mirror.

    1. List the configured package repositories. They should match the standard RHEL package repositories.

      $ dnf repolist
      rhel-10.0-for-x86_64-appstream-rpms                                                                       Red Hat Enterprise Linux 10.0 AppStream (dvd)
      rhel-10.0-for-x86_64-baseos-rpms                                                                          Red Hat Enterprise Linux 10.0 BaseOS (dvd)
    2. Verify that your RHEL package repositories do NOT point to the Red Hat customer portal. Instead they should point to a machine inside your virtual labs environment.

      $ dnf repoinfo rhel-10.0-for-x86_64-baseos-rpms | grep baseurl
      Last metadata expiration check: 0:01:12 ago on Thu Aug  7 12:48:44 2025.
      Repo-baseurl       : http://content.example.com/rhel10.0/x86_64/dvd/BaseOS
    3. Verify that the bootc package is available, but do NOT install it.

      $ dnf info bootc
      Last metadata expiration check: 0:44:11 ago on Thu Aug  7 12:48:44 2025.
      Available Packages
      Name         : bootc
      Version      : 1.1.6
      Release      : 2.el10_0
      Architecture : x86_64
      Size         : 2.7 M
      Source       : bootc-1.1.6-2.el10_0.src.rpm
      Repository   : rhel-10.0-for-x86_64-appstream-rpms
      Summary      : Bootable container system
      URL          : https://github.com/containers/bootc
      License      : Apache-2.0 AND BSD-3-Clause AND MIT AND (Apache-2.0 OR BSL-1.0) AND (Apache-2.0 OR MIT) AND (Apache-2.0 WITH LLVM-exception OR Apache-2.0 OR MIT) AND (Unlicense OR MIT)
      Description  : Bootable container system
  2. Install the container tools on your development machine.

    You already have Podman installed, but during this course you will use additional convenience tools, such as Skopeo.

    $ sudo dnf install skopeo buildah
    ...
    Complete!
  3. Verify that your development machine has access to bootc base images from a private registry.

    1. The private registry requires authentication, even for images that would be public on the Red Hat registries.

      $ podman login -u student -p redhat registry.lab.example.com:5000
      Login Succeeded!
    2. List all images available on the private registry. The list should include some application container images and some bootc container images, for different releases of RHEL.

      $ podman search registry.lab.example.com:5000/
      NAME                                                                  DESCRIPTION
      registry.lab.example.com:5000/openshift4/microshift-bootc-rhel9
      registry.lab.example.com:5000/rhel10/bootc-image-builder
      registry.lab.example.com:5000/rhel10/rhel-bootc
      registry.lab.example.com:5000/rhel9-eus/rhel-9.6-bootc
      registry.lab.example.com:5000/rhel9-eus/rhel-9.6-bootc-image-builder
      registry.lab.example.com:5000/ubi10/ubi
      registry.lab.example.com:5000/ubi9/ubi
      The podman search command, and similar commands from other tools such as Docker, are not reliable to list container images in a production container registry nor to verify the availability of an image by its name and tag. Container registry servers do NOT have to return the results in any strict order. They can truncate the results, and do NOT have to return any indication that the results were truncated. The podman search command works here only because there is a small number of container images stored in the private registry.
    3. Inspect the RHEL 10 base bootc image to verify it is indeed a bootc container image. Look for the containers.bootc key.

      Instead of displaying all information about a container, which could spawn multiple pages of your terminal, use the --format option to list only the labels,

      $ skopeo inspect --format '{{ .Labels }}' docker://registry.lab.example.com:5000/rhel10/rhel-bootc
      map[architecture:x86_64 build-date:2025-07-31T04:03:30 com.redhat.component:rhel-bootc-component containers.bootc:1 description:RHEL bootc container distribution-scope:public io.buildah.version:1.40.1 io.k8s.description:RHEL bootc container name:rhel10/rhel-bootc org.opencontainers.image.source:https://gitlab.com/redhat/rhel/bifrost/rhel-bootc.git ostree.bootable:1 ostree.commit:8f3b22bd5d278d525440baa3ae7709fa89d575d7f6799f82913c805f2d7b8b1e ostree.final-diffid:sha256:12787d84fa137cd5649a9005efe98ec9d05ea46245fdc50aecb7dd007f2035b1 redhat.compose-id: redhat.id:rhel redhat.version-id:10.0 release:10.0 url:https://www.redhat.com vcs-ref:2ff3f1d1ffe1b320f7a54ef32c4fd19551736eba vcs-type:git vendor:Red Hat, Inc. version:10.0]
    4. You can output the information in JSON format and format it for legibility, which makes it easier to visually find a specific key.

      $ skopeo inspect --format '{{ json .Labels }}' docker://registry.lab.example.com:5000/rhel10/rhel-bootc | jq
      {
        "architecture": "x86_64",
        "build-date": "2025-07-31T04:03:30",
        "com.redhat.component": "rhel-bootc-component",
        "containers.bootc": "1",(1)
        "description": "RHEL bootc container",
        "distribution-scope": "public",
        "io.buildah.version": "1.40.1",
        "io.k8s.description": "RHEL bootc container",
        "name": "rhel10/rhel-bootc",
        "org.opencontainers.image.source": "https://gitlab.com/redhat/rhel/bifrost/rhel-bootc.git",
        "ostree.bootable": "1",
        "ostree.commit": "8f3b22bd5d278d525440baa3ae7709fa89d575d7f6799f82913c805f2d7b8b1e",
        "ostree.final-diffid": "sha256:12787d84fa137cd5649a9005efe98ec9d05ea46245fdc50aecb7dd007f2035b1",
        "redhat.compose-id": "",
        "redhat.id": "rhel",
        "redhat.version-id": "10.0",
        "release": "10.0",
        "url": "https://www.redhat.com",
        "vcs-ref": "2ff3f1d1ffe1b320f7a54ef32c4fd19551736eba",
        "vcs-type": "git",
        "vendor": "Red Hat, Inc.",
        "version": "10.0"
      }
      1 The label could take any value, but by convention it should be set to "1" or empty.
    5. Alternatively, you can check for the containers.bootc key directly, without using JSON or the jq command.

      $ skopeo inspect --format '{{ index .Labels "containers.bootc" }}' docker://registry.lab.example.com:5000/rhel10/rhel-bootc
      1
    6. Verify that an application container image, for example a UBI base image, does NOT have a containers.bootc label.

      $ skopeo inspect --format '{{ index .Labels "containers.bootc" }}' docker://registry.lab.example.com:5000/ubi10/ubi
      
      $
      Because the output of the last command is empty, you may want to retrieve and format all labels, just to be sure.
  4. Explore the contents of a bootc container image and an application container image and notice important packages that are present or not.

    1. Bootc container images include the bootable container system utility, that is, the bootc package and the command with the same name.

      $ podman run --rm --name bootc registry.lab.example.com:5000/rhel10/rhel-bootc bash -c "rpm -q bootc"
      ...
      bootc-1.1.6-2.el10_0.x86_64
      $ podman run --rm --name ubi registry.lab.example.com:5000/ubi10/ubi bash -c "rpm -q bootc"
      ..
      package bootc is not installed
      Be patient, bootc container images are considerably larger than regular application containers, so they take longer to download.
    2. Bootc container images include a Linux kernel.

      $ podman run --rm --name bootc registry.lab.example.com:5000/rhel10/rhel-bootc bash -c "rpm -q kernel"
      ...
      kernel-6.12.0-55.24.1.el10_0.x86_64
      $ podman run --rm --name ubi registry.lab.example.com:5000/ubi10/ubi bash -c "rpm -q kernel"
      ..
      package kernel is not installed
  5. Install the RHEL virtualization tools.

    1. Install the Libvirt tools and enable the Libvirt socket.

      $ sudo dnf install qemu-kvm libvirt virt-install virt-viewer
      ...
      Complete!
      $ sudo systemctl enable virtqemud.socket --now
      Created symlink /etc/systemd/system/multi-user.target.wants/virtqemud.socket → /usr/lib/systemd/system/virtqemud.socket.
    2. Check that your unprivileged user can connect to Libvirt’s session interface.

      $ virsh uri
      qemu:///session
      $ virsh nodeinfo
      CPU model:           x86_64
      ...

What’s next

The next chapter demonstrates how to craft a containerfile and use it to build a bootc container image.