fivenines
15/40

Guided Problem

MiniDock Build 11: Pull Only Missing Verified Content

Time
25m
Level
intermediate
Artifacts
not specified
Progress0%
Lesson 15 · Distribution

Pull, End to End

Design claim: A pull is a verified graph synchronization operation, not an archive download.

Starting model

  • You can authorize protected image reads and writes without exposing long-lived client credentials to content storage.
  • The useful vocabulary at this point is deliberately small: manifest-first, local diff, parallel download, digest verification.

Pull the graph, not the label

A client should obtain exactly the missing objects for a selected platform while reusing trusted local content. Distribution adds concurrency and remote failure to an immutable object graph. The useful question is when another client may safely observe a release.

The tempting shortcut is straightforward: download every object named by a tag and trust successful HTTP responses. The happy path makes the shortcut appear atomic even though metadata and large byte transfers complete at different times. Tags move, manifests may be platform-specific, local blobs may already exist, and transport success does not prove digest identity. Once a reader or retry can interleave with publication, visibility and durability need an explicit order.

Resolve before transferring

The manifest-first order is what makes pulls fast in practice. The manifest is a few KB and lists every blob digest, so before downloading anything heavy the engine can ask its layer store "which of these do I already have?" Pulling api:2.2 when you have api:2.1 typically means one changed app layer — a 40 MB download instead of 800. The missing blobs have no ordering dependencies (they're just bytes) so they download in parallel; only extraction must run bottom-up, because each layer's directory is stacked on its parent (Lesson 9).

The client resolves the reference, selects the platform manifest, walks its descriptors, skips verified local objects, and verifies every transfer before installation. The protocol separates authorization, object identity, transfer, and publication so each response has a precise meaning.

Read the architecture as a trust boundary around metadata and bytes, then identify the one operation that makes a graph visible.

Architecture — what a pull touches
  flowchart LR
    E["engine (pull api:2.2)"]
    R["registry"]
    LS[("layer store")]
    RS[("reference store")]
    E -- "1· GET manifest (small)" --> R
    E -- "2· which layers are new?" --> LS
    E -- "3· GET missing blobs
(parallel)" --> R E -- "4· verify + extract
(bottom-up)" --> LS E -- "5· record api:2.2 → digest" --> RS

It shows reference and platform resolution producing a descriptor graph. Its central claim is that a pull completes only when every descriptor reachable from the selected manifest is present and digest-verified; the labels therefore describe authority rather than decorative grouping.

Reuse local truth and verify new bytes

The manifest-first order is what makes pulls fast in practice. The manifest is a few KB and lists every blob digest, so before downloading anything heavy the engine can ask its layer store "which of these do I already have?" Pulling api:2.2 when you have api:2.1 typically means one changed app layer — a 40 MB download instead of 800. The missing blobs have no ordering dependencies (they're just bytes) so they download in parallel; only extraction must run bottom-up, because each layer's directory is stacked on its parent (Lesson 9).

Manifest and config resolution establish the graph; concurrent blob downloads fill only gaps; snapshot preparation happens after verified content is local. At each message, ask what the client and registry can now prove about the object graph.

The second figure tests the same model in motion: it traces local checks, concurrent transfers, verification, and final availability.

Sequence — pulling with a warm local store
  sequenceDiagram
    participant E as Engine
    participant R as Registry
    participant LS as Layer store
    E->>R: GET /v2/api/manifests/2.2
    R-->>E: manifest (layers: base 77ff, runtime 88aa, app 33cc)
    E->>LS: have 77ff? 88aa? 33cc?
    LS-->>E: have base + runtime, missing app 33cc
    par only the missing blob, in parallel with any others
      E->>R: GET /v2/api/blobs/sha256:33cc
      R-->>E: 40 MB
    end
    E->>E: re-hash — matches 33cc ✓
    E->>LS: extract 33cc atop runtime chain
    E->>E: record tag api:2.2 → manifest digest
      

It traces local checks, concurrent transfers, verification, and final availability. The ordering is valid only when it continues to preserve the stated invariant under retries and interruption.

Partial success is not a runnable image

One layer download is truncated while other layers succeed, so the image must not become runnable with an incomplete graph. Interruption may leave resumable work, but it must not leave a visible release whose referenced content cannot be served.

A pull completes only when every descriptor reachable from the selected manifest is present and digest-verified. The rule binds remote visibility to verified reachability rather than to connection success.

Make MiniDock pull to a closed graph

MiniDock synchronizes content by proof of identity rather than by assuming a remote bundle arrived intact. MiniDock gains a distribution contract while placement remains a design decision.

What carries forward

  • A pull completes only when every descriptor reachable from the selected manifest is present and digest-verified.
  • Install only complete verified missing content during an interruptible pull.
  • The rejected shortcut remains a diagnostic: if the design starts depending on it again, the original constraint has probably been lost.
Next step

See what actually stuck.

Take the practice scenarios now.