Buildah: Build OCI Images Without Docker

Khimananda Oli 8 min read Database
Buildah: Build OCI Images Without Docker

By Khimananda Oli | Last reviewed: August 2026

Running a privileged Docker daemon inside CI runners or Kubernetes pods remains one of the most persistent security risks in modern DevOps workflows. Buildah: Build OCI Images Without Docker solves this by providing a daemonless, rootless-capable tool that constructs standard Open Container Initiative images directly from userspace. This approach eliminates the attack surface of a long-running root process while maintaining full compatibility with existing registries and runtimes. For teams implementing DevSecOps practices, migrating to Buildah is often the critical step needed to secure the software supply chain without sacrificing developer velocity.

How does Buildah build OCI images without Docker work?

Unlike traditional container tools that rely on a client-server model, Buildah operates as a standalone command-line utility that manipulates filesystem layers and metadata directly. When you invoke a build command, Buildah creates a working container (a lightweight sandbox), executes your instructions against it, and commits the resulting filesystem changes into an OCI image layout. There is no socket communication, no REST API, and no persistent background service consuming resources when idle.

User / CI Runner(Unprivileged)Buildah CLIDaemonless ToolLinux KernelUser NamespacesOCI ImageStandard FormatNo Daemon Socket • No Root Privileges Required • Direct Filesystem Manipulation
Buildah architecture: direct userspace interaction with kernel namespaces eliminates the Docker daemon dependency

This architectural difference has profound implications for security and resource efficiency. In my experience managing multi-tenant Kubernetes clusters, removing the Docker daemon means a compromised build pod cannot pivot to control other containers on the node. The tool leverages Linux user namespaces to map the unprivileged build user to root inside the container namespace, allowing package installation and file permission changes without actual host root access. If you are familiar with Kubernetes RBAC security models, think of Buildah as applying least-privilege principles to the image build process itself.

How do you configure Buildah for rootless builds on Ubuntu?

Rootless mode is not enabled by default on all distributions, and misconfiguration here is the most common reason engineers abandon Buildah prematurely. You must configure subordinate UID/GID ranges and verify storage drivers before your first build.

Configure subordinate IDs and storage

  1. Install Buildah and required dependencies:
    sudo apt update
    sudo apt install -y buildah uidmap slirp4netns fuse-overlayfs
  2. Verify subordinate ID mappings exist for your user:
    grep "^$(whoami):" /etc/subuid
    grep "^$(whoami):" /etc/subgid
    If these return empty, add mappings:
    sudo usermod --add-subuids 100000-165535 --add-subgids 100000-165535 $(whoami)
  3. Configure the storage driver for rootless operation by editing ~/.config/containers/storage.conf:
    [storage]
    driver = "overlay"
    
    [storage.options.overlay]
    mount_program = "/usr/bin/fuse-overlayfs"
  4. Test the configuration with a simple scratch build:
    buildah from scratch
    buildah run --isolation chroot scratch echo "Rootless works"

A common mistake I see in Nepal-based development teams setting up local VPS environments is skipping the fuse-overlayfs installation. Without it, Buildah falls back to the VFS driver, which copies entire layer trees instead of using copy-on-write. Build times increase tenfold, and disk usage explodes. Always verify overlay support before proceeding to production pipeline integration.

What is the best way to write a Buildah build script for CI/CD?

While Buildah can parse Dockerfiles via buildah bud, its native scripting interface unlocks capabilities impossible with declarative syntax alone. Native scripts let you conditionally install packages, inject secrets at build time without baking them into layers, and validate intermediate states programmatically.

buildah frombuildah runbuildah copybuildah configbuildah commitWorking Container (Mutable Sandbox)• Install dependencies with package manager• Copy application source and configs• Set environment variables, ports, entrypoint• Run tests or validation checks mid-build• Inject secrets via --secret flag (not stored)⚠ Secrets never touch the final image layers✓ Final image is immutable OCI artifact
Native Buildah script flow: mutable working container enables secret injection and mid-build validation before committing immutable OCI image

Here is a production-grade native build script pattern I use for Go microservices. Note how secrets are mounted temporarily during compilation but never committed:

