Image Tags, Digests, Mutable vs Immutable References, Pull Policies, Pinning, and Reproducibility: Configuration, Design Choices, and Tradeoffs
Choose tag, digest, pull-policy, and promotion strategies deliberately. This lesson compares floating development tags, semantic release aliases, digest pinning, base-image pins, Docker and Compose pull policies, and build-once/promote-the-same-digest workflows.
Learning objectives
- Select when human-friendly tags, digest pins, or both should appear in build and deployment configuration.
- Compare Docker Engine and Compose pull policies as freshness controls rather than identity controls.
- Explain the operational tradeoff of base-image pinning: reproducibility improves, but updates must become an explicit reviewed event.
- Design a build-once/promotion workflow that moves aliases without rebuilding approved release bytes.
- Choose development and production policies from evidence, trust boundary, rollback, and offline requirements.
1. Start with the decision, not the syntax
The right reference strategy depends on what the consumer is trying
to optimize. A developer may intentionally follow
app:dev. A production rollback procedure needs an exact
immutable identity. A Dockerfile base should usually be readable to
humans but also reproducible enough to audit. These goals are not
contradictory when you keep an alias and its digest together.
2. Reference strategy decision table
| Pattern | Strength | Risk | Good fit |
|---|---|---|---|
app:dev |
Simple, intentionally follows a moving channel. | Same config can resolve to new content later. | Fast inner-loop development. |
app:3.8.0 |
Readable release intent. | Still mutable unless registry policy protects it. | Catalog/UI alias plus recorded digest. |
app@sha256:… |
Exact immutable registry object. | Less readable; updates require explicit change. | Production deployment, rollback, evidence. |
app:3.8.0@sha256:… |
Readable intent plus immutable constraint. | Must keep tag/digest pairing current. | Dockerfile base pinning and reviewable config. |
3. Docker Engine pull policies
docker run --pull=missing uses local cached content
when the named image exists, always initiates a pull
before container creation, and never requires the image
to already be local. These policies answer “should I consult the
registry?” They do not answer “which release is approved?”
| Policy | Registry behavior | Typical use | Identity warning |
|---|---|---|---|
missing |
Pull only if not local. | General local use; offline-tolerant cache. | A mutable tag may remain stale locally. |
always |
Pull before creation. | Follow a mutable channel deliberately. | Fresh tag resolution is still mutable. |
never |
No implicit pull. | Offline or tightly staged hosts. | You must prove the preloaded content identity separately. |
4. Compose adds time-based and build-aware policies
Current Compose service configuration supports always,
never, missing, build,
daily, weekly, and
every_<duration>. The latest tag is
always pulled under missing. This is useful for
developer freshness policies, but production identity should still
be explicit.
services:
api:
image: registry.example/team/api@sha256:REVIEWED_DIGEST
pull_policy: missing
Here the digest fixes identity; the policy controls whether missing content can be retrieved. Avoid inventing a tag-refresh policy as a substitute for release approval.
5. Base-image pinning: deterministic input versus automatic drift
Docker’s build guidance recommends digest pinning when you need
exact base identity. A pattern such as
FROM alpine:3.21@sha256:… communicates the intended
release line and freezes the exact object. If the publisher later
updates 3.21, your build does not silently change.
The cost is deliberate maintenance: a pinned base does not automatically absorb security fixes. Use dependency automation or scheduled review to propose a new digest, rerun tests/scans, and merge the update with an audit trail.
6. Build once; move references, not bytes
flowchart TD
A[Source SHA] --> B[Build once]
B --> C[Digest D]
C --> D[Test / scan / attest D]
D --> E[Attach candidate alias to D]
E --> F[Promote staging alias to D]
F --> G[Promote production alias to D]
G --> H[Deployment records D]
If promotion rebuilds the source, the new result is a new artifact that requires its own evidence. A tag that says the same version does not make two builds identical.
7. Multi-platform promotion needs two levels of identity
For a multi-platform release, record the index digest as the release-set identity and retain the child manifest digests used by supported platforms. If an arm64-only incident occurs, the index proves the overall release while the arm64 descriptor identifies the exact failing platform artifact.
8. Worked scenarios
| Scenario | Recommended pattern | Why |
|---|---|---|
| Developer follows newest integration build |
Floating :dev + --pull=always
|
Freshness is intentional; failures are expected to track the channel. |
| Air-gapped validation host | Preloaded digest + --pull=never |
No network lookup; exact preload evidence is required. |
| Production release |
Deploy approved repo@digest; optionally publish
readable alias
|
Independent verification and rollback. |
| Dockerfile base | tag@digest with scheduled update PRs |
Readable intent plus deterministic bytes and reviewable upgrades. |
9. Registry policy can reinforce—but not replace—evidence
Some registries can protect tags from mutation. That is useful governance, but consumers should still record digests because the digest travels with scans, signatures, attestations, deployment records, and incident evidence. Registry policy answers “who may move this alias?”; the digest answers “what content is this?”
10. Decision challenge
Your CI pipeline pushes app:2.7.4, tests it, then
rebuilds the same source in a production job and pushes the new
bytes under the same tag. Explain why this breaks provenance even if
both images pass tests, and redesign the workflow so staging and
production consume the exact approved digest.
Knowledge check
Is pull_policy: always a substitute for digest
pinning?
No. It asks the registry for the current reference; a mutable tag can still resolve differently over time.
Why can tag@digest be useful in a
Dockerfile?
It keeps a readable release hint while constraining the build to exact immutable content.
What maintenance burden does digest pinning introduce?
Updates become explicit reviewed changes; you must intentionally move to a newer digest for fixes or features.
What is wrong with rebuilding during promotion?
It creates a different artifact, so earlier test/scan/provenance evidence no longer proves the promoted bytes.
For a multi-platform release, why retain child manifest digests?
They let you identify and diagnose the exact platform artifact behind the overall index.
Official references and version notes
-
docker image ls— digest display, local image IDs, and digest-addressed pull/create/run examples. -
docker image inspect— low-level local image metadata, including platform-aware inspection on capable stores. -
docker run— current--pull=missing|always|neversemantics. -
Compose
pull_policy—always,never,missing,build,daily,weekly, andevery_<duration>. - Docker build best practices — pinning base images by digest, controlled updates, and auditability tradeoffs.
-
docker buildx imagetools inspect— registry-side manifest/index and platform inspection. - Image digests — manifest-list/index versus per-platform image digest distinctions.
- OCI Image Index Specification — immutable index descriptors and platform selection.
- OCI Image Manifest Specification — config and layer descriptors addressed by digest.
- Docker Engine 29 release notes — Engine 29.8.1 baseline used when authoring this chapter.
- Buildx releases and BuildKit releases — current build-tool release history.
Version-sensitive statements were rechecked against primary documentation on 2026-09-21. The authoring baseline is Docker Engine 29.8.1, Buildx 0.37.1, BuildKit 0.33.0, and Dockerfile frontend 1.27.0, but every executable lab records the versions and context actually present. Registry tags, platform indexes, local image stores, and Compose behavior can evolve independently; prefer observed digests and current primary documentation over memorized output.
Keep the academy open
Support free, practical DevOps education.
Every lesson is designed to remain readable in a browser, downloadable from GitHub, and usable without a paid learning platform. Contributions help expand and maintain the curriculum.
0x716c4Ab160C4B66F31a28AE2448BfF68fc3a2ef0
Send only Ethereum/ERC-20 compatible assets to this
address.