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
runc
to execute containers - Directory
/etc/containers/
…registries.conf
container image name completionmounts.conf
paths automatically mounted inside containers
images
, containers
& from
# list all local images
buildah images
Build a working container from an existing image…
# list local working containers
buildah containers
- …defaults to appending
-working-container
to the image’s name - CLI conveniently returns the name of the new container…
- …assigning the returned value to a shell variable
from
pulls 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
c5162c15716e2f679a23ca59347ca380bbee238b8759e02ebd8927ef2aae417b
Dockerfile
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
-f
specify the path to the Dockerfile - …option
-t
to 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-slurmctld
Same 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 $container
buildah
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
podman
to 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_world
config
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" $container
Example --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 $container
commit
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 container
Noteworthy options…
- …
--rm
…remove working container afterwards - …
--format
…for the image manifest and configuration data- …
docker
version 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 directorydocker://
…docker compatible registryoci:
… OCI container layoutoci-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-layout
Examples
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.1
Spack & 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 \
$spack_source_path
https://github.com/spack/spack.git 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 $container
The 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