#!/bin/bash
set -euo pipefail

ctr=$(buildah from docker.io/library/golang:1.23-alpine)
mnt=$(buildah mount $ctr)

buildah run $ctr apk add --no-cache git ca-certificates

# Mount private repo credentials only during fetch
buildah run --secret=id=git_token,src=/run/secrets/git_token \
  $ctr sh -c 'git clone https://x-access-token:$(cat /run/secrets/git_token)@github.com/org/private-lib.git /tmp/lib'

buildah copy $ctr ./go.mod ./go.sum /app/
buildah run --workingdir /app $ctr go mod download
buildah copy $ctr . /app/
buildah run --workingdir /app $ctr go build -ldflags="-s -w" -o /app/server

buildah config --entrypoint '["/app/server"]' $ctr
buildah config --port 8080 $ctr
buildah config --env GIN_MODE=release $ctr

buildah unmount $ctr
buildah commit --squash $ctr myregistry.io/app:v1.2.3
buildah rm $ctr

The --squash flag collapses all intermediate layers into a single layer, reducing both image size and the forensic surface area for vulnerability scanners. For teams already practicing build pipeline automation, this script pattern slots directly into GitHub Actions or GitLab CI runners without requiring Docker-in-Docker sidecars.

How does Buildah compare to Docker and Kaniko for image building?

Choosing the right builder depends on your specific constraints around security, performance, and ecosystem compatibility. Each tool occupies a distinct niche in the container build landscape.

CriteriaBuildahDockerKaniko
Daemon RequiredNoYes (rootful or rootless)No
Rootless SupportNative, maturePossible, complex setupDesigned for rootless
Dockerfile CompatibilityFull (via buildah bud)NativeFull
Scripting / Programmatic BuildsExcellent (native CLI)Limited (multi-stage only)None (declarative only)
Secret Handling--secret mount (safe)BuildKit secrets (safe)ConfigMap/volume mounts
Layer CachingLocal + registry cacheLocal + BuildKit cacheRegistry-only cache
Best Use CaseCI/CD, K8s jobs, custom workflowsDeveloper workstationsGKE/EKS managed CI

In practice, I recommend Buildah for any environment where you control the build infrastructure and need flexibility. Kaniko excels specifically in managed Kubernetes CI systems like Google Cloud Build where even user namespaces are restricted. Docker remains appropriate for local development where convenience outweighs security concerns, but should be replaced in automated pipelines.

BuildahSecurity: ★★★★★Flexibility: ★★★★★Ease of Setup: ★★★☆☆✓ Rootless native✓ Scriptable builds✓ No daemon overhead✗ Steeper learning curve✗ SubUID config requiredDockerSecurity: ★★☆☆☆Flexibility: ★★★☆☆Ease of Setup: ★★★★★✓ Universal familiarity✓ Rich ecosystem✓ Compose integration✗ Privileged daemon✗ Attack surface in CIKanikoSecurity: ★★★★☆Flexibility: ★★☆☆☆Ease of Setup: ★★★★☆✓ Works in restricted K8s✓ No special node config✓ Registry caching built-in✗ Dockerfile only✗ Slower than Buildah
Buildah vs Docker vs Kaniko: trade-offs across security, flexibility, and operational complexity for container image building

How do you integrate Buildah into Kubernetes and CI pipelines securely?

Deploying Buildah in orchestrated environments requires attention to pod security standards and storage provisioning. The goal is maintaining rootless operation while ensuring builds complete reliably under resource constraints.

  • Pod Security Standards: Apply the restricted Pod Security Admission level. Buildah works within this constraint when user namespaces are enabled at the node level (userns=keep-id).
  • Storage Provisioning: Use ephemeral volumes or PVCs with ReadWriteOnce access for the build workspace. Avoid hostPath mounts entirely — they break rootless isolation guarantees.
  • Registry Authentication: Mount registry credentials as projected secrets rather than embedding them in build scripts. Use workload identity (IRSA, Workload Identity Federation) where available to eliminate static credentials.
  • Resource Limits: Set memory requests to at least 1GiB for Go/Rust builds. CPU limits cause throttling during compression phases; prefer requests-only scheduling for build pods.
  • Caching Strategy: Enable registry-based layer caching with --cache-from and --cache-to flags. Local cache volumes help but don't survive pod rescheduling in autoscaling clusters.

