containerd Content Store & Image Management

Understand how containerd stores and manages OCI images using content-addressable storage, metadata, and efficient distribution mechanisms.

OCI Images Content Addressing Metadata Store Image Distribution
Content Store Overview

The content store is the low-level storage system in containerd that manages all content blobs (image layers, manifests, configs) using content-addressable storage (CAS). Each piece of content is identified by its cryptographic hash (digest), ensuring integrity and deduplication.

This design allows containerd to efficiently store and retrieve image layers, share them across images, and verify content integrity. The content store works closely with the metadata store and snapshotter to provide a complete image management system.

Content-addressable storage means each blob is stored once and referenced by its hash. If two images share the same layer, it's stored only once, saving disk space.
Content-Addressable Storage (CAS)

containerd uses a content-addressable storage system where each content blob is stored under its digest (SHA256 hash). This provides several benefits:

  • Deduplication: Identical layers are stored only once
  • Integrity: Content can be verified by recalculating its hash
  • Immutability: Content cannot be changed without changing its identifier
  • Efficient distribution: Only new content needs to be transferred
# View content store (Linux) ls /var/lib/containerd/io.containerd.content.v1.content/blobs/sha256/ # Example content paths: # /var/lib/containerd/io.containerd.content.v1.content/blobs/sha256/ # a1b2c3d4e5f6... (manifest) # 1a2b3c4d5e6f... (layer) # f6e5d4c3b2a1... (config) # View content by digest ctr content ls # Show content info ctr content info sha256:a1b2c3d4e5f6...
OCI Image Format

containerd fully supports the Open Container Initiative (OCI) image format. An OCI image consists of three main components:

  • Manifest: JSON document describing the image layers and configuration
  • Config: JSON document with image metadata (entrypoint, env vars, etc.)
  • Layers: Tar archives containing the filesystem changes (tarballs)
# Inspect an OCI image manifest ctr image ls ctr image info docker.io/library/nginx:alpine # View image configuration ctr image ls -q | xargs ctr image info # Example OCI manifest structure: { "schemaVersion": 2, "mediaType": "application/vnd.oci.image.manifest.v1+json", "config": { "mediaType": "application/vnd.oci.image.config.v1+json", "size": 1234, "digest": "sha256:abc123..." }, "layers": [ { "mediaType": "application/vnd.oci.image.layer.v1.tar+gzip", "size": 5678, "digest": "sha256:def456..." } ] }
Image Pull Flow

When you pull an image, containerd follows a well-defined flow to fetch, verify, and store the image content:

1. Client requests image pull via `ctr image pull` or `nerdctl pull`
2. Resolution - containerd resolves the image name to a manifest digest
3. Manifest Fetch - Downloads the image manifest from registry
4. Layer Download - Downloads each layer tarball (parallelized)
5. Verification - Verifies each layer's digest matches the manifest
6. Storage - Stores content in the content store (CAS)
7. Unpack - Extracts layers to the snapshotter for container creation
# Pull an image with verbose output ctr image pull --debug docker.io/library/nginx:alpine # Pull with specific snapshotter ctr image pull --snapshotter=overlayfs docker.io/library/nginx:alpine
Metadata Store

The metadata store manages all high-level image metadata, including image names, tags, and references. It uses BoltDB (embedded key-value store) to persist metadata.

