WSS
On this page
Deployment & DeliveryRequiredUpdated

OCI image specification

The Open Container Initiative (OCI) Image Format Specification standardizes how container images are built, packed, and signed. It ensures interoperability between different container engines and registries.

Introduction

The Open Container Initiative (OCI) Image Format Specification defines a standard for packaging software into a container image. Before this standard, image formats were heavily tied to specific container engines. The OCI specification ensures that an image built with one tool can be pushed to any compliant registry and run by any compliant engine.

Mental Model

Think of an OCI image as a multi-tier wedding cake in a transparent box. The box has a label listing exactly what is inside. Each tier of the cake is baked separately and stacked on top of the last. If two people order cakes with identical bottom tiers, the bakery only needs to bake that bottom tier once and share it between the two boxes, saving resources.

Algorithms/Resolution

An OCI image is content-addressable. The registry identifies every component by a cryptographic hash (typically SHA-256) of its contents. If you change a single byte in a file, its hash changes, creating a completely new component.

When an engine pulls an image, it requests the image manifest. The manifest lists the hashes of the image layers. The engine downloads each layer independently. If the engine already possesses a layer with a matching hash from a previous pull, it skips the download. This deduplication reduces network transfer and disk usage.

Images support multi-architecture deployments via an image index. The index points to multiple manifests, each built for a specific CPU architecture (e.g., amd64, arm64). The client engine resolves the index and pulls the manifest matching its host architecture automatically.

Semantics

An OCI image comprises three main structures: the manifest, the image configuration, and the filesystem layers.

The layers are tar archives representing changes to the filesystem. A layer contains added files, modified files, and “whiteout” files that mark deletions from lower layers.

The image configuration is a JSON document. It specifies the environment variables, the default working directory, the entrypoint command, and the ordered list of layer hashes required to construct the root filesystem.

The manifest binds them together. It is a JSON document containing the hash of the image configuration and the hashes of the layer archives.

Failure Modes

Appending files creates bloat. If you download a 1GB file in one layer, and delete it in the next layer, the final container filesystem does not show the file. However, the image still includes the 1GB layer archive. Registries and clients must transfer and store the full size.

Unpinned base images introduce drift. Using FROM ubuntu:latest means the underlying operating system changes unexpectedly between builds. A build that succeeds today might fail tomorrow due to an upstream library update.

Missing architectures break deployments. If an operations team deploys an application to an ARM-based cluster, but the OCI index only contains an x86 manifest, the engine fails to start the container.

Security

Layer contents are readable by anyone with access to the image. Storing passwords, API keys, or certificates in a layer exposes them permanently, even if a subsequent layer deletes them.

Base images contain vulnerabilities. The OCI specification provides a mechanism to package software, but it makes no guarantees about the security of that software. Images require continuous scanning for known CVEs.

Signatures verify provenance. The specification supports attaching cryptographic signatures to images. Engines can enforce a policy that prevents running unsigned images or images signed by untrusted authorities.

Operational Guidance

Minimize layer size. Combine commands that add and remove temporary files into a single layer (e.g., apt-get install && rm -rf /var/lib/apt/lists/*).

Use multi-stage builds. Compile the application in one stage, and copy only the compiled binary into a minimal runtime image in the final stage. This excludes build tools and source code from the final artifact.

Pin dependencies by hash. Reference the base image by its immutable SHA-256 digest rather than a mutable tag. This guarantees the build pipeline uses the exact same base image every time.

Diagnostics

Inspect the image layers using dive or the engine’s built-in history command. This reveals which commands created which layers and identifies wasted space.

Verify the manifest structure. Tools like skopeo can download and parse the OCI manifest without pulling the entire image, useful for checking architecture support or configuration details.

Audit the image configuration. Check the JSON payload for unintended environment variables or overly permissive default entrypoints.

Related topics

Sources & further reading