For teams operating in Nepal or regions with limited bandwidth to international registries, consider deploying a local pull-through cache like Harbor or Zot. Buildah respects standard registry mirror configurations in /etc/containers/registries.conf, dramatically reducing build times when base images are cached locally. This mirrors the optimization strategies discussed in container registry selection guides, but with Buildah-specific configuration paths.

Secure Your Build Pipeline with Buildah Today

Migrating to Buildah: Build OCI Images Without Docker is a concrete step toward supply chain security that pays dividends immediately in reduced attack surface and improved compliance posture. Start by converting a single non-critical CI job to validate your rootless configuration, then expand systematically across your pipeline. The initial setup investment in subordinate IDs and storage drivers is modest compared to the operational risk of running privileged daemons in shared infrastructure. If your team needs guidance on securing container build workflows or achieving SOC 2 compliance for your deployment pipeline, reach out to discuss your specific requirements.

Frequently Asked Questions

Buildah is a CLI tool for building OCI-compliant container images without requiring a daemon. It offers better security in CI pipelines by running as a non-root user and eliminates the single point of failure associated with the Docker daemon architecture.

No, Buildah supports rootless mode using user namespaces. This allows unprivileged users to build images safely, reducing security risks in shared CI environments compared to traditional Docker setups that often require root access or privileged daemon sockets.

Yes, Buildah fully supports standard Dockerfile syntax via the buildah bud command. You can reuse existing Dockerfiles without modification, making migration from Docker seamless while gaining daemonless benefits and stricter OCI compliance for your container workflows.

Buildah focuses exclusively on building OCI images, while Podman manages container lifecycles. Podman actually uses Buildah internally for builds. Use Buildah directly in CI scripts for granular control over layers and mounts without the overhead of container runtime management.

Yes, Buildah produces standard OCI images compatible with any Kubernetes distribution and registry like ECR, GCR, or Harbor. The resulting images are indistinguishable from Docker-built ones, ensuring full interoperability across cloud-native infrastructure in 2026 deployments.

Install via apt install buildah after enabling the universe repository. For newer versions, use the Kubic project PPA. Verify installation with buildah version to confirm compatibility with your kernel’s user namespace support for rootless operations.

Yes, Buildah excels at nested builds within containers using fuse-overlayfs storage drivers. This enables secure, isolated CI pipelines where the build environment itself is containerized, avoiding host system pollution and enabling reproducible builds across different runner environments.

Buildah supports overlay, fuse-overlayfs, vfs, and btrfs storage drivers. Overlay is default for rootful builds; fuse-overlayfs is preferred for rootless. Configure via /etc/containers/storage.conf based on your filesystem capabilities and permission model requirements.

Use buildah push with authentication via --creds or pre-configured auth.json. Buildah respects standard containers-auth.json locations. For CI, inject credentials securely through environment variables or mounted secrets rather than embedding them in build scripts.

Slowness often stems from missing layer caching or inefficient storage drivers. Ensure you use overlay or fuse-overlayfs instead of vfs. Also verify that base images are pulled once and cached locally, as Buildah doesn’t share Docker’s image cache.

Yes, Buildah fully supports multi-stage Dockerfile builds. Each stage creates intermediate working containers that are discarded after copying artifacts. This reduces final image size effectively while maintaining compatibility with complex application build patterns common in Laravel and Node.js projects.

Use buildah unshare to enter the build namespace interactively. Inspect working containers with buildah inspect or mount them via buildah mount to examine filesystem state. Check logs with --log-level debug to diagnose storage, network, or permission issues during builds.

Yes, Buildah integrates with tools like syft and trivy for SBOM generation. Use buildah commit with annotations or post-process images to embed software bills of materials, meeting 2026 supply chain security requirements for enterprise and government deployments.

Yes.

Absolutely.