Open-Source Wikis

/

Moby

/

Systems

/

Image management

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 under api/types/image/, then both store implementations.
  • Layer-format change: legacy path goes through daemon/internal/layer/ and daemon/graphdriver/; modern path goes through daemon/snapshotter/ and containerd snapshotters.
  • Pull/push: containerd path under daemon/containerd/image_pull.go / image_push.go; legacy under daemon/internal/distribution/pull_v2.go / push_v2.go.

See also

Built by Factory AutoWiki from public repository content. It is a generated preview for codebase exploration, not source-maintained documentation.

Image management – Moby wiki | Factory