Why Not Just Docker Build?
Traditional docker build requires:
- Docker daemon running (root privileges)
- Docker socket access (security risk in CI)
- Privileged containers in Kubernetes
Both Buildah and Kaniko solve this with daemonless, rootless builds.
Buildah
Buildah builds OCI container images without a daemon. Created by Red Hat, it integrates with Podman and CRI-O.
Basic Usage
# Build from Dockerfile
buildah bud -t myapp:latest .
# Scripted build (no Dockerfile needed)
container=$(buildah from registry.access.redhat.com/ubi9/ubi-minimal)
buildah run $container -- dnf install -y python3
buildah copy $container ./app /opt/app
buildah config --cmd "python3 /opt/app/main.py" $container
buildah commit $container myapp:latest
buildah push myapp:latest docker://registry.example.com/myapp:latestIn GitLab CI (Rootless)
build:
image: quay.io/buildah/stable
stage: build
variables:
STORAGE_DRIVER: vfs
BUILDAH_FORMAT: docker
script:
- buildah login -u $CI_REGISTRY_USER -p $CI_REGISTRY_PASSWORD $CI_REGISTRY
- buildah bud --layers -t $CI_REGISTRY_IMAGE:$CI_COMMIT_SHA .
- buildah push $CI_REGISTRY_IMAGE:$CI_COMMIT_SHAIn GitHub Actions
- name: Build with Buildah
uses: redhat-actions/buildah-build@v2
with:
image: myapp
tags: latest ${{ github.sha }}
containerfiles: ./Dockerfile
- name: Push
uses: redhat-actions/push-to-registry@v2
with:
image: myapp
registry: ghcr.io/${{ github.repository_owner }}Strengths
- Rootless operation β no privilege escalation
- Dockerfile compatible β drop-in replacement for
docker build - Scripted builds β build without Dockerfile using shell commands
- Layer caching β
--layersflag enables layer reuse - OCI-native β produces standard OCI images
- Multi-arch β
buildah manifestfor cross-platform images
Limitations
- Linux only β no macOS/Windows support
- CI environments β needs
vfsstorage driver in containers (slower) - Not in Kubernetes pods natively β needs privileged or user namespace
Kaniko
Kaniko builds container images inside Kubernetes without Docker daemon or root access. Created by Google.
In Kubernetes (Pod)
apiVersion: v1
kind: Pod
metadata:
name: kaniko-build
spec:
containers:
- name: kaniko
image: gcr.io/kaniko-project/executor:latest
args:
- "--dockerfile=Dockerfile"
- "--context=git://github.com/org/repo.git#refs/heads/main"
- "--destination=registry.example.com/myapp:latest"
- "--cache=true"
- "--cache-repo=registry.example.com/cache"
volumeMounts:
- name: docker-config
mountPath: /kaniko/.docker/
volumes:
- name: docker-config
secret:
secretName: registry-credentials
restartPolicy: NeverIn GitHub Actions
- name: Build with Kaniko
uses: aevea/action-kaniko@v0.12.0
with:
image: myapp
tag: ${{ github.sha }}
registry: ghcr.io
username: ${{ github.actor }}
password: ${{ secrets.GITHUB_TOKEN }}
cache: true
cache_registry: ghcr.io/${{ github.repository }}/cacheIn GitLab CI
build:
stage: build
image:
name: gcr.io/kaniko-project/executor:debug
entrypoint: [""]
script:
- |
cat > /kaniko/.docker/config.json << EOF
{"auths":{"$CI_REGISTRY":{"auth":"$(echo -n $CI_REGISTRY_USER:$CI_REGISTRY_PASSWORD | base64)"}}}
EOF
- /kaniko/executor
--context $CI_PROJECT_DIR
--dockerfile $CI_PROJECT_DIR/Dockerfile
--destination $CI_REGISTRY_IMAGE:$CI_COMMIT_SHA
--cache=trueStrengths
- Runs in Kubernetes unprivileged β no root, no daemon, no socket
- Remote context β pull from Git, S3, GCS directly
- Layer caching β push cache layers to registry
- Reproducible β consistent builds regardless of host
- Multi-stage support β full Dockerfile support
Limitations
- No interactive debugging β canβt
execinto build - Slower first builds β no local layer cache
- Limited RUN caching β only layer-level, not apt/pip cache
- Snapshot overhead β filesystem snapshotting adds ~10-30% time
- No scripted builds β Dockerfile only
Head-to-Head
| Factor | Buildah | Kaniko |
|---|---|---|
| Runs in K8s pods | β οΈ Needs config | β Native |
| Dockerfile support | β Full | β Full |
| Scripted builds | β | β |
| Build speed | Faster (native) | Slower (snapshots) |
| Layer caching | Local + registry | Registry only |
| Multi-arch | β
buildah manifest | β |
| Security model | User namespaces | No root needed |
| Maintained by | Red Hat |
Build Time Comparison
Building a Node.js app (500MB image, 12 layers):
| Scenario | Buildah | Kaniko |
|---|---|---|
| Cold build (no cache) | 45s | 62s |
| Warm build (cached layers) | 8s | 18s |
| Only app code changed | 12s | 22s |
When to Choose
Choose Buildah when:
- GitLab CI/GitHub Actions (not in K8s)
- You need scripted builds (no Dockerfile)
- Multi-architecture images
- Fastest possible build times
- Red Hat / Podman ecosystem
Choose Kaniko when:
- Building inside Kubernetes (Tekton, Argo Workflows)
- Zero privilege escalation requirement
- Remote build contexts (Git, S3)
- Shared CI clusters where Docker socket is unavailable
- Google Cloud Build or GKE environments
Use Both:
- Kaniko for production CI in Kubernetes
- Buildah for local development and testing