Buildah - Build OCI Container Images
buildah
…user-space tool to interactively build container images…
- …replicates commands that are found in a Dockerfile
- …enables a build workflow as non-root user
- …compatible to OCI container images with Docker format
- …supports multi-stage customizable image layer caching
- …use the same image and storage components as CRI-OCI
- References…
Configuration…
- …uses runcto execute containers
- Directory /etc/containers/…- registries.confcontainer image name completion
- mounts.confpaths automatically mounted inside containers
 
images, containers & from
# list all local images
buildah imagesBuild a working container from an existing image…
# list local working containers
buildah containers- …defaults to appending -working-containerto the image’s name
- CLI conveniently returns the name of the new container…
- …assigning the returned value to a shell variable
- frompulls and creates a working container in one step…
# ...for example latest RockyLinux
>>> buildah from rockylinux/rockylinux:8
...
rockylinux-working-container     # <- name of the container
# ...automatically started
>>> buildah containers     
CONTAINER ID  BUILDER  IMAGE ID     IMAGE NAME                       CONTAINER NAME
c5162c15716e     *     c830f8e8f82b docker.io/library/rockylinux:... rockylinux-working-container
# shell into the container
>>> buildah run rockylinux-working-container bash
[root@c5162c15716e /]# exit
exit
# remove the container
>>> buildah rm rockylinux-working-container      
c5162c15716e2f679a23ca59347ca380bbee238b8759e02ebd8927ef2aae417bDockerfile vs Scripting
The build sub-command takes a Dockerfile [^2] as input and produces container image…
FROM rockylinux:latest
MAINTAINER Victor Penso
RUN set -x \
    && dnf -y update; dnf -y clean all \
    && dnf install -y epel-release dnf-plugins-core \
    && dnf config-manager --set-enabled powertools \
    && dnf install -y slurm-slurmctld
EXPOSE 6817
CMD ["/usr/sbin/slurmctld", "-Dvvvv"]- …option -fspecify the path to the Dockerfile
- …option -tto tag the container image
buildah build -f /tmp/Dockerfile -t rocky-slurmctld
# list the container image
podman images rocky-slurmctld
# create a container from the image...
podman run --rm rocky-slurmctldSame as above with buildah sub-commands…
container=rocky-slurm
buildah from --name $container rockylinux
buildah run $container -- dnf -y update; dnf -y clean all
buildah run $container -- dnf install -y epel-release dnf-plugins-core
buildah run $container -- dnf config-manager --set-enabled powertools
buildah run $container -- dnf install -y slurm-slurmctld
buildah config --port 6817 $container
buildah config --cmd '/usr/sbin/slurmctld -Dvvvv' $container
buildah commit $containerbuildah commands can be used with any scripting language to automate container build completely in user-space (no additional access privileges required).
run & copy
run executes a command in the container…
- …run commands as part of the build process
- …intended for debugging
- …use podmanto run containers in production
 
# start an interactive shell...
buildah run --terminal $container -- $SHELL
# execute a single command...
buildah run $container -- dnf install -y git
buildah run $container --workingdir /tmp -- ...
# run multiple commands...
buildah run $container -- /bin/bash -ic '
        dnf -y update
        dnf -y clean all
'copy files to a container without mounting it
# dummy executable
echo 'echo Hello World' > /tmp/hello_world && chmod +x /tmp/hello_world
# create a new container and copy a the executable
container=$(buildah from alpine)
buildah copy $container /tmp/hello_world /usr/local/bin
# use the executable as entrypoint
buildah config --entrypoint '/bin/sh -c /usr/local/bin/hello_world' $container
buildah commit $container localhost/hello_world:latest
podman run -it localhost/hello_worldconfig
config modifies the container meta-configuration…
Example --entrypoint configuration:
# configure the container entrypoint...
container=$(buildah from rockylinux)
buildah run $container -- dnf install -y httpd
# configure the process to run on container start
buildah config --entrypoint "/usr/sbin/httpd -DFOREGROUND" $containerExample --port and --cmd configuration:
container=$(buildah from rockylinux)
buildah run $container -- dnf install -y nginx
buildah run $container -- systemctl enable nginx.service
# enable port mapping
buildah config --port 8080:80 $container
# configure the command to execute on container start
buildah config --cmd /usr/sbin/init $containercommit
Create a container image from a working container…
                     ┌────────┬──────────────── container registry on localhost
                     │        │
                     │        │      ┌────┬──── optional tag or version information
buildah commit hello localhost/hello:2.12.1
               │   │           └───┴─────────── name of the container image
               │   │
               └───┴─────────────────────────── name of working containerNoteworthy options…
