Skip to content
Lesson 16 of 19

Step 1 of 5 · Reading · ~3 min

Read

Filesystems & Images

Registry Pull Protocol

docker pull alpine:3.19 looks like one download. It is a conversation, defined by the OCI Distribution Specification, and every property people find surprising about pulls — why the second one is instant, why two images share a download, why a failed pull leaves nothing behind — is visible in the transcript.

The conversation

GET /v2/library/alpine/manifests/3.19
    -> 200, a manifest naming config + layer digests

for each layer digest, in order:
    already in the local content store?  -> skip it, no request at all
    otherwise: GET /v2/library/alpine/blobs/sha256:<digest>
    -> 200, stream the bytes to disk, then verify the hash

all layers present -> the image is ready

Three things are worth reading off that. The manifest is always refetched, because a tag is a mutable pointer and the client cannot know it still means what it meant yesterday. The blobs are not, because a digest is an identity — once sha256:abc… is in the store it is that content forever, and there is no cache-invalidation question to ask. And blobs are stored per digest, not per image, which is why pulling python:3.11-slim after debian:bookworm downloads only the difference.

Tags move, digests do not

alpine:latest today and alpine:latest in a year are two different manifests. The old blobs are still in your store under their own digests until garbage collection removes them; nothing was overwritten, because nothing addressed by content ever can be. This is exactly why deployments that must be reproducible pin image@sha256:… rather than a tag — a digest pin cannot drift, and a tag pin silently can.

When it fails

  • 404 on the manifest — a typo in the repository, or a tag that does not exist. Nothing was transferred; the pull ends there.
  • 404 on a blob — registry corruption or an over-eager garbage collection. The pull stops at that layer; the layers already fetched stay in the store (they are valid content, just not a complete image), and the image does not appear.
  • 401 with WWW-Authenticate: Bearer realm=… — the normal opening move for a private repository. The client fetches a token from the named realm and retries. Your exercise skips auth.

Why the exercise is a simulator

There is no privilege problem here and no network in the grader — the exercise is the protocol with the sockets removed, which leaves the part that carries the behaviour: order of requests, and what the cache lets you skip.

Your exercise: Simulate docker pull

The registry / client doesYour simulator does
a blob exists in the registry at some sizePUT-BLOB <digest> <size>
a tag resolves to an ordered list of layer digestsPUT-MANIFEST <repo> <tag> <digests...>
the whole pull conversation, printed line by linePULL <repo> <tag>
the local content store is emptiedFLUSH-CACHE

The output is the answer, so the sequence has to be exact: the manifest request, then the manifest result, then per layer either CACHED <digest> with no request line, or the request line followed by 200 <size> bytes. A missing blob prints 404 blob, stops the loop immediately — later layers are never requested — and ends the pull with PULL FAILED. A layer only enters the cache after it was successfully fetched, which is what makes the second PULL of the same image all-cached and a FLUSH-CACHE between them fetch everything again.

Up nextContainer CreationContainer Lifecycle

Discussion

Ask a question, share an insight, or help someone who’s stuck.

Sign in to post a comment or reply.

Loading…