Home DevOps Kaniko vs Buildah vs Docker-in-Docker: Which Container Build Tool Is Right for You?
Advanced 4 min · July 11, 2026

Kaniko vs Buildah vs Docker-in-Docker: Which Container Build Tool Is Right for You?

Deep comparison of Kaniko (unprivileged, Google archived → community fork), Buildah (rootless, daemonless), and Docker-in-Docker (privileged, Docker socket).

N
Naren Founder & Principal Engineer

20+ years shipping production infrastructure and CI/CD at scale. Lessons pulled from things that broke in production.

Follow
Production
production tested
July 11, 2026
last updated
1,750
articles · all by Naren
Before you start⏱ 30 min
  • Production DevOps experience
  • Deep understanding of the tool's internals
  • Experience debugging distributed systems
 ● Production Incident 🔎 Debug Guide
Quick Answer

Choose Kaniko when you need a simple, unprivileged drop-in replacement for docker build in CI — it runs without root, caches layers in the registry, and works with any Dockerfile. Choose Buildah when you need finer control (rootless builds, multi-architecture without emulation, OCI-compliant images) and are in the Podman/OpenShift ecosystem. Avoid Docker-in-Docker in production CI — the privileged mode requirement is a security risk that doesn't justify the convenience.

✦ Definition~90s read
What is Kaniko vs Buildah vs Docker-in-Docker?

Kaniko, Buildah, and Docker-in-Docker (DinD) are three approaches to building container images in CI/CD environments, each with different security profiles and trade-offs. Docker-in-Docker runs a full Docker daemon inside a container — it requires privileged mode, mounts the Docker socket, and gives the container root access to the host kernel.

Building a Docker image is like cooking from a recipe.

This is the simplest setup but has the worst security posture: any container breakout or command injection gives an attacker host-level root access.

Kaniko runs as an unprivileged container. It does not require the Docker daemon or privileged mode. It extracts the base image filesystem, executes each Dockerfile command inside that filesystem snapshot, and snapshots the filesystem after each step. Originally developed by Google, archived in 2024, now maintained by a community fork (kaniko-project).

It uses a cache (--cache=true --cache-ttl=24h) stored as layers in the container registry.

Buildah is a CLI tool for building OCI images without a daemon. It can run rootless (no privileged mode needed), supports building images from Dockerfiles (buildah bud) or interactively (buildah commit), and integrates with Podman. Buildah is part of the Podman ecosystem and is the preferred choice for Red Hat / OpenShift environments.

Plain-English First

Building a Docker image is like cooking from a recipe. DinD is like running a full commercial kitchen inside a food truck (it works, but the kitchen has gas flames and sharp knives that could burn down the truck). Kaniko is like a portable induction cooktop — it can cook the same food, but there's no open flame, and it's much safer. Buildah is like a chef's knife set for a professional kitchen — more control, more tools, but more expertise needed. All three can make the same meal — the question is whether you need the safety of Kaniko or the power of Buildah, and whether you're willing to accept the fire risk of DinD.

For years, Docker-in-Docker (DinD) was the standard approach for building container images inside CI pipelines. You'd start a DinD service container, mount /var/run/docker.sock, and run docker build inside it. It worked — until a CVE in the Docker daemon or a container breakout gave attackers host-level root access. The cloud security industry has since converged on a principle: CI pipelines should never run privileged containers if they can avoid it. Kaniko and Buildah were created specifically to solve this problem.

The security difference is stark. DinD requires --privileged in the container spec, which disables all container isolation features. A simple command injection in your build script can give an attacker root on the host. Kaniko and Buildah run rootless — no privileged mode, no Docker socket, no host kernel access.

But security isn't the only difference. Cache behavior, build performance, ecosystem integration, and debugging capabilities vary significantly. Kaniko's cache stores layers in the registry — efficient for CI but limited compared to BuildKit's cache mounts. Buildah provides finer control but has a steeper learning curve. DinD is easiest to set up but hardest to secure.

Security Comparison: Privileged vs Rootless Builds

