Pinning base image digests with SHA256
A tag like node:20 is a moving pointer — the registry can repoint it to a new build at any time, so two docker pulls a month apart can yield different images and break reproducibility silently. Pinning to the immutable @sha256:... digest makes the base image byte-identical forever. This page shows how to find, pin, and maintain digests. It extends the Container Registry Best Practices for Dev Images cluster.
Prerequisites
- Docker Engine 24+ or a compatible runtime
- Pull access to the registry hosting the base image
How-To Steps
-
Resolve the digest for the tag you currently use:
docker pull node:20-bookworm docker inspect --format '{{ index .RepoDigests 0 }}' node:20-bookworm # e.g. node@sha256:3f9a...c1 -
Pin the digest in
devcontainer.json, keeping the human-readable tag as a comment in your docs:{ "image": "node:20-bookworm@sha256:3f9a...c1", "remoteUser": "node" } -
Pin in the Dockerfile
FROMwhen you build your own image:FROM node:20-bookworm@sha256:3f9a...c1 -
Pin Features too — they are OCI artifacts with digests:
{ "features": { "ghcr.io/devcontainers/features/node@sha256:7b2e...": { "version": "20" } } } -
Verify the running image matches the pin:
devcontainer exec --workspace-folder . sh -c 'cat /etc/os-release | head -1' docker inspect --format '{{.Image}}' "$(docker ps -ql)" # matches the pinned digest
Common Pitfalls
| Symptom | Root Cause | Remediation |
|---|---|---|
| Build differs across machines/time | Floating tag repointed by the registry | Pin @sha256: digest |
| Digest pull fails | Digest garbage-collected from the registry | Mirror critical images to your own registry |
| Security scan flags old base | Digest pinned and never refreshed | Schedule a controlled digest-bump PR |
| Multi-arch pull picks wrong arch | Pinned a single-arch digest | Pin the manifest-list digest instead |
Conclusion
The invariant: every base reference — image, Dockerfile FROM, and Features — is pinned to a SHA256 digest, so the environment is byte-reproducible. Pinning is not “set and forget”: pair it with a scheduled, reviewed digest-bump so you stay reproducible and patched.
FAQ
Doesn’t pinning prevent security updates? It prevents silent ones. You still update — through a deliberate PR that bumps the digest, so the change is reviewed and reproducible rather than arriving unannounced.
Can I pin a multi-arch image by digest? Yes — pin the manifest-list digest. The runtime still selects the correct per-architecture image beneath it, as covered in multi-architecture builds.
Related
- Container Registry Best Practices for Dev Images — the parent cluster.
- Choosing between Alpine and Debian base images — which base to pin.
- Multi-Architecture Builds for ARM & x86 — pinning manifest-list digests.