Skip to content

Architecture ​

Big picture ​

Distribution is three layers stacked on top of each other. At the top is an HTTP API layer that routes registry requests to handlers (registry/handlers). Below it is a storage abstraction that knows the registry's on-disk layout and the content-addressable rules (registry/storage). At the bottom are storage drivers, each a filesystem-like key/value backend for a specific target such as the local filesystem, S3, GCS, or Azure Blob (registry/storage/driver). A request enters at the top, and the layers translate it down to reads and writes on whatever backend is configured.

Components ​

HTTP router and dispatchers ​

registry/handlers/app.go is the center of the HTTP layer. The App holds a gorilla/mux router and registers one dispatcher per route name (registry/handlers/app.go:106). The route names are defined in registry/api/v2/routes.go:11: base, manifest, tags, blob, blob-upload, blob-upload-chunk, and catalog. A dispatcher is a function that reads the request, builds the right handler, and maps HTTP methods to handler methods.

Handlers ​

Each registry operation has a handler file under registry/handlers/: blob.go for blob GET/HEAD/DELETE, blobupload.go for the blob upload session that a push uses, manifests.go for manifest GET/PUT, plus tags.go and catalog.go. A handler is the glue between an HTTP request and the storage layer; it does not itself know how bytes are stored.

Storage abstraction ​

registry/storage/ holds the layer that knows the registry's layout. blobStore and blobStatter (registry/storage/blobstore.go:19, registry/storage/blobstore.go:156) are the global, repository-independent view of blobs, keyed by digest. blobServer (registry/storage/blobserver.go:19) serves blob bytes over HTTP. linkedBlobStore (registry/storage/linkedblobstore.go) is the per-repository view: it tracks which blobs a given repository contains, using small link files. This is the layer that enforces content-addressability and repository membership.

Storage drivers ​

registry/storage/driver/ holds the backends: filesystem, inmemory, s3-aws, gcs, and azure. They all satisfy one interface, StorageDriver (registry/storage/driver/storagedriver.go:56), which models a filesystem-like key/value object store: GetContent, PutContent, Reader, Writer, Stat, List, Move, Delete, RedirectURL, and Walk. Swapping backends means swapping the driver; nothing above this interface changes.

How a request flows ​

Trace a blob GET, the read half of docker pull, from HTTP request to bytes:

  1. The blob route is registered with blobDispatcher (registry/handlers/app.go:112). The dispatcher builds a blobHandler and maps GET and HEAD to GetBlob (registry/handlers/blob.go:14, registry/handlers/blob.go:34).
  2. blobHandler.GetBlob gets the repository's blob service with bh.Repository.Blobs(bh), then calls blobs.Stat(bh, bh.Digest) to confirm the blob exists (registry/handlers/blob.go:55, registry/handlers/blob.go:58), and on success calls blobs.ServeBlob (registry/handlers/blob.go:68).
  3. Stat resolves to blobStatter.Stat (registry/storage/blobstore.go:165). It computes the blob's data path from the digest and calls driver.Stat (registry/storage/blobstore.go:166, registry/storage/blobstore.go:173). A missing path is translated from the driver's PathNotFoundError into distribution.ErrBlobUnknown (registry/storage/blobstore.go:176), which the handler turns into the correct HTTP error.
  4. ServeBlob resolves to blobServer.ServeBlob (registry/storage/blobserver.go:26). It re-stats the blob, computes the path, and if redirect is enabled it asks the driver for a RedirectURL (registry/storage/blobserver.go:37). If the driver returns a non-empty URL, the registry replies 307 Temporary Redirect and the client fetches the bytes straight from object storage (registry/storage/blobserver.go:41).
  5. If there is no redirect URL, the registry falls back to streaming: it opens a newFileReader on the driver and serves the content with http.ServeContent (registry/storage/blobserver.go:50, registry/storage/blobserver.go:73).

Key design decisions ​

Content-addressable storage. A blob is stored once, under a path derived from its digest (blobs/<algorithm>/<digest>/data), and each repository refers to it through a link file rather than a second copy. The layout is documented in a comment block in registry/storage/paths.go:24. A blob shared by many repositories costs one copy of the bytes plus a handful of tiny links. Integrity comes for free: the digest is the address, so a corrupted blob does not match its own path.

Redirect instead of proxy. For cloud drivers, the registry does not sit in the data path. blobServer.ServeBlob returns a 307 to a presigned object-storage URL and the client downloads directly from the store (registry/storage/blobserver.go:37). This keeps the registry process from being the bottleneck when thousands of nodes pull a popular image at once. It can be turned off with the redirect flag, in which case the registry streams the bytes itself.

Pluggable drivers. Backends are registered through a factory and created by name (registry/storage/driver/storagedriver.go:50 comment). Because every driver is just a filesystem-like key/value store behind one interface, the storage and HTTP layers are backend-agnostic.

Cross-repository blob mount. If a blob already lives in another repository the client can mount it instead of re-uploading, short-circuiting the upload entirely (registry/storage/linkedblobstore.go:139). This is a direct payoff of content-addressability: the bytes already exist, so a mount is just a new link.

Extension points ​

  • Storage drivers: implement StorageDriver (registry/storage/driver/storagedriver.go:56) and register it with the factory to add a backend. The in-tree drivers (filesystem, s3-aws, gcs, azure, inmemory) are examples of the same interface.
  • The library itself: the README states the components are meant to be consumed as libraries for building a larger registry, and notes those library interfaces are unstable (README). Harbor is the canonical example of a product built this way.