Skip to main content
RunBook Academy

Git, CI/CD & GitOpsCXII · Container Delivery PipelineRegistryAndDeploy

Registry and deploy — the artefact goes home

Advanced⏱ ~27 mingitdocker

What you'll learn

  • Push the signed image to a registry by digest and tag it for human consumption without pinning production to the tag
  • Land the digest in the rendered manifest (Helm values, Kustomize overlay) so the cluster pulls by digest
  • Recognise that promotion between environments is digest promotion, not rebuild
  • Roll back by reverting the manifest commit; the registry and the signature remain intact

Prerequisites

Verified against Git 2.55.x teaching target; 2.40+ minimum · GitHub Actions continuous service; Aug 2026 documentation baseline · Argo CD v3.5.x teaching target; v3.0+ minimum · Flux v2.9.x · Sigstore Cosign v3.1.x · SLSA v1.2 · OCI Distribution Specification v1.1 · Git LFS v3.7.1 · Kubernetes (cross-course target) 1.36.x

Not yet marked complete on this device.

The final stage of the container delivery pipeline takes the signed, attested image and places it where the cluster can find it. The image is pushed to a registry by digest; the digest lands in the rendered manifest; the GitOps controller syncs the cluster. Promotion between environments is digest promotion - the same blob moves from staging to production without a rebuild. Rollback is a manifest revert that keeps the registry entry and the signature intact. The chain from commit to running pod is closed.

The registry as the chain endpoint

The registry is the durable home of the image, the signature, and the attestations. The OCI distribution specification models all three as content-addressed blobs:

flowchart LR
    A["Image digest sha256:8a3f..."] --> B["registry.example.com/app@sha256:8a3f..."]
    A --> C["Signature"]
    A --> D["SBOM attestation"]
    A --> E["Vuln report attestation"]
    B --> F["Tag app:8a3f9d2 (alias)"]
    B --> G["Tag app:v3.2.7 (alias)"]

The push writes the image blob and its attestations under the same digest. The tags are mutable pointers; the digest is the immutable identifier. Two manifests, two environments, one blob: staging and production can reference the same digest without rebuilding.

A registry that is not the cluster’s source of truth breaks the chain. A workflow that pushes to the registry, then applies manifests with kubectl apply from the runner, bypasses the controller and produces a cluster state that the GitOps controller does not know about. The pipeline must push to the registry; the GitOps controller must read from the registry and apply to the cluster.

Pushing the image and landing the digest

The push step:

docker push registry.example.com/app@sha256:$IMAGE_DIGEST
docker tag registry.example.com/app@sha256:$IMAGE_DIGEST \
           registry.example.com/app:$COMMIT_SHA
docker push registry.example.com/app:$COMMIT_SHA

The digest push writes the blob; the tag push writes a pointer for humans. Both are recorded in the registry; the digest is the durable identifier.

The render step lands the digest in the manifest. For Helm, the values file:

image:
  repository: registry.example.com/app
  digest: sha256:8a3f9d2c1e7b6f4a5d9c0e2b1a8f7d6c5b4a3e2d1c0b9a8f7e6d5c4b3a2f1e0d
  tag: v3.2.7

For Kustomize, the image transformer in the overlay:

images:
  - name: app
    digest: sha256:8a3f9d2c1e7b6f4a5d9c0e2b1a8f7d6c5b4a3e2d1c0b9a8f7e6d5c4b3a2f1e0d

Either way, the rendered manifest carries the digest. The GitOps controller reconciles to that manifest; the kubelet pulls that digest. The tag stays as a human-readable alias in the values file but is not what the cluster pulls.

Promotion is digest promotion

The same digest can be promoted from staging to production without rebuilding. The CI job publishes once; the values file or overlay is updated to point to that digest for the next environment:

flowchart LR
    A["CI build at commit 8a3f9d2"] --> B["registry.example.com/app@sha256:8a3f..."]
    B --> C["overlays/staging (digest 8a3f...)"]
    B --> D["overlays/prod (digest 8a3f...)"]
    C --> E["Argo CD sync to staging"]
    D --> F["Argo CD sync to production"]

Two manifests, two environments, one immutable blob. Rebuilding per environment defeats the purpose: a staging build at ${COMMIT_SHA} and a production build at the same commit a few minutes later produce different digests, because build timestamps and layer metadata move between runs. Promote the digest, not the build.

Rollback is a manifest revert

The cluster’s rollback path is the GitOps controller’s revert. The manifest that pointed at digest B is reverted to point at digest A; the controller reconciles; the kubelet pulls digest A again. The registry still holds both digests; the signatures still cover both; the attestations still describe both.

git revert --no-edit HEAD~1
git push origin main

The cluster rollback is a Git operation. The image rollback is no operation - the digest has not changed, the blob is still in the registry, the signature is still valid. The cluster’s desired state changes; the registry’s content does not.

A rollback that requires a rebuild is a rollback that has lost the chain. The image that the cluster is rolling back to is a different image than the one it rolled back from; the attestations do not carry forward; the audit trail splits.

What this stage does not do

The registry-and-deploy stage closes the chain. It does not:

  • Rebuild the image. The build is a single, per-commit operation; promotion is digest promotion, not rebuild.
  • Rotate signing keys. Key rotation is a separate, scheduled operation.
  • Trigger the test stage. Tests run earlier in the chain, gated on the source commit.
  • Audit past deployments. The attestations on the digest are the audit trail; audits consume them, they do not write them.

Production discipline

  1. Push by digest, tag for humans. The push writes the digest; the tag is an alias for humans; the manifest keys off the digest.
  2. Render manifests in CI, not on the runner. The rendered manifest is an artefact that lives in Git; the values file that lands the digest is committed, reviewed, and versioned.
  3. Promote by digest, not by build. Updating the values file or overlay to point at the existing digest moves the same artefact to the next environment.
  4. Roll back by reverting the manifest, not by rebuilding. The digest is still in the registry; the signature still covers it; a Git revert restores it.
  5. Verify in the admission controller on every pull. The signature is metadata until something checks it; the admission controller is the check.

Cross-course references

  • This course, Part CXI (KubernetesDelivery) - covers the GitOps sync and reconcile loop on the cluster side.
  • This course, Part XLV (ImmutableIdentity) - covers content addressing and digest promotion across environments.
  • Container Security for Production Sysadmins - Parts VII-VIII cover admission control, the verifier side of the deploy.

Quiz

Knowledge check · 4 questions

  1. Q1. A team rebuilds the same commit per environment - once for staging, once for production - and references the resulting images by tag. What is the failure mode?

  2. Q2. Rolling back a deployment that references a digest by reverting the manifest commit does not require a rebuild and does not change the registry contents.

  3. Q3. Name the three things that the registry stores under the same digest, and identify which one is the durable identifier the pipeline keys off.

  4. Q4. Diagnose a deployment where the manifest references a tag instead of a digest, and prescribe the fix.

    A team deploys a container application. The CI builds, signs, and pushes the image with the tag `registry.example.com/app:v3.2.7`. The values file references `tag: v3.2.7`. The cluster pulls and runs. The team later publishes v3.2.7-hotfix1 under the same tag `v3.2.7` (the team reuses tags across releases). The next sync pulls the new digest under the same tag without a manifest change. Production is running a digest no one reviewed.

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