moby/moby
Image management
Purpose
Moby has two image stores in the same binary, behind a common interface. The choice happens at startup. Both stores expose the same ImageService contract to the rest of the daemon.
| Store | Code | Storage | Status |
|---|---|---|---|
| Containerd | daemon/containerd/ |
containerd content + image stores | Modern path; default going forward. |
| Legacy | daemon/internal/image/, daemon/internal/layer/, daemon/internal/distribution/ |
Graphdriver layer cache + JSON metadata | Original implementation. Being phased out. |
The picker is daemon/image_store_choice.go. Both stores satisfy ImageService so the rest of the daemon doesn't care which one runs.
The ImageService contract
daemon/image_service.go declares a small interface — pull, push, build base, list, inspect, history, save, load, tag, remove, prune, get layer info, get container's read-write layer. Most of those map 1-to-1 to API endpoints under /images/....
Containerd-backed store
daemon/containerd/ is the modern implementation. Notable files:
| File | Role |
|---|---|
service.go |
ImageService constructor and dependency wiring. |
image.go |
Resolve image references, tag, untag. |
image_pull.go |
Pull via containerd's resolver and content store. |
image_push.go |
Push, including OCI annotations. |
image_list.go |
List images with filters; the largest file in the package. |
image_delete.go |
Untag/remove with reference counting. |
image_history.go |
Replay manifest history. |
image_inspect.go |
docker image inspect data assembly. |
image_builder.go |
Glue for the builder backend. |
image_exporter.go |
docker save/load over OCI layout. |
image_snapshot.go |
Allocate a containerd snapshot for a new container. |
progress.go |
Streams pull/push progress to the API client. |
migration/ |
One-shot import from the legacy store. |
identitycache/ |
Caches resolved chain IDs to avoid repeated layer scans. |
The store reuses the containerdClient already created for container runtime, so a single connection serves both content and runtime calls.
Legacy store
The legacy store predates containerd. Its pieces are spread across several packages:
| Package | Role |
|---|---|
daemon/internal/image/ |
Image config metadata and JSON store (store.go), tar export/import, V1 manifest support. |
daemon/internal/layer/ |
RW + RO layer abstraction (chain IDs, mount manager, metadata DB). |
daemon/graphdriver/ |
Per-driver overlay/btrfs/zfs/vfs/fuse-overlayfs/windows backends. |
daemon/internal/distribution/ |
Pull/push against OCI distribution registries (V2 only by now). |
daemon/internal/refstore/ |
Reference (tag) store backed by a JSON file under image/. |
daemon/images/ |
Glue layer that hooks the legacy store into Daemon. |
When the legacy store is active, Daemon.layerStore and Daemon.distributionMetadataStore are populated; with the containerd store they are nil and image work goes through Daemon.imageService directly.
Pull lifecycle (containerd path)
sequenceDiagram participant Client participant Router as image router participant Service as containerd ImageService participant Resolver as containerd resolver participant Content as containerd content store Client->>Router: POST /images/create?fromImage=... Router->>Service: PullImage(ref, auth) Service->>Resolver: resolve manifest Resolver-->>Service: descriptor Service->>Content: fetch layers (parallel) Content-->>Service: progress events Service-->>Router: stream JSON progress Router-->>Client: chunked HTTP response
The progress streaming logic lives in daemon/containerd/progress.go; it bridges containerd's progress channel to the JSON-line output Docker clients expect.
Tags and references
Both stores parse references with github.com/distribution/reference. Tagging on the containerd path writes a new entry into containerd's image store; on the legacy path it updates the JSON ref store.
Migration
Migration from the legacy store to the containerd store is one-way. The driver is in daemon/migration.go; the heavy lifting is in daemon/containerd/migration/, which walks the existing layer DB and writes equivalent records into containerd's content/image stores.
Entry points for modification
- New image API field: update
api/swagger.yaml, the corresponding type underapi/types/image/, then both store implementations. - Layer-format change: legacy path goes through
daemon/internal/layer/anddaemon/graphdriver/; modern path goes throughdaemon/snapshotter/and containerd snapshotters. - Pull/push: containerd path under
daemon/containerd/image_pull.go/image_push.go; legacy underdaemon/internal/distribution/pull_v2.go/push_v2.go.
See also
- Distribution for the legacy registry client.
- Graphdrivers for the legacy filesystem layer.
- Container runtime for the shared containerd client.
Built by Factory AutoWiki from public repository content. It is a generated preview for codebase exploration, not source-maintained documentation.