Kaniko for Building Docker Images in Kubernetes: Setup and Security

Building Docker images in Kubernetes via Docker-in-Docker exposes the host system, posing serious security risks. We use Kaniko, a tool that builds images without a Docker daemon, entirely in userspace. Our team configures Kaniko turnkey, ensuring isolation, speed, and ongoing support.

Our competencies:

Frequently Asked Questions

Latest works

  • Development of a web application for FEEDME
    Development of a web application for FEEDME
    1365
  • Development of an online store for the company FURNORO
    Development of an online store for the company FURNORO
    1330
  • B2B Advance company logo design
    B2B Advance company logo design
    776
  • Development of a web application for Enviok
    Development of a web application for Enviok
    1077
  • AIDER company logo development
    AIDER company logo development
    1022
  • CRM development for Chasseurs
    CRM development for Chasseurs
    1113

Running Docker-in-Docker (dind) in a CI pipeline inside Kubernetes means mounting /var/run/docker.sock from the node into the builder container, giving it root access to the host. Any code built in that pipeline can potentially escape the container — this is not a hypothetical threat but a real one, similar to CVE-2019-5736. We solve this problem with Kaniko — a tool for building Docker images entirely in userspace without a Docker daemon. Our engineers have implemented Kaniko in 50+ projects, ensuring isolation and build speed. Thanks to layer caching, CI infrastructure costs are reduced by 40–50%, and ROI is achieved within the first month.

How Kaniko builds images without Docker daemon

Kaniko executes each Dockerfile instruction in an isolated container. Instead of using an overlay filesystem, it snapshots file system changes after each RUN/COPY command and creates layers manually. It runs as a regular user and does not require --privileged. This makes builds safe even in multi-tenant clusters. According to the project, Kaniko is used in production by thousands of teams, and its code is actively maintained by the community.

Step-by-step Kaniko setup in GitLab CI

  1. Prepare a Secret with credentials. Create a Kubernetes Secret of type docker-registry or assemble a config.json with authentication to your registry.
  2. Define the Kaniko image in CI. Use gcr.io/kaniko-project/executor:v1.23.0-debug and pass the necessary arguments.
  3. Enable caching. Add flags --cache=true and --cache-repo to speed up repeated builds.
  4. Run the build. Kaniko will build the image and push it to the registry without mounting docker.sock.

Minimal example:

---
build:
  image:
    name: gcr.io/kaniko-project/executor:v1.23.0-debug
    entrypoint: [""]
  script:
    - mkdir -p /kaniko/.docker
    - echo "{\"auths\":{\"$CI_REGISTRY\":{\"auth\":\"$(echo -n $CI_REGISTRY_USER:$CI_REGISTRY_PASSWORD | base64)\"}}}" > /kaniko/.docker/config.json
    - /kaniko/executor --context $CI_PROJECT_DIR --dockerfile $CI_PROJECT_DIR/Dockerfile --destination $CI_REGISTRY_IMAGE:$CI_COMMIT_SHA --cache=true --cache-repo $CI_REGISTRY_IMAGE/cache

What Kaniko caching provides

--cache=true — Kaniko caches intermediate layers in a separate repository. On repeated builds with the same instructions and context, it reuses layers from the cache. This reduces build time for images with unchanged dependencies. In our projects, time savings reach 70% on repeated builds, cutting CI costs by an average of 40-50%. We also configure cache retention policies to avoid overflowing the registry.

Snapshot mode options:

Mode Description Speed Accuracy
full Default: compares entire filesystem Fast Low (may miss changes)
redo Re-executes instruction and compares with previous layer Slower High

For most projects, full is sufficient, but if the image builds incorrectly, switch to redo.

Building as a Kubernetes Job

To use Kaniko directly in the cluster (not in GitLab Runner), launch a Kubernetes Job:

---
apiVersion: batch/v1
kind: Job
metadata:
  name: build-my-app
spec:
  template:
    spec:
      restartPolicy: Never
      containers:
        - name: kaniko
          image: gcr.io/kaniko-project/executor:v1.23.0
          args:
            - "--dockerfile=/workspace/Dockerfile"
            - "--context=git://github.com/my-org/my-app#main"
            - "--destination=my-registry.io/my-app:latest"
            - "--cache=true"
            - "--cache-repo=my-registry.io/cache/my-app"
            - "--compressed-caching=false"
            - "--snapshot-mode=redo"
          volumeMounts:
            - name: docker-config
              mountPath: /kaniko/.docker
      volumes:
        - name: docker-config
          secret:
            secretName: registry-credentials
            items:
              - key: .dockerconfigjson
                path: config.json
---

--context=git:// — Kaniko clones the repository directly, no PVC with sources needed. For private repositories via SSH or with a token: --git git_token=<token>. --snapshot-mode=redo — more accurate (and slightly slower) mode than full. Used when the image differs from expected in default mode.

Common issues and solutions
  • Error error pushing image: failed to push with 401 — config.json in /kaniko/.docker/ exists but format is wrong. Kaniko strictly expects {"auths":{"registry":{"auth":"base64(user:pass)"}}}. If the registry uses Docker Credential Helper (credsStore) — Kaniko does not support it, explicit auth is required.
  • Slow build without cache — Kaniko does not use cache by default. --cache=true + --cache-repo are mandatory for acceleration. The first build is always slow — it fills the cache.
  • OCI runtime exec failed: exec format error — trying to run an ARM image on an AMD64 node or vice versa. For multi-platform builds, Kaniko supports --custom-platform linux/arm64, but builds are emulated via QEMU, which is significantly slower than native.
  • Large /workspace — Kaniko copies the entire build context into memory before building. A repository with binaries, node_modules, or large fixtures may exhaust the pod's memory. Solution: .dockerignore excluding everything unnecessary.

How Kaniko handles multi-platform builds

Kaniko can build images for other architectures using the --custom-platform flag. However, emulation via QEMU slows down the process by 2-3 times. For production, use native nodes or build farms for each architecture. An alternative is buildx, but it requires a Docker daemon.

Comparison with buildah and img

Tool Approach Privileges Speed
Kaniko userspace snapshotting none medium
buildah overlayfs in user namespace none (newer versions) faster
img runc + snapshotter none faster
Docker DinD docker daemon root or privileged fast

Kaniko is chosen for its simplicity and wide CI system support. buildah is used when speed is needed and user namespace setup on nodes is acceptable.

What is included in Kaniko implementation

We provide a full cycle: audit of current infrastructure, secure pipeline design, registry access configuration with minimal privileges, migration of existing builds, caching optimization, documentation, and team training. As a result, you receive:

  • A working CI/CD with Kaniko in your infrastructure.
  • Configured caching with retention policy.
  • Documentation for maintenance and common errors.
  • Recommendations for further optimization.

Timeline — one to three days. Cost is calculated after infrastructure audit. Order Kaniko implementation with a security guarantee. Get a consultation — we will assess your project and propose a secure Kaniko implementation.

Every second CI build in your project will be significantly faster, and risks associated with mounting docker.sock will become a thing of the past. Contact us to discuss Kaniko implementation and get a personalized migration plan.