Chapter 12: The Ecosystem
Topic 72

The OCI Standard

StandardOCI

The reason a driftwood/web image you built with docker build runs unchanged under Podman, containerd, and Kubernetes — and pushes to Docker Hub, GHCR, or registry.driftwood.example without translation — is that none of those tools invented their own image format. They all implement the Open Container Initiative (OCI) specs.

"Docker images" are really OCI images. Docker donated the format to a vendor-neutral body in 2015, and that act is the foundation of the whole book's portability claim. Every time this course said "build once, run anywhere," it was leaning on a standard it had not yet named — this topic names it.

Three Specs, One Contract

OCI is not one document but three, and together they cover the full lifecycle: build, run, and ship. The image-spec defines how an image is laid out — its manifest, config, and layers. The runtime-spec defines how a runtime turns an unpacked image into a running container: the namespaces, cgroups, and mounts. The distribution-spec defines how registries serve images over HTTP. Three contracts, one artifact moving through all of them.

Three OCI specs, one artifact
image-spec
The image format: manifest, config, and content-addressed layers. Defines how an image is laid out so any tool reads the same bytes.
runtime-spec
How to run a filesystem bundle: an unpacked root filesystem plus a config.json of namespaces, cgroups, and mounts to exec.
distribution-spec
The registry API: the standardized pull and push HTTP endpoints every compliant registry serves over the wire.

The split matters because it lets different tools own different stages without colliding. A builder writes the image-spec format; a runtime reads the runtime-spec bundle; a registry speaks the distribution-spec API. Each can be a separate project from a separate vendor, and they interoperate because they agree on these three documents rather than on a single product.

Image-Spec — Why Any Tool Reads Your Image

The manifest, config, and layer format you met back in Chapter 2 is the OCI image-spec. Because Docker, Podman, and containerd agree on it byte-for-byte, the image you built is the exact artifact every other tool consumes — no conversion, no repacking, no import step. The layers are content-addressed blobs; the config records the entrypoint, working dir, and user; the manifest ties them together. Any compliant tool reads all three the same way.

Runtime-Spec — The Bundle Any Runtime Runs

The runtime-spec describes a filesystem bundle — an unpacked root filesystem plus a config.json listing the namespaces, cgroups, mounts, and the process to exec. runc, covered in the next topic, is the reference implementation, but it is just one implementation of a written contract. That is exactly why crun, gVisor, and Kata can be drop-in replacements: they all read the same bundle and honor the same config.json, so you swap the runtime without touching the image.

Distribution-Spec — Why Every Registry Speaks the Same API

The distribution-spec standardizes the pull and push HTTP API, so docker push registry.driftwood.example/driftwood/web:1.4.0 and the same push to Docker Hub or ECR hit identical endpoints. A registry is OCI-compliant or it is not, and compliance is the only thing that matters when you pick one. The product name on the registry is marketing; the distribution-spec is what decides whether your client can push a multi-arch manifest to it.

Where Docker Sits Now

Docker is one implementation of these specs, not the definition of them. The headline portability of "build once, run anywhere" is an OCI property you have been relying on since Chapter 2 without it being named. Docker Engine, BuildKit, and the Docker CLI are the spine this book taught because they are the way most people build and run containers — but the artifact they produce belongs to the standard, not to Docker.

This reframes the rest of the chapter. containerd and runc are OCI runtime implementations; Podman and Buildah are OCI build-and-run tools; Kubernetes consumes OCI images through containerd. Once you reason in terms of the three specs, every alternative tool stops being a competitor to Docker and becomes another reader of the same driftwood/web artifact.

Common Mistakes
  • Believing "Docker image" and "OCI image" name two different artifacts you might need to convert between — they are the same thing; there is no conversion step, and looking for one wastes time.
  • Assuming an image only runs where Docker is installed — any OCI-compliant runtime (containerd, CRI-O, Podman) runs it unchanged, which is precisely why Kubernetes dropped dockerd and lost nothing.
  • Picking a registry product on brand without checking OCI distribution-spec compliance, then discovering a client cannot push multi-arch manifests or OCI artifacts to it.
  • Treating the runtime-spec as Docker-internal trivia — it is the contract that lets you swap runc for gVisor or Kata under the same image, which is a real security lever covered in the next topic.
Best Practices
  • Reason about portability in OCI terms — image-spec for the artifact, runtime-spec for execution, distribution-spec for the registry — so "will this run there" has a precise answer instead of a vendor guess.
  • Choose registries and runtimes by OCI compliance, not brand, so the driftwood/web artifact stays usable across every tool the team later adopts.
  • Treat the image you build as the durable contract with downstream consumers — Kubernetes, Podman, CI — because the OCI specs guarantee they all read it identically.
  • Pin and verify by digest, knowing the digest is an OCI image-spec property every compliant tool computes the same way, so a pinned image is provable across runtimes.
Comparable tools Docker · Podman · containerd · CRI-O implementations of the OCI specs, not competing formats runc · crun reference and alternative OCI runtimes honoring the runtime-spec skopeo · oras work directly against the distribution-spec to move images and OCI artifacts

Knowledge Check

What does the Open Container Initiative actually standardize?

  • Three specs: the image layout, how a runtime runs it, and how registries serve it over HTTP
  • A single reference binary every vendor must ship and certify before calling itself compliant
  • The Linux kernel system-call API for namespaces and cgroups that every container depends on
  • The Docker CLI command set, so every tool exposes the same subcommands and flags

Why does a driftwood/web image built with docker build run unchanged under Podman and containerd?

  • They all implement the OCI image-spec, so the manifest, config, and layers are read identically with no conversion
  • Each tool silently converts the Docker format into its own incompatible internal on-disk layout the first time it pulls the image
  • Because Docker is quietly installed alongside them and translates the image on demand at runtime
  • The runtime rebuilds the image from its original Dockerfile source the first time it runs

What does the OCI runtime-spec make possible?

  • Swapping the runtime — runc, crun, gVisor, Kata — under the same image without rebuilding
  • Defining how the layers, config, and manifest are laid out on disk as content-addressed blobs
  • Standardizing the HTTP push and pull API a registry uses to serve images over the wire
  • Encrypting the container's root filesystem at rest before the process starts

How should you decide whether a registry will work with your toolchain?

  • Check OCI distribution-spec compliance — that, not the brand, determines whether your client can push and pull
  • Pick the largest vendor by market share, since their scale guarantees every artifact type and manifest version just works
  • Match the registry to whichever container runtime your nodes happen to be running in production today
  • Confirm it can convert your images into the registry's own proprietary storage format on upload

You got correct