# 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).