
In the world of containers, Buildah stands out as a powerful yet lightweight tool for building OCI (Open Container Initiative)-compliant container images. Unlike traditional tools like Docker, Buildah takes a daemonless approach, making it secure, flexible, and ideal for modern development workflows.
Key Features
-
Daemonless Architecture: Buildah doesn’t rely on a background service (like Docker’s daemon). Instead, it directly manipulates images, ensuring a smaller footprint and lower resource usage.
-
Rootless and Secure: You can run Buildah without root privileges, making it safer, especially in multi-user environments or CI/CD pipelines.
-
Dockerfile-Free Flexibility: While Buildah supports Dockerfiles, it also enables image creation without one. Developers can use shell commands or scripts, offering full control over the image-building process.
-
OCI Compliance and Versatility: Buildah creates both OCI and Docker-formatted images, ensuring compatibility with tools like Podman, Docker, and Kubernetes.
-
Lightweight and Scriptable: Its minimal design makes Buildah perfect for automation and scripting, particularly in resource-constrained environments.
Installation
On Linux install it like this:
sudo apt-get -y install buildah
sudo yum -y install buildah
For other Linux systems or for building from scratch, please take a look at the Buildah Website: Installation.
Using Buildah
Buildah allows us to derive custom images from a base image in no time, following a similar workflow:
Starting a container from a base image
buildah from alpine
buildah from alpine
Resolved "alpine" as an alias (/etc/containers/registries.conf.d/shortnames.conf)
Trying to pull docker.io/library/alpine:latest...
Getting image source signatures
Copying blob 1f3e46996e29 done
Copying config b0c9d60fc5 done
Writing manifest to image destination
Storing signatures
alpine-working-container
Modify a container
We want to install curl into our container…
buildah run alpine-working-container -- apk add --no-cache curl
buildah run alpine-working-container -- apk add --no-cache curl
fetch https://dl-cdn.alpinelinux.org/alpine/v3.21/main/x86_64/APKINDEX.tar.gz
fetch https://dl-cdn.alpinelinux.org/alpine/v3.21/community/x86_64/APKINDEX.tar.gz
(1/9) Installing brotli-libs (1.1.0-r2)
(2/9) Installing c-ares (1.34.3-r0)
(3/9) Installing libunistring (1.2-r0)
(4/9) Installing libidn2 (2.3.7-r0)
(5/9) Installing nghttp2-libs (1.64.0-r0)
(6/9) Installing libpsl (0.21.5-r3)
(7/9) Installing zstd-libs (1.5.6-r2)
(8/9) Installing libcurl (8.11.1-r0)
(9/9) Installing curl (8.11.1-r0)
Executing busybox-1.37.0-r9.trigger
OK: 12 MiB in 24 packages
Add Files
buildah copy alpine-working-container ./my-app /app
buildah copy alpine-working-container ./my-app /app
e8cd61d7504140f22f673147bbdd78d3ac5f99d325bab53aafcfca029d689f84
Set metadata (modify environment variables and entrypoints)
buildah config --env APP_ENV=production --entrypoint "/app/start.sh" alpine-working-container
buildah config --env APP_ENV=production --entrypoint "/app/start.sh" alpine-working-container
WARN[0000] cmd "/bin/sh" exists but will be ignored because of entrypoint settings
Commit the Changes
buildah commit alpine-working-container my-custom-image
buildah commit alpine-working-container my-custom-image
Getting image source signatures
Copying blob a0904247e36a [--------------------------------------] 0.0b / 0.0b
Copying blob 0704e6598cc7 done
Copying config c353c06acc done
Writing manifest to image destination
Storing signatures
c353c06acc7fc4c66f1189a5f21bd94589e74b4f657634c3b518a5ad651b05c6
List containers
buildah ls
CONTAINER ID BUILDER IMAGE ID IMAGE NAME CONTAINER NAME
5ceeca1b8928 * b0c9d60fc5e3 docker.io/library/alpine:latest alpine-working-container
Clean up
buildah rm alpine-working-container
buildah rm alpine-working-container
5ceeca1b8928d0a8d25456767429914b23fdc548bb1a76ac939dee275ef36be5
Working with Dockerfiles
Buildah can also work with Dockerfiles. Here’s how we can build an image using a Dockerfile
:
FROM alpine
RUN apk add --no-cache curl
COPY ./my-app /app
ENV APP_ENV=production
ENTRYPOINT ["/app/start.sh"]
buildah bud -t my-custom-image .
buildah bud -t my-custom-image .
STEP 1/5: FROM alpine
STEP 2/5: RUN apk add --no-cache curl
fetch https://dl-cdn.alpinelinux.org/alpine/v3.21/main/x86_64/APKINDEX.tar.gz
fetch https://dl-cdn.alpinelinux.org/alpine/v3.21/community/x86_64/APKINDEX.tar.gz
(1/9) Installing brotli-libs (1.1.0-r2)
(2/9) Installing c-ares (1.34.3-r0)
(3/9) Installing libunistring (1.2-r0)
(4/9) Installing libidn2 (2.3.7-r0)
(5/9) Installing nghttp2-libs (1.64.0-r0)
(6/9) Installing libpsl (0.21.5-r3)
(7/9) Installing zstd-libs (1.5.6-r2)
(8/9) Installing libcurl (8.11.1-r0)
(9/9) Installing curl (8.11.1-r0)
Executing busybox-1.37.0-r9.trigger
OK: 12 MiB in 24 packages
STEP 3/5: COPY ./my-app /app
STEP 4/5: ENV APP_ENV=production
STEP 5/5: ENTRYPOINT ["/app/start.sh"]
COMMIT my-custom-image
Getting image source signatures
Copying blob a0904247e36a skipped: already exists
Copying blob a2485dbc391e done
Copying config 24ffb5a676 done
Writing manifest to image destination
Storing signatures
--> 24ffb5a6765
Successfully tagged localhost/my-custom-image:latest
24ffb5a67653ba898d5f921eb461806b65494de08a45f5b80dea5498231af55e
Tutorial Sources
Please feel free to download the tutorial sources from my GitHub repository, fork it there or clone it using Git:
git clone https://github.com/hascode/buildah-tutorial.git