Files
exploded-cluster/content/course-VII-supply-chain.md

92 lines
5.8 KiB
Markdown

# Course VII - The image supply chain: registries, mirrors, tags and digests
**Series position:** second course of the delivery arc. Course I taught what an image IS;
this course teaches how one travels - and how to say its name precisely.
**Safety gate:** public site - technologies only. Claims source from [[zot-registry]],
[[homelab-pull-through-registry]], [[work-container-image-tagging]] (generalised: the
calendar-rev pattern taught as "a human tag scheme", no corp framing), Azure Container
Registry as the generic managed-registry example, OpenShift IDMS behaviour from public
Red Hat docs.
## Title (thesis)
**A tag is a promise. A digest is a fact.**
## Hook - the uncomfortable default
`myapp:latest` feels like a name. It is not - it is a sticky note. A tag is a mutable
pointer anyone with push rights can peel off one image and press onto another, and
nothing anywhere records that it moved. The digest - sha256 of the content - is the
image's actual name: same bytes, same digest, forever. Most outages in this territory
begin with two machines both holding "the same tag" and running different code.
## Move 1 - Say the name properly
Three ways to name an image, in rising order of honesty: `:latest` (a moving target),
`:1.4.2` (a promise somebody keeps, until they re-push it), `name:1.4.2@sha256:...`
(a fact - the tag stays for human eyes, the digest does the pulling). Content-addressing
is the same idea git uses for commits: the name IS the bytes. Pin by digest and "what is
running?" has exactly one answer.
Say it like you mean it: **the tag is for reading, the digest is for pulling.**
FIELD NOTE (amber): `:latest` is how two nodes run different code from one manifest -
the second node pulled an hour later, after a re-push. Nobody changed the YAML.
## Move 2 - Why a fleet pulls once
Between the build and the node sits the registry chain. Upstream, a managed registry
(Azure Container Registry as the worked example) holds what CI built. In front of the
cluster sits a MIRROR - a pull-through cache like zot: the fleet asks the mirror, the
mirror asks upstream once, everything after is local. Three reasons this exists: rate
limits and egress cost (a hundred nodes should not make a hundred internet pulls),
availability (the fleet boots even when upstream is down or the site is disconnected),
and control (one place to gate, scan and audit what enters). OpenShift formalises the
re-route with image mirror rules - and carries a sharp edge: its digest-mirror rules
rewrite DIGEST pulls only, so a by-tag pull skips them - UNLESS an ImageTagMirrorSet is also
added (the rule type for tag pulls; corrected 2026-08-17). The pinning habit
from Move 1 is what makes the mirror actually catch the traffic.
FIELD NOTE: a mirror can also serve a STALE tag->digest mapping while upstream moved the
tag. Pin by digest and the whole chain becomes content-addressed - the mirror cannot be
wrong about a hash.
TIERING (added 2026-08-17, owner ask): at real fleet scale the mirror itself tiers - a
central pull-through in the cloud fronts upstream once; per-site mirrors pull from the
centre; nodes pull from their site over the LAN. The load fans out in layers instead of
every site hammering upstream at once. Say it: mirrors tier - the load fans out in
layers, never all at once.
## Move 3 - Build once, promote by copy
The anti-pattern: rebuild the image for each environment ("the prod build"). Every
rebuild is a different artefact - different digest, different bytes, untested by the
stages before it. The discipline: build ONCE, then PROMOTE the same digest through
environments by copying (skopeo copy --all --preserve-digests for multi-arch, or the copy takes
one arch and the promoted digest is not the one that lands) - dev proves the exact bytes
prod will run. Human-readable tags ride along (a calendar-plus-revision scheme reads well:
month, year, revision), but the digest is the through-line; promotion never changes it.
Say it like you mean it: **if the digest changed, it is not a promotion - it is a new
candidate.**
## Close
Everything in this course is one idea wearing three coats: names that can move are
convenient exactly until they move. Address content by what it IS, let humans keep their
readable labels, and the supply chain stops being a chain of trust and becomes a chain
of arithmetic.
## Legend terms (DOM layer)
tag / digest / content-addressing / pull-through mirror / disconnected pull / rate limit /
image mirror rule (digest-only rewrite) / build-once / promotion / skopeo copy
## Scene concept (hero + slices, the v3 mechanism)
Exploded left-to-right journey: the layered image CUBE from Course I (familiar - four
thin slabs, tight formation, reads as one unit now) -> upstream registry TOWER (tall
managed vault, cool white-cyan) -> the mirror WAY-STATION (squat wide cache block, warm
cyan, visibly closer to the cluster side) -> the node/cluster CORE. Floating above the
journey, two seal plates apart from each other: a GHOST RIBBON plate (the tag - faint,
translucent, edges blurring) and an ENGRAVED SEAL plate (the digest - dense, crisp,
crystalline). 6 parts, generous void, no connectors. Slice plan: collapse draws the
journey into the mirror block (everything local); the two seals collapse toward each
other but never merge - ghost stays ghost.
## Page footer - pre-reads + further reading (site convention: every course carries this)
Pre-reads: Course I (what an image IS - layers, this course ships that object);
Kubernetes images concept (https://kubernetes.io/docs/concepts/containers/images/).
Further reading: zot registry docs (https://zotregistry.dev/); Azure Container
Registry (https://learn.microsoft.com/azure/container-registry/); OpenShift image
configuration + mirroring (via
https://docs.redhat.com/en/documentation/openshift_container_platform); skopeo
(https://github.com/containers/skopeo).