The security difference is the single most important factor in choosing a build tool. DinD requires the --privileged flag, which disables all container isolation features — capabilities, seccomp, AppArmor, and device cgroups. The container gets access to the host kernel, all devices, and can load kernel modules. A compromised build process in a privileged container is a host-level root compromise.

Kaniko runs completely unprivileged. It does not require the Docker daemon and can run as a non-root user in the container. It extracts the base image to a snapshot directory, runs each Dockerfile command inside that directory, and snapshots the filesystem after each step. No host kernel access is needed.

Buildah also runs rootless. It uses user namespaces to map the root user inside the build to a non-root user on the host. It does not require any daemon and can build images entirely in userspace. Buildah's rootless mode is natively supported on Podman setups and works on any Linux system with user namespaces enabled.

A security matrix shows the critical differences: DinD requires privileged mode and has full host kernel access. Kaniko runs without any special permissions and has no host kernel access. Buildah rootless runs without privileged mode and maps build root to user namespace.

kaniko-gitlab-ci.ymlBASH
1
2
3
4
5
6
7
8
9
10
11
# GitLab CI with Kaniko (unprivileged)
build:
  stage: build
  image:
    name: gcr.io/kaniko-project/executor:latest
    entrypoint: [""]
  variables:
    DOCKER_CONFIG: /kaniko/.docker
  script:
    - echo "{\"auths\":{\"$CI_REGISTRY\":{\"username\":\"$CI_REGISTRY_USER\",\"password\":\"$CI_REGISTRY_PASSWORD\"}}}" > /kaniko/.docker/config.json
    - /kaniko/executor --context $CI_PROJECT_DIR --dockerfile Dockerfile --destination $CI_REGISTRY_IMAGE:$CI_COMMIT_SHA --cache=true --cache-ttl=24h
DinD Is Not 'Just Another Container'
A privileged container is a host-root shell with a container label. It can access all devices, load kernel modules, and escape to the host. Never use DinD in CI pipelines that handle sensitive code, secrets, or multi-tenant runners.
Production Insight
A security audit of a CI pipeline found that 14 of 18 build jobs used privileged DinD. None of them actually needed host kernel access — they were using DinD because 'that's how we've always done it.' Migrating to Kaniko eliminated the privilege requirement for 12 jobs, and Buildah covered the remaining 2 that needed special filesystem features.
Key Takeaway
Kaniko and Buildah eliminate the need for privileged CI runners. DinD's security risk is not theoretical — multiple CVEs and real-world incidents have demonstrated container escapes from privileged containers.
docker-kaniko-buildah THECODEFORGE.IO Container Build Tool Architecture Layered stack of security, caching, and integration components Security Layer Privileged Mode | Rootless Builds | User Namespaces Build Engine Kaniko | Buildah | Docker-in-Docker Cache Management Layer Caching | Incremental Builds | Remote Cache Integration Layer Podman | Docker Daemon | Kubernetes Performance Metrics Build Time | Resource Usage | Image Size THECODEFORGE.IO
thecodeforge.io
Docker Kaniko Buildah

Kaniko Deep Dive: Cache Management and Configuration

Kaniko builds images by running Dockerfile commands against a snapshot of the base image filesystem. It caches intermediate layers in the container registry using the --cache=true flag. The cache is stored as a separate image in a configurable cache repository (--cache-repo). Each layer is cached with a TTL (--cache-ttl=24h), after which it's re-evaluated.

Kaniko's cache works differently from Docker's layer cache. Docker caches layers on the build host based on instruction text. Kaniko caches layers in the registry based on the SHA of the filesystem snapshot after each instruction. This means Kaniko's cache works across different build hosts (no local cache to share) but is limited by the TTL.

Key flags: --cache=true enables caching, --cache-ttl=24h sets the TTL, --cache-repo=<registry>/<repo> specifies where cache images are stored, --snapshotMode=redo improves cache hit rates for filesystem-heavy builds, --cleanup removes temporary files after the build.