- …--rm…remove working container afterwards
- …--format…for the image manifest and configuration data- …dockerversion 2, using schema format 2 for the manifest
- …oci…default…OCI image-spec v1.0
 
- …
push
…image from local storage to a specified destination…
- …decompressing and recompessing layers as needed
- …read man 5 containers-transports
- Destinations….
- dir:…existing local directory
- docker://…docker compatible registry
- oci:… OCI container layout
- oci-archive:…OCI container image archive
 
>>> buildah push fedora dir:fedora/
>>> ls -1 fedora   
  2ecb6df959942dd2fdeb65606ca2e42a54f8c06af10eeb594fdfc3e2656c53d1
  62946078034b7fe37984579d9b82ccf20cc98ffcd6517cf79ffad18e06fe2b23
  manifest.json
  version>>> buildah push fedora oci:fedora/
>>> ls -1 fedora 
blobs/
index.json
oci-layout
# ...build an OCI image archive
>>> buildah push localhost/hello:2.12.1 oci-archive:/tmp/hello.tar
>>> tar -tf /tmp/hello.tar
blobs/
blobs/sha256/
blobs/sha256/3bb03adbd305b52d94c0db084885c730f35791e5b948cc4aca084a9c9daa95d4
blobs/sha256/9dad25583c4d8ccfefa2758f6ade83a162e92de4e810aa683a38a7bac3c77bc1
blobs/sha256/cb42c62e4863a105c291cb68c2caa9ce838e48fcfb3f92ec8c17e70e1ec3c438
blobs/sha256/f54fcbf88ba2e4838e115116f98b438e0019e2c1eb9703ac79f10203e32dcdb0
index.json
oci-layoutExamples
Build the hello source code within the container…
container=$(buildah from fedora:37)
buildah config --label maintainer="John Snow <j.snow@example.com>" $container
wget https://ftp.gnu.org/gnu/hello/hello-2.12.1.tar.gz
buildah copy $container hello-2.12.1.tar.gz /tmp/hello-2.12.1.tar.gz
rm hello-2.12.1.tar.gz
buildah run $container dnf install -y tar gzip gcc make
buildah run $container dnf clean all
buildah run $container tar xvzf /tmp/hello-2.12.1.tar.gz -C /opt
buildah config --workingdir /opt/hello-2.12.1 $container
buildah run $container ./configure
buildah run $container make
buildah run $container make install
buildah run $container hello -v
buildah config --entrypoint /usr/local/bin/hello $container
buildah commit --format docker $container hello:2.12.1Spack & Nano
Following builds a container including the spack package management system…
spack_version=${1:-0.19}
spack_source_path=/srv/spack
spack_install_root=/opt/spack
container_image=${2:-rockylinux/rockylinux:8}
container=spack-$spack_version
# bootstrap container and install platform dependencies
buildah from --name $container $container_image
buildah run $container -- dnf install -y epel-release dnf-plugins-core
buildah run $container -- dnf config-manager --set-enabled powertools
buildah run $container -- dnf group install -y 'Development Tools'
# install Spack dependencies
buildah run $container \
        -- dnf install -y \
                curl findutils gcc-c++ gcc gcc-gfortran git gnupg2 \
                hostname iproute redhat-lsb-core make patch python3 \
                python3-pip python3-setuptools unzip \
        && python3 -m pip install boto3
# install the Spack source code repository
buildah run $container \
        -- git clone -c feature.manyFiles=true \
                https://github.com/spack/spack.git $spack_source_path
buildah run --workingdir $spack_source_path $container \
        -- git checkout releases/v$spack_version
# add Spack to the environment
tmp_file=$(mktemp)
echo "source /srv/spack/share/spack/setup-env.sh" > $tmp_file
buildah copy $container $tmp_file /etc/default/spack
buildah run $container -- ln -s /etc/default/spack /etc/profile.d/spack.sh
# configure Spack
buildah run --terminal $container -- /bin/bash -ic \
        "spack config --scope system add config:install_tree:root:$spack_install_root"
# build the container and store it to the local registry
buildah commit $container $containerThe generic Spack container is then used to build a specific application container…
nano_version=6.3
container=nano-$nano_version
buildah from --name $container localhost/spack-0.19
buildah run $container -- /bin/bash -ic "
      spack install nano@$nano_version
      spack load --sh nano > /etc/profile.d/nano.sh
"
buildah config --entrypoint '/bin/bash -ic nano' $container
buildah commit --rm $container $container
# run the container to launch nano...
podman run -it localhost/nano-6.3