Skip to main content
RunBook Academy

KubernetesCXV · Image Registry OperationsImage registry operations

Tag vs digest strategy — immutability and reproducibility

Advanced⏱ ~17 minkubectldocker

What you'll learn

  • Use tags for development and digests for production
  • Pull images by digest for reproducibility
  • Reason about the immutability vs convenience trade-off
  • Apply the operational discipline of pinning digests in production

Prerequisites

Verified against Kubernetes 1.34.x · kubeadm 1.34.x · kubectl 1.34.x · etcd 3.6.x · CoreDNS 1.11.x · containerd 1.7.x / 2.x · 2026-08-16

Not yet marked complete on this device.

Tag vs digest is the immutability vs convenience trade-off in image references. This lesson walks tags, digests, the trade-offs, the recommendation, and the discipline.

Tags vs digests

flowchart LR
    A[Image references] --> B[Tags]
    A --> C[Digests]
    B --> B1["Mutable: myapp:1.2.3"]
    B --> B2["myapp:latest"]
    C --> C1["Immutable: myapp@sha256:abc..."]
    C --> C2[Specific bytes]

Tags vs digests:

  • Tags. Mutable; a re-push can change the contents. e.g., myapp:1.2.3 may refer to different bytes over time.
  • Digests. Immutable; SHA256 hash of the image manifest. e.g., myapp@sha256:abc... always refers to the same bytes.

Pulling by digest

# Get the digest of an image
docker inspect --format='{{index .RepoDigests 0}}' \
  myapp:1.2.3

# Output: myapp@sha256:abc123...

# Pull by digest
docker pull myapp@sha256:abc123...

The digest is the SHA256 hash of the image manifest. The hash is computed by the registry at push time and never changes.

Using digests in Kubernetes

apiVersion: apps/v1
kind: Deployment
metadata:
  name: myapp
spec:
  template:
    spec:
      containers:
        - name: app
          image: registry.example.com/myapp@sha256:abc123...
          imagePullPolicy: IfNotPresent

The Pod references the image by digest. The kubelet pulls the exact bytes identified by the digest.

# Track image versions via digest
sum by (image) (kube_pod_container_info)

The trade-offs

flowchart LR
    A[Tags] --> B[+ Convenient]
    A --> C["- Mutable: surprises"]
    D[Digests] --> E["+ Immutable: reproducible"]
    D --> F[- Hard to read]
    D --> G[- More verbose]

The trade-offs:

Tags:

  • Pros: Convenient; human-readable; CI/CD workflows are familiar.
  • Cons: Mutable; a re-push can change the bytes; surprises.

Digests:

  • Pros: Immutable; reproducible; exact bytes.
  • Cons: Hard to read (long SHA256 strings); more verbose in YAML.

The recommendation

flowchart LR
    A[Recommendation] --> B["Development: tags"]
    A --> C["Production: digests"]
    B --> B1[Convenient for iteration]
    C --> C1[Reproducible for safety]
    C --> C2[Combined with semantic version tags]

The recommendation:

  • Development. Tags are convenient; iteration is fast.
  • Production. Digests ensure the exact bytes deployed; combined with semantic version tags (:1.2.3 becomes @sha256:abc... with a comment referencing the tag).
# Production: digest + comment with tag
containers:
  - name: app
    # 1.2.3
    image: registry.example.com/myapp@sha256:abc123...

The comment documents the version; the digest ensures reproducibility.

The CI/CD workflow

flowchart LR
    A["CI: build image"] --> B[Push to registry]
    B --> C[Get digest]
    C --> D[Update manifest with digest]
    D --> E[Commit to Git]
    E --> F[Argo CD syncs]

The workflow:

  1. CI builds the image.
  2. CI pushes the image to the registry.
  3. CI queries the digest (docker inspect or registry API).
  4. CI updates the Kubernetes manifest with the digest.
  5. CI commits the updated manifest to Git.
  6. Argo CD (or Flux) syncs the manifest.

The digest is captured at push time and stored in Git; the cluster always pulls the exact bytes.

Quiz

Knowledge check · 4 questions

  1. Q1. What does deploying by digest guarantee that a version tag does not?

  2. Q2. Deploying by digest removes the need for image signing and verification.

  3. Q3. Establish why a rollback returned the same faulty build, and pin the deployment to the bytes you meant.

    `kubectl -n prod-app rollout undo deployment/checkout` completed and the Pods came back on the previous ReplicaSet, but the fault is unchanged. `kubectl rollout history deployment/checkout --revision=8` shows image `registry.example.com/checkout:2.4.0`, while `kubectl -n prod-app get pods -o jsonpath='{..imageID}'` reports the same digest as the faulty 2.4.1 build. The registry's tag history shows `2.4.0` was pushed twice, the second time during last night's hotfix.

  4. Q4. What does the CI pipeline write into the manifest after pushing an image so the deployment is reproducible, and where does it obtain that value?

Passing score: 75%. Answers are checked in this browser.

The operational discipline

Tag vs digest in production rests on five non-negotiable elements:

  • Pin digests in production. Reproducibility; defence against tag mutation.
  • Comment with the tag. Human readability.
  • Automate digest capture in CI. Manual capture is error-prone.
  • Test the digest pinning. Verify the deployment pulls the expected bytes.
  • Document the strategy. In the runbook: tags for dev, digests for prod.

Tag vs digest is the immutability vs convenience trade-off. The discipline is digests for production with CI/CD automation.