Buildah
What it is
Buildah is a command-line tool for building OCI (Open Container Initiative) container images, allowing you to create images from scratch or by modifying existing ones without needing a container runtime like Docker.
Installation
Linux (Debian/Ubuntu)
sudo apt update
sudo apt install buildah
Linux (Fedora/CentOS/RHEL)
sudo dnf install buildah
# or
sudo yum install buildah
macOS
Buildah typically runs within a Linux environment. The recommended way to use it on macOS is via Docker Desktop or a similar VM.
- Install Docker Desktop: Download and install from docker.com.
- Enable the "Use Rosetta for x86/amd64 emulation on Apple Silicon" setting in Docker Desktop’s General preferences. This is crucial for running Linux containers on Apple Silicon.
- Pull a suitable base image:
docker pull fedora:latest - Run Buildah interactively:
docker run --rm -it -v /var/run/docker.sock:/var/run/docker.sock fedora:latest bash # Inside the container: dnf update -y && dnf install -y buildah # Now you can use buildah commands within this container
Windows
Buildah can be run within the Windows Subsystem for Linux (WSL) 2.
- Install WSL 2: Follow Microsoft’s official guide: Microsoft Docs - Install WSL.
- Install Buildah within your chosen Linux distribution:
# Example for Ubuntu in WSL sudo apt update sudo apt install buildah
Core Concepts
- Container as a Build Environment: Buildah doesn’t build images in a daemon. Instead, it creates a working container from a base image. You then
mountthis container’s filesystem and make modifications (installing software, copying files, setting environment variables) directly to it. - Image Layers: Each command that modifies the container’s filesystem (like installing a package or copying a file) can be committed as a new layer in the final image. This allows for efficient image layering and caching.
- Scratch Image: You can start building an image from
scratch, which is an empty filesystem, and add everything yourself. - OCI Image: Buildah produces images that conform to the Open Container Initiative (OCI) image specification, making them compatible with other OCI-compliant runtimes and registries.
Commands / Usage
Building from a Base Image
-
buildah from <image>: Creates a working container from a specified base image.buildah from fedora:latest # Output: fedoraThis command returns the name of the new working container. You’ll use this name in subsequent commands.
-
buildah mount <container>: Mounts the working container’s filesystem to a directory on your host.container=$(buildah from fedora:latest) mountpoint=$(buildah mount $container) echo $mountpoint # Output: /var/lib/containers/storage/overlay-images/...The output is the path to the mounted filesystem.
-
buildah unmount <container>: Unmounts the working container’s filesystem.buildah unmount $container -
buildah config <container> [options]: Configures metadata for the image being built.--author "Jane Doe <jane@example.com>": Sets the author.buildah config $container --author "Jane Doe <jane@example.com>"--label key=value: Adds a label.buildah config $container --label maintainer="John Smith" --label version="1.0"--cmd "/usr/bin/python": Sets the default command to run when the container starts.buildah config $container --cmd "/app/run.sh"--entrypoint '["/usr/bin/python", "app.py"]': Sets the entrypoint. Note the JSON array format.buildah config $container --entrypoint '["/usr/local/bin/my-app"]'--env KEY=VALUE: Sets environment variables.buildah config $container --env PATH="/usr/local/bin:$PATH" --env MY_VAR=my_value--port 8080: Exposes a port.buildah config $container --port 8080 --port 443--user "appuser": Sets the default user.buildah config $container --user appuser--workingdir /app: Sets the working directory.buildah config $container --workingdir /app--url http://example.com: Sets the URL for the image.buildah config $container --url http://example.com--created-by "Buildah": Sets the creator.buildah config $container --created-by "Buildah v1.20"--stop-signal SIGTERM: Sets the stop signal.buildah config $container --stop-signal SIGKILL--health-cmd '["CMD-SHELL", "curl -f http://localhost:8080 || exit 1"]': Sets health check command.buildah config $container --health-cmd '["CMD-SHELL", "wget --quiet --tries=1 --spider http://localhost:8080 || exit 1"]'--health-interval 30s: Sets health check interval.buildah config $container --health-interval 1m--health-timeout 10s: Sets health check timeout.buildah config $container --health-timeout 5s--health-retries 3: Sets health check retries.buildah config $container --health-retries 5--health-start-period 10s: Sets health check start period.buildah config $container --health-start-period 30s
-
buildah run <container> [command]: Runs a command inside the working container. This is how you install packages, create directories, etc.buildah run $container -- dnf update -y && dnf install -y httpdThe
--separates Buildah options from the command being run. -
buildah copy <container> <src> [dest]: Copies files or directories from the host to the working container.# Copy a single file buildah copy $container ./my-app.conf /etc/httpd/conf.d/ # Copy a directory recursively buildah copy $container ./app-code /var/www/html/ -
buildah add <container> <src> [dest]: Similar tobuildah copy, but specifically designed for adding files/directories to the container’s filesystem. Often used interchangeably withcopyfor basic file additions. -
buildah commit <container> <image-name> [options]: Creates a new OCI image from the working container.--rm: Removes the working container after committing.buildah commit --rm $container my-web-server:latest
-
buildah push <image-name> [options]: Pushes an image to a container registry.--tls-verify=false: Disables TLS verification (use with caution).buildah push my-web-server:latest docker://docker.io/yourusername/my-web-server:v1.0 --tls-verify=false
-
buildah images: Lists images available on the host.buildah images -
buildah containers: Lists working containers.buildah containers -
buildah rm <container>: Removes a working container.buildah rm $container
Building from a Dockerfile
buildah bud [options] [context]: Builds an image from a Dockerfile.-f Dockerfile: Specifies the Dockerfile path.buildah bud -f Dockerfile .--format oci: Specifies the output format (default is oci).buildah bud --format docker .--tag my-app:latest: Tags the resulting image.buildah bud -f Dockerfile --tag my-app:v1.1 .--output: Outputs the image as a tarball.buildah bud -f Dockerfile --output my-app.tar .--isolation chroot: Specifies the container isolation method (default ischroot). Other options includeociandoverlay.buildah bud --isolation overlay -f Dockerfile .--platform linux/amd64: Specifies the target platform.buildah bud --platform linux/arm64 -f Dockerfile .
Inspecting Images and Containers
-
buildah inspect <image-or-container>: Displays detailed information about an image or container in JSON format.buildah inspect my-app:latest -
buildah history <image>: Shows the history of an image (layers).buildah history fedora:latest
Managing Container Storage
-
buildah storage --driver overlay --storage-driver-opts size=10G: Sets storage driver options.buildah storage --driver overlay --storage-driver-opts size=20G -
buildah storage --driver overlay --storage-driver-opts overlay.mount_program=/usr/bin/fuse-overlayfs: Specifies the mount program for overlayfs.buildah storage --driver overlay --storage-driver-opts overlay.mount_program=/usr/local/bin/fuse-overlayfs
Working with Existing Images
-
buildah pull <image>: Pulls an image from a registry.buildah pull ubuntu:22.04 -
buildah tag <source-image> <new-tag>: Tags an existing image.buildah tag my-app:latest my-app:v2.0 -
buildah rmi <image>: Removes an image.buildah rmi my-app:v2.0
Advanced Operations
-
buildah from --pull-never <image>: Creates a working container without attempting to pull the image if it doesn’t exist locally.buildah from --pull-never non-existent-image -
buildah config --annotation key=value <container>: Adds an annotation to the image configuration.buildah config $container --annotation com.example.project="my-project" -
buildah mount --json <container>: Mounts the container and outputs mount information in JSON format. Useful for scripting.buildah mount --json $container # Output: {"Name":"my-container","Mountpoint":"/var/lib/containers/storage/overlay-images/..."} -
buildah tree <image>: Displays the image layers in a tree format.buildah tree fedora:latest -
buildah manifest <command>: Manages OCI image manifests (for multi-architecture images).buildah manifest create my-multi-arch-image:latest: Creates a new manifest list.buildah manifest create my-multi-arch-image:latestbuildah manifest add my-multi-arch-image:latest my-amd64-image:v1.0: Adds an image to the manifest list.buildah manifest add my-multi-arch-image:latest my-amd64-image:v1.0 --os linux --arch amd64buildah manifest push my-multi-arch-image:latest docker://docker.io/yourusername/my-multi-arch-image:latest: Pushes the manifest list.buildah manifest push my-multi-arch-image:latest docker://docker.io/yourusername/my-multi-arch-image:latest
Common Patterns
-
Basic Image Build Workflow:
# Create a working container from a base image container=$(buildah from fedora:latest) # Mount the container's filesystem mountpoint=$(buildah mount $container) # Perform actions inside the container (e.g., install packages, copy files) buildah run $container -- dnf update -y && dnf install -y httpd buildah copy $container ./index.html $mountpoint/var/www/html/ # Configure image metadata buildah config $container --cmd "/usr/sbin/httpd -DFOREGROUND" --port 80 # Unmount the filesystem buildah unmount $container # Commit the container to an image buildah commit --rm $container my-httpd-image:latest # Optionally, push the image # buildah push my-httpd-image:latest docker://docker.io/yourusername/my-httpd-image:v1.0 -
Building from a Dockerfile with Buildah:
# Build and tag the image buildah bud --tag my-custom-app:v1.0 -f Dockerfile . # Push the image # buildah push my-custom-app:v1.0 docker://docker.io/yourusername/my-custom-app:v1.0 -
Copying files into a running container for debugging:
container=$(buildah from ubuntu:latest) mountpoint=$(buildah mount $container) # Now you can manually copy files into $mountpoint or use buildah copy buildah copy $container ./my-debug-script.sh /tmp/ # ... inspect the container ... buildah rm $container # Clean up -
Creating an image from scratch:
# Start with an empty container container=$(buildah from scratch) # Mount it mountpoint=$(buildah mount $container) # Manually copy your compiled binary and any necessary libraries/configs cp /path/to/your/static-binary $mountpoint/usr/local/bin/my-app # If not static, you'd need to copy shared libraries too. # Configure the image to run your binary buildah config $container --cmd "/usr/local/bin/my-app" # Unmount and commit buildah unmount $container buildah commit --rm $container my-scratch-app:latest -
Using
buildah runwithdnfand committing intermediate layers:container=$(buildah from fedora:latest) buildah run $container -- dnf update -y buildah config $container --label "updated=true" # Add a label for this layer # You could commit here if you wanted to save this state as an image layer # buildah commit $container fedora-updated:latest buildah run $container -- dnf install -y vim buildah commit --rm $container fedora-vim:latest
Gotchas
- Rootless Mode: Buildah supports rootless mode, which is highly recommended for security. However, some operations (like mounting filesystems with certain drivers or network configurations) might behave differently or have limitations in rootless mode. Ensure your storage driver and mount options are compatible.
- Mountpoint Paths: The path returned by
buildah mountis a direct path to the container’s filesystem overlay. Be careful when using this path; it’s not a typical container mount point like you’d see withdocker run -v. Direct manipulation is possible but less common than usingbuildah copyorbuildah run. - Container Naming:
buildah fromreturns a container name (often a random string). You need to capture this name in a variable and reuse it for subsequent commands operating on that specific working container. buildah runvs.docker run:buildah runexecutes a command within the working container to modify its filesystem or state for the build process. It does not start a long-running container for execution likedocker run.- Image Tagging: When committing, you provide the final image tag (
my-image:latest). Buildah doesn’t automatically tag intermediate layers unless you explicitlybuildah committhem. buildah budvs.docker build: Whilebuildah budaims for Dockerfile compatibility, there might be subtle differences in how certain Dockerfile instructions are interpreted or supported, especially regarding complex build arguments or specific Docker daemon interactions.- Storage Drivers: Buildah relies on storage drivers (like overlay, overlay2, btrfs, etc.) to manage container layers. The availability and behavior of these drivers can vary between Linux distributions and kernel versions. Ensure you have a compatible driver configured.
buildah rmvs.docker system prune:buildah rmonly removes the specified working container. Buildah doesn’t have a direct equivalent todocker system prunefor cleaning up all unused images and containers automatically. You’ll typically manage image cleanup withbuildah rmiand container cleanup withbuildah rmafter committing or abandoning them.