Registry and Release Workflow
A registry is not just a place to push images. It is part of the release system. A good workflow makes every deployed image traceable, immutable, scannable, and easy to roll back.
Name images consistently
Use a stable repository name and clear tags.
1registry.example.com/team/api:<git-sha>
2registry.example.com/team/api:1.4.2
3registry.example.com/team/api:main
4registry.example.com/team/api:latest
Use immutable tags for release records.
Commit SHA tags are good deployment records.
Semantic version tags are good human release records.
Branch tags are convenient for development environments.
latestis only a moving convenience pointer.
Tag and push
Build and push with Buildx.
1export IMAGE=registry.example.com/team/api
2export GIT_SHA="$(git rev-parse --short HEAD)"
3
4docker buildx build \
5 --platform linux/amd64,linux/arm64 \
6 -t "${IMAGE}:${GIT_SHA}" \
7 -t "${IMAGE}:latest" \
8 --push .
Record the digest
Deployments should record the digest, not just the tag.
1docker buildx imagetools inspect "${IMAGE}:${GIT_SHA}"
The digest form is the immutable artifact reference.
1registry.example.com/team/api@sha256:<digest>
Promotion
Promote the same image between environments. Do not rebuild separately for staging and production unless the build inputs are intentionally different.
1build once -> scan -> deploy to dev -> deploy same digest to staging -> deploy same digest to production
Promotion can be implemented by updating deployment manifests to point at the same digest or by copying the image into environment-specific repositories.
Registry policy
Use registry controls that match the risk of the environment.
Authenticate every push.
Restrict push access to CI or release automation.
Make production tags immutable.
Scan images on push and rescan when vulnerability data changes.
Retain release tags and digests longer than branch and cache tags.
Separate development and production repositories or accounts when access boundaries matter.
Keep SBOM and provenance attestations with release images.
Rollback
Rollback by digest when possible.
1registry.example.com/team/api@sha256:<previous-digest>
This avoids the ambiguity of a mutable tag. The deployment history should answer these questions quickly:
Which digest is running?
Which source commit created that digest?
Which Dockerfile and build target created it?
Which SBOM, scan report, and provenance attestation belong to it?
Which previous digest is known-good?
CI example
1set -euo pipefail
2
3IMAGE="registry.example.com/team/api"
4GIT_SHA="$(git rev-parse --short HEAD)"
5
6docker buildx build \
7 --platform linux/amd64,linux/arm64 \
8 --cache-from type=registry,ref="${IMAGE}:buildcache" \
9 --cache-to type=registry,ref="${IMAGE}:buildcache",mode=max \
10 --sbom=true \
11 --provenance=true \
12 -t "${IMAGE}:${GIT_SHA}" \
13 --push .
14
15docker buildx imagetools inspect "${IMAGE}:${GIT_SHA}"
Practical rules
Build once and promote the same digest.
Treat
latestas optional metadata, not the deployment source of truth.Keep cache tags separate from release tags.
Use immutable release tags.
Store release metadata with the deployment.
Prefer digest references for production rollback.