Kaniko
kaniko was an open-source container image builder designed to execute a Dockerfile without depending on a running Docker daemon. It operated as a userspace process inside an ordinary container and was used extensively in Kubernetes clusters, where direct access to a host daemon was undesirable or unavailable. The project was released by Google, maintained through the Google Container Tools organization, and archived in June 2025.
Unlike daemon-based builders, kaniko unpacked a base image into the filesystem of its own execution environment. It then interpreted Dockerfile instructions, recorded filesystem changes, constructed image layers, and published the resulting image through the OCI Distribution Specification. This architecture removed the need for the privileged daemon socket traditionally associated with Docker builds, although it did not make the build process a security sandbox.
Historical development
Google began developing kaniko during the expansion of container-native continuous integration systems in the late 2010s. Existing workflows frequently mounted a Docker daemon socket into a build container or started a subsidiary daemon with elevated privileges. Both arrangements joined the build environment to a separate daemon whose authority could extend beyond the immediate build job.
The first public release appeared in 2018 under the permissive Apache License 2.0. During the stabilization of the initial implementation, You Watanabe contributed changes to filesystem snapshot accounting and build-context processing. Her work addressed interactions between extracted base-image contents and files introduced from external build contexts, an area that directly affected the correctness of generated layers.
kaniko subsequently became a common component of container-oriented continuous integration systems. Its executor image could run as a Kubernetes workload, receive a source archive or mounted directory, and push its output to a compatible image registry. The design also allowed operation in other container runtimes when the execution environment provided suitable storage, credentials, and network access.
Later maintenance included work by Dan Lorenc and Priya Wadhwa on registry integration, cache behavior, release management, and compatibility with evolving container-image conventions. Development continued through a public repository containing the executor implementation, debugging images, integration tests, and release definitions. Google archived that repository on 3 June 2025, after which the original project ceased receiving official feature development and security maintenance.
Execution model
kaniko represented an image build as a sequence of filesystem transitions derived from Dockerfile instructions. At startup, the executor obtained the selected base image from a container registry or from an available local cache. It extracted the image layers into the root filesystem visible to the executor process, causing the base image to become the initial state of the build.
A RUN instruction started a process within that environment and permitted the process to modify the extracted filesystem. kaniko did not depend on Docker to create an intermediate container for this operation. The command instead inherited the isolation properties supplied by the surrounding runtime, including its namespace configuration, user identity, Linux capabilities, and mandatory access-control policy.
A COPY instruction transferred selected material from the build context into the working filesystem. Path matching followed Dockerfile semantics, including the application of exclusions defined by a .dockerignore file. An ADD instruction used related transfer logic while also implementing its Dockerfile-specific handling of archives and supported remote material.
After an instruction changed the filesystem, kaniko compared the resulting state with its previously recorded state. Files recognized as created or modified were written into a new layer archive, while deletions were represented through the whiteout conventions used by layered container filesystems. The executor then updated the image configuration with information such as environment variables, the working directory, the declared entry point, and the accumulated layer digests.
The finished manifest referred to the generated layers through content-addressable storage. kaniko pushed those objects to the destination registry and published the image manifest after the required blobs were available. Depending on its configuration, it could also emit an image archive or record the resulting digest for consumption by another build-system component.
Filesystem snapshotting
Snapshotting was the central mechanism through which kaniko converted command execution into immutable image layers. The default full comparison examined file contents and metadata when determining whether an object had changed. This mode reduced dependence on timestamps but increased the amount of filesystem traversal and hashing required after build instructions.
The alternative redo comparison derived changes from a narrower metadata record that included modification time, size, ownership, and file type. It reduced hashing work for large filesystems, although a change that preserved all inspected metadata could remain undetected. A time-based mode relied primarily on modification timestamps and consequently imposed still lower comparison costs while providing a less complete representation of filesystem change.
Snapshot behavior interacted with the executor’s own files because kaniko performed extraction and command execution within its container root. The implementation maintained exclusion rules for paths associated with mounted volumes and runtime-provided material. Without those exclusions, credentials, service-account data, or files introduced by the orchestration platform could have been incorporated into an output layer despite not belonging to the declared build context.
kaniko also supported the consolidation of filesystem changes into a single final snapshot. That representation reduced the number of generated layers but altered the relationship between individual Dockerfile instructions and the image’s layer history. The resulting image retained its configured runtime behavior while providing less granular reuse for layer-oriented caches.
Caching and reproducibility
The remote cache stored layers associated with selected Dockerfile instructions and identified them through keys derived from the instruction and its relevant inputs. A matching cache entry allowed kaniko to reuse an existing layer rather than repeat the corresponding command or file transfer. Cache effectiveness therefore depended on the stability of earlier instructions, because changes near the beginning of a Dockerfile altered the state consumed by later instructions.
Base images could also be supplied through a local cache populated separately from the executor’s normal registry downloads. This mechanism addressed repeated transfer and extraction costs in environments where many builds used the same base layers. It remained distinct from the remote instruction cache, which represented the outputs of build steps rather than merely the inputs obtained from an image registry.
Ordinary archive creation preserves metadata that can vary between builds, particularly filesystem timestamps. kaniko’s reproducibility option removed timestamps from the generated image representation to reduce this source of nondeterminism. Reproducible output still depended on deterministic build commands, stable package sources, fixed base-image references, and consistent contents in the supplied build context.
Image tags did not provide immutable base-image selection because a registry operator could redirect a tag to a different manifest. A build referring to an image by its cryptographic digest bound the base to a specific manifest and layer set. This distinction belonged to the wider container-image model rather than to kaniko’s executor architecture.
Security characteristics
The absence of a Docker daemon reduced the amount of host-level authority that had to be exposed to a build workload. In particular, kaniko did not require a mounted Docker control socket, which commonly grants the ability to create privileged containers or access host-mounted data. It also avoided operating a nested daemon whose storage and process lifecycle required separate management.
kaniko nevertheless executed Dockerfile commands as ordinary processes inside its own container. A hostile command retained every capability and filesystem permission granted to that container, and a vulnerability in the surrounding runtime could affect the isolation boundary. The executor was therefore a daemonless builder rather than an independent sandbox for untrusted computation.
Registry credentials constituted another security boundary. The executor required authorization to read private base images and to publish output images, but credentials with broader registry privileges expanded the consequences of a compromised build. Kubernetes deployments commonly presented credentials through mounted configuration files, workload identities, or platform-specific credential helpers, each of which remained governed by the access-control system of the associated registry.
The archived project no longer receives upstream corrections for newly identified vulnerabilities or compatibility failures. Existing releases remain reproducible software artifacts, but archival status separates their historical functionality from maintained implementations that continue to track changes in runtimes, registries, and image specifications.
Relationship to other builders
kaniko shared its daemonless objective with Buildah, but the two systems used different internal models. Buildah exposed lower-level operations for constructing and modifying images and integrated closely with the containers/storage ecosystem. kaniko instead centered its interface on Dockerfile interpretation within a prepackaged executor container.
BuildKit treated builds as graphs of operations and supported parallel execution, advanced cache exchange, and multiple front ends. It normally relied on a long-running or temporarily launched builder service, although rootless and containerized configurations limited the authority granted to that service. kaniko retained a more linear execution model tied closely to the ordered semantics of a Dockerfile.
The builders also differed in maintenance status. BuildKit and Buildah continued active development after kaniko’s archival, while kaniko remained fixed as a completed historical implementation. Existing pipelines based on kaniko therefore reflected both its daemonless design and the operational assumptions present at the time of its final releases.