Containers & Images

The Container Registry

The registry is the boundary between "built" and "deployable", and the one component every host in the fleet pulls from. Tags are mutable pointers, digests are the artifact, and :latest in a production manifest is the classic finding.

The question this answers

Infrastructure question

Where do images live between build and deployment, and how do you know the thing production pulled is the thing you tested?

Application requirement

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.

What it provides

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.

Application RequirementInfrastructure RequirementComputeNetworkStorageIdentityDeploymentScalingReliabilityObservabilitySecurityCostTrade-offs

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.

CI writes; the fleet reads. The pull path decides both the bill and the failure surface.PROVIDER-NEUTRAL
CI build jobinternal— push-only identity, one repository
Private registryprivate— source of truth; mirrors third-party bases
Public upstream registrypublic
Production virtual network
Zone A node poolprivate
Nodes (pull-only identity)private
Zone B node poolprivate
Nodes (pull-only identity)private
Private endpoint to registryprivate— keeps pulls off the NAT and egress meters
Public upstream registryPrivate registry· mirror on a schedule, not at deploy timecrosses boundary
CI build jobPrivate registry· push new tag + digestcrosses boundary
Nodes (pull-only identity)Private endpoint to registry· pull by digest
Nodes (pull-only identity)Private endpoint to registry· pull by digest
Private endpoint to registryPrivate registry· private path

Tags point; digests are

containers· Digest addressing is part of the OCI distribution specification and works identically on every conforming registry.

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.

ReferenceMutable?Rollback meansAudit answer to "what ran?"Verdict
app:latestYes, constantlyUndefined — the previous bytes have no nameUnanswerableThe classic finding. Not a version.
app:v2.4Yes, unless the registry enforces immutabilityDeploy v2.3 and hope it was never overwrittenA name, not a proofAcceptable only with immutability enforced.
app:git-9f2c1abBy convention onlyDeploy the previous commit's tagTraceable to a commit, still a pointerGood for humans; pair it with a digest.
app@sha256:6b1f…No — content-addressedDeploy the previous digest. Exact and instant.Byte-exactWhat the deployment should actually reference.
Three ways to reference the same image, and what each one can prove.

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.

Node identity for a production node pool. Pull-only, scoped, and unable to change what anything else runs.
node-pool-prod (instance/workload identity attached to every node)vmleast privilege
on registry.example.com/checkout/*, registry.example.com/base/*
Allowed
  • registry:PullImage on checkout/* and base/*
  • registry:GetAuthorizationToken
Actually needed
  • Pull the digests this node pool is scheduled to run, plus the shared base images they build on.
Explicitly denied
  • 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.
  • :latest in 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.

How it works
  • 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.
What you still own
  • 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.
How it fails
  • 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.
How it scales
  • 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.
Security
  • 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.
Cost shape
  • 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.
What to watch
  • 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.
Simpler alternatives
  • 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.
What adopting this costs
  • 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

Claim

:latest means the newest image.

Reality

It means whatever was pushed to that tag most recently, which may be older, may change mid-rollout, and cannot be rolled back to.

Claim

A private registry means the images are secret.

Reality

It means access-controlled. Anyone with pull permission — including every node — can extract every layer, which is why secrets in images are a disclosure.

Claim

The registry is only needed at deploy time.

Reality

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.

Apply it