bootc / Image-Mode RHEL

Deliver the operating system as an immutable OCI container image with atomic updates and automatic rollbacks.

What is bootc?

bootc is a tool for managing bootable container images. It enables image-mode RHEL, where the entire operating system — kernel, packages, configuration — is delivered as a standard OCI container image. Instead of managing individual RPM packages on each machine, you build a container image with your desired OS state and deploy it.

Key insight: With bootc, your VM's operating system is managed the same way you manage container applications — build an image, push it to a registry, and roll it out. This brings container-native workflows to traditional VM-based workloads.

bootc vs. Traditional Package Management

Aspect Traditional (dnf/yum) bootc (Image-Mode)
Update unit Individual RPM packages Entire OS image (atomic)
Rollback Manual, unreliable Automatic, guaranteed (previous image retained)
Drift Possible (manual changes accumulate) Eliminated (OS state defined by image)
Build process Kickstart / Ansible / manual Containerfile (standard container build)
Registry RPM repos (dnf/yum) OCI container registry (Quay, GHCR, etc.)
Testing Test on live system Test image in CI before deploying
Reproducibility Depends on repo state at install time Fully reproducible (pinned image digest)

How bootc Updates Work in This Golden Path

When you select bootc Image as the boot source, the template configures automatic OS updates inside the VM guest:

  1. Systemd Timer — A bootc-update.timer unit is injected via cloud-init and runs daily (OnCalendar=daily, Persistent=true).
  2. Pull & Stage — The timer triggers bootc update --apply, which pulls the latest version of the bootc image from the registry and stages it for the next boot.
  3. Reboot & Activate — On the next reboot (manual or scheduled), the new OS image is activated. The previous image is retained as a rollback target.
  4. Automatic Rollback — If the new image fails to boot successfully, bootc automatically rolls back to the previous known-good image.

Building Custom bootc Images

You build bootc images using standard container tooling (Podman, Buildah, Docker). Start from a base bootc image and layer your customizations:

Basic Containerfile

FROM quay.io/centos-bootc/centos-bootc:stream9

# Install packages
RUN dnf install -y \
    httpd \
    vim-enhanced \
    git \
    && systemctl enable httpd \
    && dnf clean all

# Add custom configuration
COPY my-httpd.conf /etc/httpd/conf.d/custom.conf

# Add application content
COPY html/ /var/www/html/

Build and Push

# Build the image
podman build -t quay.io/myorg/my-rhel-bootc:v1.0 .

# Push to registry
podman push quay.io/myorg/my-rhel-bootc:v1.0

Multi-Stage Build with Testing

FROM quay.io/centos-bootc/centos-bootc:stream9 AS base

RUN dnf install -y httpd php php-mysqlnd && \
    systemctl enable httpd && \
    dnf clean all

COPY app/ /var/www/html/
COPY httpd-8080.conf /etc/httpd/conf.d/listen-8080.conf

# Verify the image builds correctly
RUN httpd -t

GitOps-Driven OS Lifecycle

The golden path integrates bootc with ArgoCD for a complete GitOps-driven OS lifecycle:

  ┌─────────────────┐     ┌──────────────┐     ┌───────────────┐
  │  Build bootc     │     │  Push image   │     │  Update YAML  │
  │  image in CI     │────►│  to Quay.io   │────►│  in Git repo  │
  │  (Containerfile) │     │              │     │  (image ref)  │
  └─────────────────┘     └──────────────┘     └──────┬────────┘
                                                       │
                                                       ▼
                                               ┌───────────────┐
                                               │  ArgoCD syncs  │
                                               │  DataVolume    │
                                               │  (new image)   │
                                               └──────┬────────┘
                                                       │
                                                       ▼
                                               ┌───────────────┐
                                               │  VM boots with │
                                               │  new OS image  │
                                               └───────────────┘

Updating the Image via Git

To update the OS image for a running VM:

  1. Build and push the new bootc image with a new tag
  2. Edit manifests/virtualmachine.yaml in the Gitea repository
  3. Update the bootcImageUrl to the new image tag
  4. Commit and push to main
  5. ArgoCD detects the change and reconciles the DataVolume
# In manifests/virtualmachine.yaml, update the source:
source:
  registry:
    url: "docker://quay.io/myorg/my-rhel-bootc:v1.1"  # Updated tag
    pullMethod: node

In-Guest bootc Commands

Once connected to the VM via SSH, you can manage bootc directly:

# Check current boot status
bootc status

# Manually check for updates
bootc update --check

# Apply an update immediately
bootc update --apply

# Switch to a different image entirely
bootc switch quay.io/myorg/my-rhel-bootc:v2.0

# Rollback to the previous image
bootc rollback

Base Images

Image Description Use Case
quay.io/centos-bootc/centos-bootc:stream9 CentOS Stream 9 bootc base image Development, testing, community use
registry.redhat.io/rhel9/rhel-bootc:latest RHEL 9 bootc base image (subscription required) Production workloads with Red Hat support