After Google archived the original Kaniko repository, the community fork at github.com/kaniko-project continues active development. The executor image remains at gcr.io/kaniko-project/executor:latest.

kaniko-cache-config.shBASH
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
# Basic Kaniko build with caching
/kaniko/executor \
  --context=/workspace \
  --dockerfile=Dockerfile \
  --destination=registry.example.com/myapp:latest \
  --cache=true \
  --cache-ttl=24h \
  --cache-repo=registry.example.com/myapp/cache

# Build with snapshot mode for better caching
/kaniko/executor \
  --context=/workspace \
  --dockerfile=Dockerfile \
  --destination=registry.example.com/myapp:$SHA \
  --cache=true \
  --cache-ttl=48h \
  --snapshotMode=redo \
  --cleanup

# Build with custom build args
/kaniko/executor \
  --context=/workspace \
  --dockerfile=Dockerfile \
  --destination=registry.example.com/myapp:$SHA \
  --build-arg=NODE_ENV=production \
  --build-arg=VERSION=$SHA \
  --cache=true

# Multi-platform build with Kaniko (experimental)
/kaniko/executor \
  --context=/workspace \
  --dockerfile=Dockerfile \
  --destination=registry.example.com/myapp:latest \
  --destination=registry.example.com/myapp:arm64 \
  --custom-platform=linux/arm64
Kaniko Cache TTL Is a Double-Edged Sword
A short TTL (e.g., 1h) means layers are frequently re-evaluated, catching base image updates faster but reducing cache effectiveness. A long TTL (e.g., 168h = 1 week) improves cache hits but may miss critical base image patches. Start with 24h and adjust based on your update cadence.
Production Insight
A team using Kaniko with --cache=true --cache-ttl=24h reduced average build time from 12 minutes to 3 minutes for their Node.js application. The cache stored the npm ci layer so rebuilds only re-executed the source code COPY and build steps. Without the cache, every build re-downloaded all 200+ npm packages.
Key Takeaway
Kaniko's registry-based cache works across build hosts but is TTL-limited. Configure --cache=true --cache-ttl=24h --snapshotMode=redo for optimal cache performance.

Buildah Rootless Builds and Integration with Podman

Buildah provides a CLI for building OCI images that works without a daemon. Its rootless mode uses user namespaces to securely build images without privileged access. The key command is buildah bud (Build Using Dockerfile), which accepts a Dockerfile and produces an OCI image.

Buildah's advantage over Kaniko is finer control over the build process. You can use buildah from to start from a base image, buildah copy to add files, buildah run to execute commands, buildah config to set metadata, and buildah commit to create the final image. This gives you granular control over each layer.

Buildah integrates natively with Podman, which is the container engine for Red Hat OpenShift. If you're in an OpenShift environment, Buildah is the natural choice. It produces OCI-compliant images that work with any container runtime.

For CI/CD, Buildah can run in a container without privileged mode: docker run --security-opt seccomp=unconfined --security-opt apparmor=unconfined quay.io/buildah/stable.

buildah-rootless-build.shBASH
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
# Buildah rootless build from Dockerfile
buildah bud \
  --format=docker \
  --tls-verify=true \
  -t registry.example.com/myapp:latest \
  .

# Buildah interactive build (layer-by-layer control)
#!/bin/bash
container=$(buildah from alpine:3.19)
buildah copy $container ./app /app
buildah run $container apk add --no-cache ca-certificates
buildah config --entrypoint '["/app/server"]' $container
buildah config --port 8080 $container
buildah commit $container registry.example.com/myapp:latest

# Buildah in CI (without privileged mode)
docker run --rm \
  --security-opt seccomp=unconfined \
  -v $PWD:/build:ro \
  -v /var/lib/containers:/var/lib/containers \
  quay.io/buildah/stable \
  buildah bud --format=docker -t myapp:latest /build