# Metadata store location ls /var/lib/containerd/io.containerd.metadata.v1.bolt/ # meta.db - BoltDB database file # View image metadata ctr image ls # View detailed image info ctr image info docker.io/library/nginx:alpine # The metadata store tracks: # - Image names and tags # - Image digests (manifest and config) # - Content references # - Labels and annotations
The metadata store is separate from the content store. The content store holds the actual blobs; the metadata store tracks references to those blobs.
Content Management Commands
# List all content ctr content ls # Show content details ctr content info sha256:a1b2c3d4e5f6... # Delete content ctr content rm sha256:a1b2c3d4e5f6... # Verify content integrity ctr content verify sha256:a1b2c3d4e5f6... # Export content to file ctr content export content.tar # Import content from file ctr content import content.tar # List images (high-level view) ctr image ls # Remove image ctr image rm docker.io/library/nginx:alpine
Image Distribution: Pull and Push
# Pull image from Docker Hub ctr image pull docker.io/library/nginx:alpine # Pull from private registry ctr image pull myregistry.azurecr.io/myapp:latest # Push image to registry (must be tagged) ctr image tag docker.io/library/nginx:alpine myregistry/nginx:alpine ctr image push myregistry/nginx:alpine # Push with specific platform ctr image push --platform linux/amd64 myregistry/nginx:alpine # Use nerdctl for Docker-like experience nerdctl pull nginx:alpine nerdctl push myregistry/nginx:alpine
Image Export and Import
# Export image to tar file ctr image export nginx.tar docker.io/library/nginx:alpine # Or with nerdctl nerdctl save -o nginx.tar nginx:alpine # Import image from tar file ctr image import nginx.tar # Or with nerdctl nerdctl load -i nginx.tar # Export multiple images ctr image export images.tar docker.io/library/nginx:alpine docker.io/library/redis:alpine
Registry Configuration

You can configure containerd to use specific registry mirrors, authentication, and TLS settings.

# Registry configuration in config.toml [plugins."io.containerd.grpc.v1.cri".registry] config_path = "/etc/containerd/certs.d" # Mirror configuration [plugins."io.containerd.grpc.v1.cri".registry.mirrors."docker.io"] endpoint = ["https://mirror.gcr.io", "https://registry-1.docker.io"] # Host configuration [plugins."io.containerd.grpc.v1.cri".registry.configs."myregistry.azurecr.io".auth] username = "myuser" password = "mypassword" # TLS configuration [plugins."io.containerd.grpc.v1.cri".registry.configs."myregistry.azurecr.io".tls] insecure_skip_verify = true # Not recommended for production
Image Layer Management
# Show image layers ctr image ls ctr image info docker.io/library/nginx:alpine | jq '.layers' # Pull specific layer ctr content fetch docker.io/library/nginx:alpine@sha256:abc123... # View layer size breakdown ctr image ls | awk '{print $1, $2}' | while read name tag; do ctr image info "$name:$tag" | grep -A 5 layers done # Clean up unused layers (by removing unused images) ctr image rm $(ctr image ls -q) # Prune unused content ctr content prune
Frequently Asked Questions
What is a content-addressable store?
Content-addressable storage (CAS) stores content by its cryptographic hash (digest). Each piece of content is uniquely identified by its hash, enabling deduplication and integrity verification.
How does containerd handle image deduplication?
Images share layers if they have the same content. Since layers are stored by their digest, identical layers (even from different images) are stored only once, saving disk space.
Where does containerd store images?
Images are stored in two parts: content blobs in `/var/lib/containerd/io.containerd.content.v1.content/` and metadata in `/var/lib/containerd/io.containerd.metadata.v1.bolt/meta.db`.
Can I use containerd with private registries?
Yes! Configure authentication in the containerd config.toml or use `ctr image pull` with `--user` flag, or use `nerdctl login` for Docker-like authentication.
What is the difference between `ctr image pull` and `ctr content fetch`?
`ctr image pull` pulls the entire image (manifest + all layers) and registers it in the image store. `ctr content fetch` only downloads a specific content blob (individual layer or manifest).
How do I clean up old images and content?
Use `ctr image rm` to remove images, which also removes unreferenced layers. Use `ctr content prune` to clean up orphaned content blobs.
Does containerd support image signing?
Yes! containerd supports OCI image signing and verification through integrations with cosign, notation, and other signing tools.
How do I check the size of an image before pulling?
Use `ctr image pull --dry-run` or check the registry manifest directly. For Docker Hub, use `docker manifest inspect` or the registry API.
Previous: Snapshot Drivers Next: ctr Commands

The content store is the foundation of containerd's image management system. Understanding it helps you manage container images efficiently.