Buildah Image Builder

Buildah cheatsheet — build OCI images without Docker daemon. buildah bud -t myapp ., buildah from, buildah run, buildah push. Rootless container image builds.

11 min read

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.

  1. Install Docker Desktop: Download and install from docker.com.
  2. 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.
  3. Pull a suitable base image:
    docker pull fedora:latest
    
  4. 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.

  1. Install WSL 2: Follow Microsoft’s official guide: Microsoft Docs - Install WSL.
  2. 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 mount this 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: fedora
    

    This 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 httpd
    

    The -- 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 to buildah copy, but specifically designed for adding files/directories to the container’s filesystem. Often used interchangeably with copy for 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 is chroot). Other options include oci and overlay.
      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:latest
      
    • buildah 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 amd64
      
    • buildah 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

  1. 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
    
  2. 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
    
  3. 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
    
  4. 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
    
  5. Using buildah run with dnf and 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 mount is 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 with docker run -v. Direct manipulation is possible but less common than using buildah copy or buildah run.
  • Container Naming: buildah from returns 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 run vs. docker run: buildah run executes 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 like docker run.
  • Image Tagging: When committing, you provide the final image tag (my-image:latest). Buildah doesn’t automatically tag intermediate layers unless you explicitly buildah commit them.
  • buildah bud vs. docker build: While buildah bud aims 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 rm vs. docker system prune: buildah rm only removes the specified working container. Buildah doesn’t have a direct equivalent to docker system prune for cleaning up all unused images and containers automatically. You’ll typically manage image cleanup with buildah rmi and container cleanup with buildah rm after committing or abandoning them.