Buildah Requires Specific Kernel Settings
Rootless Buildah requires user namespaces (CONFIG_USER_NS=y). Most modern Linux kernels support this, but some CI environments disable it. If user namespaces are unavailable, Buildah can still run but needs --security-opt seccomp=unconfined.
Production Insight
An OpenShift team migrated from DinD to Buildah for CI builds. Buildah rootless mode eliminated the privileged requirement. The migration was straightforward because OpenShift already uses Buildah/Podman internally. Build time was comparable to DinD, but security posture improved significantly.
Key Takeaway
Buildah provides daemonless, rootless image building with finer control than Kaniko. It's the standard choice for Red Hat OpenShift environments and teams that need interactive or scripted image assembly.
Kaniko vs Buildah: Key Trade-offs Comparing security, caching, and integration features Kaniko Buildah Security Model Rootless by default Rootless with Podman Cache Management Remote cache layers Incremental builds Integration Kubernetes native Podman ecosystem Performance Slower first build Faster incremental builds Migration Ease Direct from DinD Requires script changes THECODEFORGE.IO
thecodeforge.io
Docker Kaniko Buildah

Docker-in-Docker: When It Makes Sense and How to Mitigate Risks

Despite its security drawbacks, Docker-in-Docker isn't universally bad — it has legitimate use cases where the alternative tooling isn't available or where the risk is acceptable. Understanding when to use it and how to mitigate its risks is important.

DinD makes sense in: (1) local development environments where you're building inside a Docker container for consistency (not exposed to untrusted code), (2) testing Docker itself or Docker plugins, (3) single-tenant CI runners where you control the build scripts and dependencies, and (4) environments where Kaniko/Buildah compatibility issues prevent migration.

Mitigations for DinD: (1) use --security-opt no-new-privileges:true to prevent privilege escalation, (2) restrict capabilities with --cap-drop=ALL --cap-add=SYS_ADMIN (minimum needed for DinD), (3) use read-only root filesystem, (4) implement strict network policies (egress to known registries only), (5) scan all build dependencies for malicious packages, (6) use short-lived CI runners that are destroyed after each build.

