containerd/containerd
Content store
The content store is a content-addressable blob storage layer that backs every image layer, manifest, and config blob the daemon knows about. The interface lives in core/content/; the default on-disk implementation lives in plugins/content/local/.
Purpose
- Store immutable blobs keyed by their digest (
sha256:...). - Serve as the source of truth for image data so that GC can prune blobs whose digests are no longer referenced.
- Support concurrent ingest with resumability: a pull that's interrupted halfway can resume from the same byte offset.
Directory layout
core/content/
├── adaptor.go # adapter helpers around the gRPC types
├── content.go # Store, Manager, Reader, Writer interfaces
├── helpers.go # WriteBlob, Copy, OpenWriter helpers reused everywhere
├── proxy/ # gRPC client implementing the same Store interface
└── testsuite/ # cross-implementation conformance tests
plugins/content/local/
└── ... # filesystem-backed implementationKey abstractions
| Type | File | Purpose |
|---|---|---|
content.Store |
core/content/content.go |
Combined Manager + Provider + Ingester interface |
content.Manager |
core/content/content.go |
Info / Update / Walk / Delete |
content.Provider |
core/content/content.go |
ReaderAt over a digest |
content.Ingester |
core/content/content.go |
OpenWriter for new blobs (with optional WithRef resumption) |
content.Writer |
core/content/content.go |
A staged ingest; Commit(size, digest) finalizes it |
helpers.WriteBlob |
core/content/helpers.go |
The "do the right thing" helper used by transfer code |
On-disk layout
The local plugin (plugins/content/local/) uses two top-level directories under its plugin root:
ingest/<random ref>/— staged writes; containsdata(the bytes),total(expected size),ref(the user-provided ref), andstartedat/updatedattimestamps. Resumability uses these to re-open a partial blob.blobs/sha256/<digest>— committed blobs, one file per digest. The path issha256/<digest hex>.
A blob is committed by os.Rename-ing the ingest/<ref>/data file into blobs/sha256/<digest> after verifying the size and digest match.
How a pull writes blobs
graph LR
Resolver[remotes resolver] -->|HTTP GET layer| Reader
Reader -->|content.OpenWriter ref=layer| Writer
Writer -->|Write bytes, periodic Status| Disk[(ingest/<ref>)]
Reader -->|Commit size,digest| Move[os.Rename]
Move --> Blob[(blobs/sha256/<digest>)]The resolver in core/remotes/docker/ opens an HTTP reader for the registry, while helpers.WriteBlob drives the writer. Multiple pulls of the same blob deduplicate via the ref name and the eventual digest commit.
Garbage collection
Each blob carries labels stored alongside it. The metadata GC roots scan walks images and snapshots, marks reachable digests, and the content store deletes anything not in the mark set (and not under a lease). See GC.
Proxying to a remote store
core/content/proxy/ wraps a gRPC ContentClient so that a content store can live in another process. The daemon registers a content proxy plugin from [proxy_plugins.<name>] entries with type = "content" (see plugin runtime).
Service surface
The content gRPC service is implemented by plugins/services/content/ and exposes:
Info/Update/Delete/ListRead(ReaderAt over a digest, returned as a stream)Write(bidirectional stream for ingest with resumption)Status/ListStatuses/Abort(for inspecting and canceling in-progress ingests)
The proto lives in api/services/content/v1/content.proto.
Entry points for modification
- New on-disk format: implement
content.Storeand register it as a built-in or proxy plugin. - Custom ingest hashing: see
helpers.WriteBloband thedigest.Verifierit constructs. - Cross-content-store copy:
helpers.Copyis the canonical copy helper, used by transfer.
For the next system in the pipeline, see image distribution.
Built by Factory AutoWiki from public repository content. It is a generated preview for codebase exploration, not source-maintained documentation.