The question this answers
Where do images live between build and deployment, and how do you know the thing production pulled is the thing you tested?
Twelve services deploy several times a day onto a fleet that scales to hundreds of nodes. Every node must be able to fetch the exact artifact that passed CI, no node may fetch anything else, and an auditor must be able to reconstruct what ran last Tuesday.
A content-addressed store with an access boundary: builders push, nodes pull, and every artifact has an immutable name that a deployment can reference and an audit can verify.
One artifact store, two very different clients
A registry looks like storage and behaves like a control point. On one side, a small number of build identities write; on the other, every node in the fleet reads, continuously, including during incidents when new capacity is being created. That asymmetry drives the design: writes are rare, privileged and auditable; reads are constant, high-volume and must not fail.
Which registry you use matters less than where it sits. A registry inside the provider network is reached over private connectivity and does not bill through the NAT meter; a public registry is reached over the internet, bills on every uncached pull, and imposes rate limits that surface as a stuck rollout on exactly the day you scale out hardest. The common production pattern is a private registry as the source of truth, with third-party images mirrored into it rather than pulled from upstream at deploy time — which also removes an external dependency from your critical path.
The registry is therefore a reliability dependency of the same rank as your load balancer. If it is unavailable, running containers keep running, but no new capacity can start and no deploy can proceed. That is a survivable outage right up until it coincides with a traffic spike.
Tags point; digests are
A tag is a mutable label attached to a manifest — a pointer, like a git branch. A digest is the SHA-256 of the manifest itself, so app@sha256:6b1f… names one specific set of bytes and can never name anything else. Everything about verifiable deployment follows from that distinction.
The classic finding is image: app:latest in a production manifest. It reads as "the current version" and means "whatever that pointer happens to reference at the moment each node pulls". During a rollout across a hundred nodes, if a build pushes mid-rollout, some nodes get one artifact and some get another, under one name. Rollback is undefined, because the previous bytes no longer have a name. And an incident timeline cannot state what was running, because the evidence was overwritten.
The fix has three parts and none of them is difficult. Tag immutably — the commit SHA or a semantic version — so a tag is never reused. Turn on registry-side tag immutability so a reused tag is rejected rather than silently accepted. Deploy by digest, recording it in the pipeline (The Container Build Pipeline). A human-readable tag is still useful; it just is not the thing the deployment references.
| Reference | Mutable? | Rollback means | Audit answer to "what ran?" | Verdict |
|---|---|---|---|---|
app:latest | Yes, constantly | Undefined — the previous bytes have no name | Unanswerable | The classic finding. Not a version. |
app:v2.4 | Yes, unless the registry enforces immutability | Deploy v2.3 and hope it was never overwritten | A name, not a proof | Acceptable only with immutability enforced. |
app:git-9f2c1ab | By convention only | Deploy the previous commit's tag | Traceable to a commit, still a pointer | Good for humans; pair it with a digest. |
app@sha256:6b1f… | No — content-addressed | Deploy the previous digest. Exact and instant. | Byte-exact | What the deployment should actually reference. |
Who may push, who may pull, and what a compromise buys
Registry permissions are usually granted once, broadly, and never revisited, which is how a single leaked token ends up able to overwrite every service's images. The useful decomposition is three identities with three different jobs: the build identity pushes new tags to one repository; the node identity pulls, and nothing else; the human identity reads metadata and, rarely and deliberately, deletes.
The pull side is the one people forget to narrow, because pull feels harmless. It is not, in two directions. A node identity with broad pull access can fetch every team's images, and images routinely contain enough application detail to plan an attack. And a node identity with *push* access — granted by accident, or by attaching one over-broad role to the whole node pool — means anything that compromises a single container can replace the images the entire fleet runs.
This is the same argument as Least Privilege in Infrastructure and connects directly to The Infrastructure Supply Chain: the registry is the last checkpoint before code executes in production. Signing artifacts and verifying signatures at admission is what turns "we trust the registry" into something a control can actually enforce.
- registry:PullImage on checkout/* and base/*
- registry:GetAuthorizationToken
- Pull the digests this node pool is scheduled to run, plus the shared base images they build on.
- registry:PushImage — a node must never be able to publish an artifact
- registry:DeleteImage — nothing at runtime should remove an artifact
- registry:PullImage on other teams' repositories
Blast radius: A compromised container on a node can read the images that node was already entitled to run. It cannot publish a replacement, cannot delete an artifact, and cannot reach another team's repositories — so a single compromised workload does not become a fleet-wide code-execution primitive.
Key points
- A tag is a mutable pointer; a digest is the artifact. Deploy the digest and keep the tag for humans.
:latestin a production manifest means "whatever that pointer references when each node pulls" — it makes rollback undefined and audit impossible.- Enable registry-side tag immutability so a reused tag is rejected instead of silently overwriting the artifact you tested.
- Split identities: builders push to one repository, nodes pull only, humans delete rarely and deliberately.
- Mirror third-party images into your own registry so an upstream outage or rate limit is not a deploy outage.
- The registry is a reliability dependency: while it is down, running workloads survive but no new capacity can start.
The loop, answered
Every field is required, which is why no lesson here can recommend something without saying what it costs and what simpler thing to consider first.
- • A push uploads each layer the registry does not already hold, then the manifest; the registry returns the manifest digest.
- • A tag is stored as a mutable reference to a manifest digest; pushing the same tag again simply repoints it.
- • A pull resolves the reference to a digest, fetches the manifest, then fetches the missing layers by their content hashes.
- • Because layers and manifests are content-addressed, the runtime can verify what it received matches what it asked for — the basis of any integrity guarantee.
- • Signing attaches an attestation to the digest; an admission controller verifies it before allowing the workload to start.
- • Garbage collection removes layers no manifest references, which is why deleting a tag does not immediately free storage.
- • You own tag conventions and immutability enforcement. Convention alone fails the first time someone is in a hurry.
- • You own retention: how many builds to keep, how long, and what a deletion policy does to a rollback target you might still need.
- • You own mirroring of upstream images and the schedule on which mirrors refresh.
- • You own the pull path — private endpoint versus NAT — which decides both the bill and whether pulls survive an egress failure.
- • You own registry availability planning: cross-region replication if a regional registry outage would block a failover deployment.
- • A rollout half-completes because a public registry rate limit is hit; some nodes run the new version, others cannot pull, and the fleet is in a mixed state.
- • An image-pull failure that is actually an authorization failure — the node identity lacks permission on the repository — and reads to the on-call as a network problem.
- • A retention policy deletes the previous release's image, and the rollback that was supposed to take thirty seconds requires a rebuild.
- • A tag is overwritten mid-rollout and two different artifacts serve traffic under one version number, producing errors that reproduce on some replicas and not others.
- • A regional registry outage during a zone failover: the failover plan requires starting new capacity, and no new capacity can pull.
- • Read volume scales with nodes × deploys × image size and is overwhelmingly the dominant load — writes are rare by comparison.
- • Concurrent pulls during a large rollout are the spike that finds the rate limit; a pull-through cache or node-level pre-pull flattens it.
- • Storage scales with retained tags and distinct layers, so retention policy is the main lever and layer sharing is the main saving.
- • What runs out first is usually the rate limit or the egress path, not registry storage or CPU.
- • The registry is the last checkpoint before code runs in production. Anyone who can push can execute code on your fleet.
- • Push permission must be narrow and auditable; pull permission must be scoped per node pool, not granted fleet-wide.
- • Sign artifacts and verify at admission — that is what makes "only images from our registry" an enforced control rather than a convention.
- • Private does not mean unreachable: a private registry with a public endpoint and a leaked credential is a public registry. Prefer private connectivity.
- • Scan on push and re-scan on a schedule; the image does not change but the known-vulnerability set does. See The Infrastructure Supply Chain.
- • Storage is driven by retained tags and distinct layers; a retention policy is the direct lever.
- • Transfer is the larger meter: bytes × pulls, and it bills again when it crosses NAT, zone or region boundaries.
- • A pull-through cache or private endpoint converts a repeated usage cost into a mostly fixed one — usually a clear win at fleet scale.
- • Cross-region replication buys deploy availability during a regional failure and costs storage in every replicated region.
- • Pull failure rate by reason — authorization, rate limit, not-found — because those three have completely different fixes.
- • Pull latency and volume per node pool, which is simultaneously the deployment-speed signal and the transfer-cost signal.
- • Push events with identity and digest, as an audit trail: who published what, when.
- • Deployed digests versus expected digests across the fleet — the check that catches a mid-rollout tag overwrite.
- • The signal that lies: registry uptime. The registry can be up while your nodes cannot pull, because the failure is in the path or the permissions.
- • The provider's managed registry rather than a self-hosted one: private connectivity, workload identity and replication without running the storage yourself.
- • A public registry with a pull-through cache for a small team — simple, and the cache removes the rate-limit failure mode.
- • For a single-host deployment, building the image on the host and skipping the registry entirely is legitimate. A registry is a distribution mechanism; with one host there is nothing to distribute.
- • A plain artifact store for non-container artifacts. Not everything needs to be an image, and a tarball with a checksum solves some distribution problems with far less machinery.
- • A private registry buys control, private pull paths and mirroring; it costs storage, replication and one more thing to keep available.
- • Digest-based deployment buys exactness and costs readability — nobody recognizes a release by its hash, so you keep tags for humans anyway.
- • Strict retention buys lower cost and costs rollback targets; keep at least the last several releases regardless of what the policy says.
- • Signature verification at admission buys a real supply-chain control and costs a hard dependency: if verification breaks, nothing deploys.
What people believe, and what is true
:latest means the newest image.
It means whatever was pushed to that tag most recently, which may be older, may change mid-rollout, and cannot be rolled back to.
A private registry means the images are secret.
It means access-controlled. Anyone with pull permission — including every node — can extract every layer, which is why secrets in images are a disclosure.
The registry is only needed at deploy time.
Every node replacement, every scale-out and every restart on a cold node pulls. It is on the critical path of recovery, not just of deployment.