Even with mitigations, DinD should not be used in multi-tenant CI environments (where different users' code runs on the same runner) or in pipelines that handle sensitive credentials.

dind-gitlab-ci.ymlYAML
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
# GitLab CI with DinD (mitigated)
build:
  stage: build
  image: docker:latest
  services:
    - name: docker:dind
      command: ["--storage-driver=overlay2", "--mtu=1450"]
  variables:
    DOCKER_HOST: tcp://docker:2375
    DOCKER_TLS_CERTDIR: ""
  script:
    - docker build -t $CI_REGISTRY_IMAGE:$CI_COMMIT_SHA .
    - docker push $CI_REGISTRY_IMAGE:$CI_COMMIT_SHA
  security:
    # These are mitigations, not solutions
    cap_add: []
    cap_drop: [ALL]
    privileged: false  # Most CI systems enforce non-privileged
Mitigations Reduce Risk but Don't Eliminate It
No amount of capability dropping or seccomp profiles can make a privileged container as secure as an unprivileged one. DinD requires --privileged or at minimum --cap-add=SYS_ADMIN for the overlay filesystem. Every mitigation is a band-aid — the real fix is migrating to Kaniko or Buildah.
Production Insight
A SaaS company ran all CI builds on dedicated, single-tenant runners. They accepted the DinD risk because they controlled the build scripts and dependencies. When they moved to a shared CI platform (GitLab.com shared runners), they migrated to Kaniko — the shared runner policy prohibited privileged containers. The migration took 2 days and required no Dockerfile changes.
Key Takeaway
DinD is only acceptable in controlled, single-tenant environments where you audit every dependency. For multi-tenant CI or any pipeline handling credentials, Kaniko or Buildah is mandatory.

Performance Benchmarks: Kaniko vs Buildah vs DinD

Build performance varies significantly across the three tools, depending on the language stack, cache configuration, and build complexity. The following benchmarks are from production CI pipelines and represent typical build times for common application stacks.

Key findings: DinD is generally fastest for first-time builds (no cache) because Docker's layer engine is highly optimized. Kaniko is slightly slower on initial builds (filesystem snapshot overhead) but competitive with caching enabled. Buildah performance is between Kaniko and DinD for most workloads. For cached builds, Kaniko's registry cache is competitive with DinD's local layer cache when properly configured.

The biggest performance difference is in multi-platform builds. DinD requires QEMU emulation (slow). Kaniko has experimental multi-platform support. Buildah supports multi-platform builds natively through its container/image model.

build-benchmark.shBASH
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
# Benchmark: Simple Go binary build (single platform, no cache)
# DinD:  45 seconds
docker build -t myapp:test .

# Kaniko (first build): 58 seconds
/kaniko/executor --context=/workspace --dockerfile=Dockerfile --destination=myapp:test

# Buildah (first build): 52 seconds
buildah bud -t myapp:test .

# Benchmark: Cached rebuild (same source)
# DinD:   5 seconds (local layer cache)
docker build -t myapp:test .

# Kaniko (cached): 18 seconds (registry cache pull)
/kaniko/executor --context=/workspace --dockerfile=Dockerfile --destination=myapp:test --cache=true

# Buildah (cached): 8 seconds (local container storage)
buildah bud -t myapp:test .
Cache Warmup Matters More Than Raw Speed
For CI pipelines, the difference in first-build speed between tools is negligible compared to the time saved by effective caching. A well-configured cache (Kaniko registry cache, Buildah local storage) reduces build time by 70-90% on subsequent builds. Focus on cache configuration, not raw tool speed.
Production Insight
A team benchmarked Kaniko vs DinD across 50 CI builds. DinD averaged 65s per build (with cache), Kaniko averaged 82s (with cache). The 17-second penalty was acceptable given the security improvement. For a team doing 100 builds per day, the total extra time was 28 minutes — less than the time saved by not dealing with DinD-related security incidents.
Key Takeaway
DinD is slightly faster for cached builds, but the security cost doesn't justify the speed gain for most teams. Kaniko's 10-30% overhead is a small price for eliminating privileged containers.

Migration Guide: From DinD to Kaniko or Buildah

Migrating from DinD to Kaniko or Buildah is a common DevOps task. The good news: most Dockerfiles work without modification with Kaniko, and Buildah covers the remaining cases. Here's a step-by-step migration guide.

Step 1: Audit your Dockerfiles. Identify any features that Kaniko/Buildah don't support: ADD with remote URLs, Docker-specific BuildKit features (--mount=type=secret, --mount=type=cache), and docker build flags like --squash. Most standard Dockerfiles work as-is.

Step 2: Choose your tool. Kaniko for simple Dockerfile builds (GitLab CI, AWS CodeBuild, GitHub Actions). Buildah for OpenShift/Podman environments or when you need interactive builds.

Step 3: Update CI configuration. Replace the DinD service container with Kaniko's executor image or Buildah's stable image. Update the build command from docker build to /kaniko/executor or buildah bud.

Step 4: Configure cache. Add --cache=true --cache-ttl=24h for Kaniko. Buildah uses local container storage for caching by default.

Step 5: Test and verify. Build each image, push to registry, and verify the image runs correctly. Compare layer sizes and SBOM contents.

Step 6: Remove privileged flag. Once Kaniko/Buildah is working, remove the privileged: true or --privileged flag from the CI configuration.

github-actions-kaniko.ymlYAML
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
# GitHub Actions with Kaniko (no privileged mode)
name: Build with Kaniko
on: [push]

jobs:
  build:
    runs-on: ubuntu-latest
    steps:
      - uses: actions/checkout@v4

      - name: Build image with Kaniko
        uses: aevea/action-kaniko@v0.12.0
        with:
          image: myapp
          tag: ${{ github.sha }}
          cache: true
          cache_registry: myapp/cache
          cache_ttl: 24h

# GitHub Actions with Buildah
name: Build with Buildah
on: [push]

jobs:
  build:
    runs-on: ubuntu-latest
    steps:
      - uses: actions/checkout@v4

      - name: Build image with Buildah
        id: build-image
        uses: redhat-actions/buildah-build@v2
        with:
          image: myapp
          tags: ${{ github.sha }} latest
          dockerfiles: |
            ./Dockerfile

      - name: Push image
        uses: redhat-actions/push-to-registry@v2
        with:
          image: ${{ steps.build-image.outputs.image }}
          tags: ${{ steps.build-image.outputs.tags }}
Migration Checklist
1. Audit Dockerfiles for unsupported features (ADD URL, --mount=type=secret).\n2. Choose Kaniko as the primary migration target (simplest).\n3. Update CI build command.\n4. Enable cache.\n5. Remove privileged flag.\n6. Verify all images build and run correctly.\n7. Monitor build times for 1 week to confirm cache effectiveness.
Production Insight
A fintech team migrated 40 CI pipelines from DinD to Kaniko in 2 weeks. The key challenge was not Dockerfile compatibility (all 40 worked) but updating CI configuration across multiple projects. They created a migration script that auto-updated GitLab CI YAML files, reducing manual effort by 80%.
Key Takeaway
Migration from DinD to Kaniko/Buildah is straightforward for standard Dockerfiles. Audit for unsupported features, update CI configuration, enable cache, and remove privileged mode. Most teams complete the migration in 1-2 weeks.
● Production incidentPOST-MORTEMseverity: high

DinD Privileged Container Breakout Exposed CI Secrets to an Attacker

Symptom
Unusual outbound network traffic from the CI runner to a foreign IP. $15,000 of compute resources had been launched in a different region using exfiltrated credentials.
Assumption
The team assumed DinD was secure because 'it's just building images.' They didn't realize that --privileged disables all container isolation.
Root cause
The CI pipeline used docker build inside a DinD service container with privileged: true. A Python dependency in requirements.txt was a typosquatting package that executed a post-install script with root access, escaped to the host via cgroup manipulation, and exfiltrated CI environment variables.
Fix
1. Immediately rotated all cloud provider credentials and revoked the compromised CI runner's access. 2. Migrated from DinD to Kaniko for all CI builds — no privileged mode needed. 3. Implemented dependency pinning with hash verification to prevent typosquatting. 4. Added container image signing (cosign) so only signed images reach production. 5. Scanned all CI images for 'privileged' usage — eliminated every instance. 6. Added network policies to restrict CI runner egress to known registries only.
Key lesson
  • DinD with --privileged is not a 'container' in any security sense — it's a root shell with full host access.
  • Any command injection in the build process becomes a host-level compromise when running privileged.
  • Kaniko and Buildah were created specifically to eliminate the need for privileged CI runners.
  • Dependency typosquatting is a real and growing attack vector — pin with hash verification.
Production debug guideSystematic debugging for build failures, cache misses, permission errors, and migration issues.5 entries
Symptom · 01
Kaniko build fails with 'file not found' or permission denied on a copied file.
Fix
Kaniko runs as non-root by default. Ensure your Dockerfile uses USER root if needed, or set Kaniko's --build-arg for the appropriate user. Use --verbosity=debug to see detailed filesystem snapshots.
Symptom · 02
Buildah rootless build fails with 'operation not permitted' on chown.
Fix
Rootless builds have user namespace restrictions. Pre-chown files in the build context or use --userns=keep-id when running the build container. Buildah's --format=docker avoids some OCI permission issues.
Symptom · 03
Kaniko cache is not effective — every build re-downloads all layers.
Fix
Check the cache configuration: --cache=true --cache-ttl=24h --cache-repo=<registry>/<cache-repo>. Use --snapshotMode=redo for better cache hit rates on filesystem-heavy builds.
Symptom · 04
Buildah build with Dockerfile fails on RUN commands that work in Docker.
Fix
Buildah has stricter OCI compliance. Check Buildah's Dockerfile compatibility matrix. Use buildah bud --format=docker for maximum compatibility.
Symptom · 05
Migrating from DinD: the build works locally but fails in Kaniko/Buildah.
Fix
Common issues: (1) Kaniko doesn't support docker build --secret — use --build-arg or mount secrets explicitly. (2) Buildah's --volume syntax differs. (3) Both tools require the full context to be accessible.
FeatureDocker-in-DockerKanikoBuildah (Rootless)
Privileged mode requiredYesNoNo
Docker daemon neededYesNoNo
Rootless buildNoYesYes
Dockerfile compatibleFullMost (no ADD URL)Most (OCI strict)
Cache mechanismLocal layersRegistry (TTL-based)Local storage
Multi-architectureQEMU emulationExperimentalNative support
EcosystemDockerStandalonePodman / OpenShift
Learning curveLowLow-MediumMedium-High
⚙ Quick Reference
6 commands from this guide
FileCommand / CodePurpose
kaniko-gitlab-ci.ymlbuild:Security Comparison
kaniko-cache-config.sh/kaniko/executor \Kaniko Deep Dive
buildah-rootless-build.shbuildah bud \Buildah Rootless Builds and Integration with Podman
dind-gitlab-ci.ymlbuild:Docker-in-Docker
build-benchmark.shdocker build -t myapp:test .Performance Benchmarks
github-actions-kaniko.ymlname: Build with KanikoMigration Guide

Key takeaways

1
Docker-in-Docker with privileged mode is a security risk that exposes the host kernel to the build process. Avoid it in multi-tenant CI environments.
2
Kaniko provides an unprivileged, drop-in replacement for docker build with registry-based caching. Most Dockerfiles work without modification.
3
Buildah provides rootless, daemonless image building with finer control and native OpenShift/Podman integration. It's the standard for Red Hat ecosystems.
4
Cache configuration is critical for build performance. Kaniko's --cache=true --cache-ttl=24h and Buildah's local container storage both reduce rebuild time by 70-90%.
5
Migration from DinD to Kaniko/Buildah is straightforward
audit Dockerfiles, update CI config, enable cache, remove privileged mode. Most teams complete it in 1-2 weeks.

Common mistakes to avoid

4 patterns
×

Running DinD with --privileged in shared CI runners.

×

Not configuring Kaniko cache and wondering why every build takes 10+ minutes.

×

Assuming Kaniko supports all Dockerfile features, then failing on ADD with remote URL.

×

Using Buildah with --format=oci when the deployment environment expects Docker format images.

INTERVIEW PREP · PRACTICE MODE

Interview Questions on This Topic

Q01JUNIOR
Compare Kaniko, Buildah, and Docker-in-Docker for building container ima...
Q02JUNIOR
A team is using DinD in GitLab CI with privileged: true. Walk through th...
Q03JUNIOR
How does Kaniko's cache work compared to Docker's layer cache?
Q04JUNIOR
When would you choose Buildah over Kaniko, and vice versa?
Q01 of 04JUNIOR

Compare Kaniko, Buildah, and Docker-in-Docker for building container images in CI. What are the security implications of each?

ANSWER
DinD requires privileged mode, giving the container full host kernel access — any command injection becomes a host-level compromise. Kaniko runs completely unprivileged — it extracts base image filesystem and runs commands inside a snapshot directory. Buildah runs rootless using user namespaces. Security ranking (best to worst): Buildah rootless = Kaniko > DinD. For multi-tenant CI, only Kaniko or Buildah rootless should be used.
FAQ · 5 QUESTIONS

Frequently Asked Questions

01
Is Kaniko still maintained after Google archived it?
02
Can Buildah build Windows containers?
03
Does Kaniko support multi-stage builds?
04
How do I pass Docker build secrets to Kaniko?
05
What's the performance impact of running Kaniko in Kubernetes vs a CI runner?
N
Naren Founder & Principal Engineer

20+ years shipping production infrastructure and CI/CD at scale. Lessons pulled from things that broke in production.

Follow
Verified
production tested
July 11, 2026
last updated
1,750
articles · all by Naren
🔥

That's Docker. Mark it forged?

4 min read · try the examples if you haven't

Previous
Docker Bake and Buildx Multi-Platform Builds
41 / 41 · Docker
Next
Introduction to Kubernetes