🎉 DevOps Interview Prep Bundle is live — 1000+ Q&A across 20 topicsGet it →
All Articles

What is OCI? The Container Image Standard Explained Simply

Learn what OCI (Open Container Initiative) is, what it standardizes, and why it matters for DevOps engineers. Covers image format, runtime spec, distribution spec, and practical tools like skopeo.

DevOpsBoys4 min read
Share:Tweet

If you have ever wondered why a Docker image built on your laptop runs fine on Kubernetes with containerd — even though Docker and containerd are completely different projects — the answer is OCI. Understanding OCI takes about 15 minutes and saves a lot of confusion when things break.

Before OCI: The Docker Lock-in Problem

When Docker launched in 2013, the container image format was a proprietary Docker format. To run a "Docker container" you needed the Docker runtime. This was fine when Docker was the only player, but by 2015 rkt (by CoreOS), lxc, and others were trying to build container runtimes and they could not agree on a shared format.

The Linux Foundation stepped in and created the Open Container Initiative (OCI) in June 2015. Docker donated the container image format spec as the starting point.

What OCI Standardizes

OCI defines three specifications:

1. Image Format Specification — how a container image is structured (layers, manifests, config JSON). Any tool that produces an OCI image can be run by any OCI-compliant runtime.

2. Runtime Specification (runc) — how to actually run a container (filesystem setup, namespace creation, cgroups, lifecycle hooks). runc is the reference implementation and is what containerd and CRI-O call under the hood.

3. Distribution Specification — how to push and pull images from a registry (HTTP API for manifests and blobs). Any OCI-compliant registry (Docker Hub, ECR, GCR, Quay, Harbor) speaks the same protocol.

How OCI Image Layers Work

An OCI image is a stack of read-only layers plus a config file:

Image manifest (JSON)
  ├── config.json  ← env vars, entrypoint, labels
  ├── layer 1  ← base OS (sha256:abc...)
  ├── layer 2  ← app dependencies (sha256:def...)
  └── layer 3  ← your app code (sha256:ghi...)

When you run the image, the runtime (containerd/runc) downloads these layers, stacks them using an overlay filesystem (overlayfs), and adds a writable layer on top. Layers are content-addressed by SHA256 digest — this is why the same layer is never downloaded twice across different images.

Check the layers of any image:

bash
docker image inspect nginx:latest --format '{{json .RootFS.Layers}}'

Output:

json
[
  "sha256:2a1e4e1b....",
  "sha256:8e4b9e3a....",
  "sha256:0f2d0c2c...."
]

Why This Matters in Practice

Podman builds Docker-compatible images:

bash
podman build -t myapp:latest .
podman push myapp:latest docker://registry.example.com/myapp:latest

That image runs on Kubernetes with containerd — zero changes needed because they all speak OCI.

CRI-O on Kubernetes pulls from Docker Hub: Kubernetes used to require Docker as the runtime. Since Kubernetes 1.24 removed dockershim, clusters use containerd or CRI-O directly. Both are OCI-compliant runtimes, so they pull and run OCI images from any OCI registry without Docker installed.

Buildah builds images without a daemon:

bash
buildah from ubuntu:22.04
buildah run mycontainer -- apt-get install -y curl
buildah commit mycontainer myapp:latest
buildah push myapp:latest

No Docker daemon, no root required. Output is a valid OCI image.

skopeo: Copy OCI Images Between Registries

skopeo is the most useful OCI tool most engineers do not know about. It copies images between any OCI-compliant registry without pulling them locally (no docker pull + docker push needed).

Install:

bash
# Ubuntu/Debian
sudo apt install skopeo
 
# macOS
brew install skopeo

Copy from Docker Hub to ECR:

bash
aws ecr get-login-password --region ap-south-1 | \
  skopeo login --username AWS --password-stdin \
  123456789012.dkr.ecr.ap-south-1.amazonaws.com
 
skopeo copy \
  docker://nginx:1.25 \
  docker://123456789012.dkr.ecr.ap-south-1.amazonaws.com/nginx:1.25

This streams the image layers directly between registries — nothing is stored on your machine.

Inspect an image without pulling it:

bash
skopeo inspect docker://nginx:latest

Output:

json
{
  "Name": "docker.io/library/nginx",
  "Digest": "sha256:...",
  "RepoTags": ["1.25", "1.25.3", "latest", "mainline"],
  "Architecture": "amd64",
  "Os": "linux",
  "Layers": ["sha256:...", "sha256:...", "sha256:..."],
  "LayersData": [...]
}

Copy between two private registries (air-gapped migration):

bash
skopeo copy \
  docker://old-registry.company.com/myapp:v2.1 \
  docker://new-registry.company.com/myapp:v2.1 \
  --src-creds user:pass \
  --dest-creds user:pass

OCI Artifacts: Beyond Container Images

The OCI distribution spec is not limited to container images. Helm charts, WASM modules, and even Terraform modules can be stored in OCI registries as "OCI artifacts."

Push a Helm chart to an OCI registry:

bash
helm package ./mychart
helm push mychart-0.1.0.tgz oci://registry.example.com/helm-charts

Pull and install:

bash
helm install myapp oci://registry.example.com/helm-charts/mychart --version 0.1.0

The same registry API, the same authentication, the same layer caching — for any artifact type.

Summary: What to Remember

  • OCI standardizes image format, runtime, and distribution — not Docker's problem to solve anymore
  • Any OCI image runs on any OCI runtime (containerd, CRI-O, podman, runc)
  • Any OCI registry (ECR, GCR, Docker Hub, Harbor) speaks the same API
  • skopeo is the best tool for moving images between registries without a daemon
  • OCI artifacts extend this to Helm charts, Wasm, and anything else

The next time someone asks "will this Docker image work on our Kubernetes cluster?" the answer is: if it is built to OCI spec (and anything built with Docker is), yes.

Learn More

  • OCI Spec GitHub — the actual specs, surprisingly readable
  • Skopeo docs — full usage guide
  • Harbor — self-hosted OCI registry with scanning, replication, and RBAC
🔧

Today I Fixed

Short real fixes from production — posted daily

Browse fixes
Newsletter

Stay ahead of the curve

Get the latest DevOps, Kubernetes, AWS, and AI/ML guides delivered straight to your inbox. No spam — just practical engineering content.

Related Articles

Comments