Chapter 2. Building and testing RHEL bootc images The following procedures use Podman to build and test your container image. You can also use other tools, for example, OpenShift Container Platform. For more examples of configuring RHEL systems by using containers, see the rhel-bootc-examples repository. Figure 2.1. Building an image by using instructions from a Containerfile, testing the container, pushing an image to a registry, and sharing it with others A general Containerfile structure is the following: The available commands that are usable inside a Containerfile and a Dockerfile are equivalent. However, the following commands in a Containerfile are ignored when the rhel-9-bootc image is installed to a system: ENTRYPOINT and CMD (OCI: Entrypoint/Cmd ): you can set CMD /sbin/init instead. ENV (OCI: Env ): change the systemd configuration to configure the global system environment. EXPOSE (OCI: exposedPorts ): it is independent of how the system firewall and network function at runtime. USER (OCI: User ): configure individual services inside the RHEL bootc to run as unprivileged users instead. The rhel-9-bootc container image reuses the OCI image format. The rhel-9-bootc container image ignores the container config section ( Config ) when it is installed to a system. The rhel-9-bootc container image does not ignore the container config section ( Config ) when you run this image by using container runtimes such as podman or docker . Note Building custom rhel-bootc base images is not supported in this release. 2.1. Building a container image Use the podman build command to build an image using instructions from a Containerfile . Prerequisites The container-tools meta-package is installed. Procedure Create a Containerfile : This Containerfile example adds the cloud-init tool, so it automatically fetches SSH keys and can run scripts from the infrastructure and also gather configuration and secrets from the instance metadata. For example, you can use this container image for pre-generated AWS or KVM guest systems. Build the <image> image by using Containerfile in the current directory: Verification List all images: Additional resources Working with container registries Building an image from a Containerfile with Buildah 2.2. Building derived bootable images by using multi-stage builds The deployment image should include only the application and its required runtime, without adding any build tools or unnecessary libraries. To achieve this, use a two-stage Containerfile : one stage for building the artifacts and another for hosting the application. With multi-stage builds, you use multiple FROM instructions in your Containerfile . Each FROM instruction can use a different base, and each of them begins a new stage of the build. You can selectively copy artifacts from one stage to another, and exclude everything you do not need in the final image. Multi-stage builds offer several advantages: Smaller image size By separating the build environment from the runtime environment, only the necessary files and dependencies are included in the final image, significantly reducing its size. Improved security Since build tools and unnecessary libraries are excluded from the final image, the attack surface is reduced, leading to a more secure container. Optimized performance A smaller image size means faster download, deployment, and startup times, improving the overall efficiency of the containerized application. Simplified maintenance With the build and runtime environments separated, the final image is cleaner and easier to maintain, containing only what is needed to run the application. Cleaner builds Multi-stage builds help avoid clutter from intermediate files, which could accumulate during the build process, ensuring that only essential artifacts make it into the final image. Resource efficiency The ability to build in one stage and discard unnecessary parts minimizes the use of storage and bandwidth during deployment. Better Layer Caching With clearly defined stages, Podman can efficiently cache the results of stages, by accelerating up future builds. The following Containerfile consists of two stages. The first stage is typically named builder and it compiles a golang binary. The second stage copies the binary from the first stage. The default working directory for the go-toolset builder is opt/ap-root/src . As a result, the final container image includes the helloworld binary but no data from the stage. You can also use multi-stage builds to perform the following scenarios: Stopping at a specific build stage When you build your image, you can stop at a specified build stage. For example: For example, you can use this approach to debugging a specific build stage. Using an external image as a stage You can use the COPY --from instruction to copy from a separate image either using the local image name, a tag available locally or on a container registry, or a tag ID. For example: Using a stage as a new stage You can continue where a stage ended by using the FROM instruction. From example: Additional resources How to build multi-architecture container images article 2.3. Running a container image Use the podman run command to run and test your container. Prerequisites The container-tools meta-package is installed. Procedure Run the container named mybootc based on the quay.io/ <namespace> / <image> : <tag> container image: The -i option creates an interactive session. Without the -t option, the shell stays open, but you cannot type anything to the shell. The -t option opens a terminal session. Without the -i option, the shell opens and then exits. The --rm option removes the quay.io/ <namespace> / <image> : <tag> container image after the container exits. Verification List all running containers: Additional resources Podman run command 2.4. Pushing a container image to the registry Use the podman push command to push an image to your own, or a third party, registry and share it with others. The following procedure uses the Red Hat Quay registry. Prerequisites The container-tools meta-package is installed. An image is built and available on the local system. You have created the Red Hat Quay registry. For more information see Proof of Concept - Deploying Red Hat Quay . Procedure Push the quay.io/ <namespace> / <image> : <tag> container image from your local storage to the registry: Additional resources podman-tag(1) man page podman-push(1) man page

Commands:
FROM registry.redhat.io/rhel9/rhel-bootc:latest RUN dnf -y install [software] [dependencies] && dnf clean all ADD [application] ADD [configuration files] RUN [config scripts]
cat Containerfile FROM registry.redhat.io/rhel9/rhel-bootc:latest RUN dnf -y install cloud-init && ln -s ../cloud-init.target /usr/lib/systemd/system/default.target.wants && dnf clean all
podman build -t quay.io/ <namespace> / <image> : <tag> .
podman images REPOSITORY TAG IMAGE ID CREATED SIZE localhost/ <image> latest b28cd00741b3 About a minute ago 2.1 GB
FROM registry.access.redhat.com/ubi9/go-toolset:latest as builder RUN echo 'package main; import "fmt"; func main() { fmt.Println("hello world") }' > helloworld.go RUN go build helloworld.go FROM registry.redhat.io/rhel9/rhel-bootc:latest COPY --from=builder /opt/app-root/src/helloworld / CMD ["/helloworld"]
podman build --target build -t hello .
COPY --from=<image> <source_path> <destination_path>_
FROM ubi9 AS stage1 [...] FROM stage1 AS stage2 [...] FROM ubi9 AS final-stage [...]
podman run -it --rm --name mybootc quay.io/ <namespace> / <image> : <tag> /bin/bash
podman ps CONTAINER ID IMAGE COMMAND CREATED STATUS PORTS NAMES 7ccd6001166e quay.io/ <namespace> / <image> : <tag> /sbin/init 6 seconds ago Up 5 seconds ago mybootc
podman push quay.io/ <namespace> / <image> : <tag>