CoursesDocker in depthImage management

Tags, digests & pinning

Mutable names vs immutable content.

Intermediate10 min · lesson 3 of 30

A tag is a human-friendly, mutable pointer: payments-api:1.4.2 names some content today and can be repointed at different bytes tomorrow. A digest is the content itself — the SHA-256 of the image manifest, written name@sha256:… — and it is immutable by definition. Humans read and push tags; systems that care about running exactly what was tested resolve and deploy by digest.

terminal
$ docker buildx imagetools inspect registry.internal/payments-api:1.4.2
Name: registry.internal/payments-api:1.4.2
Digest: sha256:9f2a44c1e0b7...
$ docker images --digests registry.internal/payments-api
REPOSITORY TAG DIGEST IMAGE ID
registry.internal/payments-api 1.4.2 sha256:9f2a44c1... a1b2c3d4

Scenario: two nodes, same tag, different code

A service misbehaves on one node but works on another, both “running 1.4.2.” The tag was rebuilt and re-pushed between the two pulls, so the nodes hold different bytes under the same name — an unversioned, invisible deploy. Pinning by digest eliminates this class of bug entirely: the digest is the bytes, so every pull on every machine forever is identical.

deploy.yaml
# a tag for humans to read, a digest for the machine to actually run
image: registry.internal/payments-api:1.4.2@sha256:9f2a44c1e0b7...
# readable ─────────────────────┘ └── the exact bytes, immutable
# resolve the current digest for a tag before deploying:
# docker buildx imagetools inspect <img>:<tag> | grep Digest

Scenario: a base image changed under your build

A nightly rebuild that always “worked” suddenly ships a new CVE, because FROM node:22-alpine floats — the tag now points at a rebuilt base. Pin the base by digest so rebuilds are reproducible, and bump it deliberately when you have reviewed the change. The same discipline that protects your own images protects the shoulders they stand on.

Dockerfile
# floating: today’s node:22-alpine may not be tomorrow’s
FROM node:22-alpine
# pinned: the exact base bytes, rebuild-stable, bumped on review
FROM node:22-alpine@sha256:d71f4f2a9c...
latest is a moving target
The latest tag is not “the newest release” — it is “whatever was last pushed as latest,” and it changes without notice. Never run latest in production: pin an explicit version tag at minimum, and a digest wherever reproducibility (and later, signature verification) matters.