Checkpoint Lab — Registries, Docker Hub, Private Registries, Authentication, Credential Stores, Push/Pull, and Distribution
Publish and retrieve a disposable image through a local registry, capture digest/auth/TLS assumptions and distribution evidence, prove a digest-addressed pull after local deletion, and clean only the Chapter 14 lab resources.
Learning objectives
- Produce a complete evidence packet tying source/build identity to pushed repository digest, registry evidence, digest-addressed retrieval, and runtime output.
- Record actual Engine/CLI/Compose/Buildx/BuildKit/Registry assumptions plus the loopback HTTP/no-auth limitation.
- Predict registry/local-store changes before execution and verify each prediction independently.
- Demonstrate optional fake credential handling without archiving auth material.
- Clean only labeled checkpoint resources and bridge the resulting distribution model into Docker Compose.
1. Setup and assumptions
This checkpoint uses only local, free resources. It intentionally does not require Docker Hub, a cloud registry, enterprise identity, or administrator changes to daemon trust. The current authoring baseline is Engine 29.8.1, Buildx 0.37.1, BuildKit 0.33.0, Dockerfile frontend 1.27.0, Compose 5.5.1, Distribution Registry 3.1.1, and OCI Distribution Spec 1.1.1. Your evidence must record what is actually installed.
set -eu
LAB="$HOME/devops-academy-ch14-checkpoint"
EVIDENCE="$LAB/evidence"
APP="$LAB/app"
REGISTRY="127.0.0.1:5000"
REPO="devops-academy/ch14-checkpoint"
REGISTRY_CONTAINER="da-ch14-checkpoint-registry"
REGISTRY_VOLUME="da-ch14-checkpoint-registry-data"
mkdir -p "$EVIDENCE" "$APP"
docker version | tee "$EVIDENCE/docker-version.txt"
docker info | tee "$EVIDENCE/docker-info.txt"
docker context show | tee "$EVIDENCE/context.txt"
docker buildx version | tee "$EVIDENCE/buildx-version.txt"
docker compose version | tee "$EVIDENCE/compose-version.txt"
docker ps -a --filter name="^/${REGISTRY_CONTAINER}$"
docker volume ls --filter name="^${REGISTRY_VOLUME}$"
2. Write predictions before changing state
Record at least these two predictions in
$EVIDENCE/predictions.txt before running the lab:
- Prediction A: after the push, the registry repository will have a manifest/tag and content blobs, while the local image will gain a repository-qualified digest association.
-
Prediction B: after local references are removed,
pulling
repository@digestwill restore the same immutable registry content even though the human tag is not required. - Prediction C: removing the registry container but retaining its labeled volume would preserve registry content; removing both will delete only this lab's registry state.
The point is to compare expectation with evidence instead of interpreting success after the fact.
3. Resolve and start the exact disposable registry
docker pull registry:3.1.1 | tee "$EVIDENCE/registry-pull.txt"
docker image inspect registry:3.1.1 \
--format 'ID={{.Id}} RepoDigests={{json .RepoDigests}}' \
| tee "$EVIDENCE/registry-image.txt"
docker volume create --label devops-academy.lab=ch14-checkpoint "$REGISTRY_VOLUME"
docker run -d \
--name "$REGISTRY_CONTAINER" \
--label devops-academy.lab=ch14-checkpoint \
-p 127.0.0.1:5000:5000 \
-v "$REGISTRY_VOLUME:/var/lib/registry" \
registry:3.1.1
docker inspect "$REGISTRY_CONTAINER" \
--format 'ID={{.Id}} Status={{.State.Status}} Ports={{json .NetworkSettings.Ports}} Mounts={{json .Mounts}}' \
| tee "$EVIDENCE/registry-state.txt"
4. Create deterministic synthetic source and build it
cat > "$APP/message.txt" <<'EOF'
academy=DevOps Academy
chapter=14
checkpoint=registry-distribution
release=1.0.0
EOF
cat > "$APP/Dockerfile" <<'EOF'
# syntax=docker/dockerfile:1
FROM busybox:1.37.0
LABEL devops-academy.lab="ch14-checkpoint"
WORKDIR /opt/checkpoint
COPY message.txt ./message.txt
CMD ["cat", "/opt/checkpoint/message.txt"]
EOF
( cd "$APP" && sha256sum Dockerfile message.txt ) \
| tee "$EVIDENCE/source-sha256.txt"
docker buildx build --load --progress=plain \
-t da-ch14-checkpoint:1.0.0 "$APP" \
2>&1 | tee "$EVIDENCE/build.log"
docker image inspect da-ch14-checkpoint:1.0.0 \
--format 'ID={{.Id}} Created={{.Created}} User={{.Config.User}} RepoDigests={{json .RepoDigests}}' \
| tee "$EVIDENCE/pre-push-image.txt"
5. Publish one tag and preserve the immutable digest
REF="$REGISTRY/$REPO:1.0.0"
docker image tag da-ch14-checkpoint:1.0.0 "$REF"
docker push "$REF" 2>&1 | tee "$EVIDENCE/push.log"
DIGEST=$(grep -Eo 'sha256:[0-9a-f]{64}' "$EVIDENCE/push.log" | tail -n 1)
test -n "$DIGEST"
printf '%s\n' "$DIGEST" | tee "$EVIDENCE/pushed-digest.txt"
docker image inspect "$REF" \
--format 'ID={{.Id}} RepoDigests={{json .RepoDigests}}' \
| tee "$EVIDENCE/post-push-image.txt"
Do not promote the push log itself as the artifact. Promote the digest it proves.
6. Preserve registry-side and protocol evidence
# Optional if curl is installed.
if command -v curl >/dev/null 2>&1; then
curl -fsS "http://$REGISTRY/v2/_catalog" \
| tee "$EVIDENCE/catalog.json"
curl -fsS "http://$REGISTRY/v2/$REPO/tags/list" \
| tee "$EVIDENCE/tags.json"
curl -fsSI \
-H 'Accept: application/vnd.oci.image.manifest.v1+json, application/vnd.docker.distribution.manifest.v2+json' \
"http://$REGISTRY/v2/$REPO/manifests/1.0.0" \
| tee "$EVIDENCE/manifest-head.txt"
fi
docker logs "$REGISTRY_CONTAINER" 2>&1 \
| tail -n 160 \
| tee "$EVIDENCE/registry-requests.log"
7. Record authentication and TLS assumptions without inventing protection
Create $EVIDENCE/assumptions.txt and state explicitly:
-
Registry endpoint is loopback-only
127.0.0.1:5000. - The lab uses HTTP/no registry-side authentication as a bounded local simulation.
- No production credential is used.
- The client-side fake login exercise, if performed, demonstrates storage/logout behavior only; it does not add authorization to the registry.
- Production/shared registries require trusted TLS and appropriate access control; do not generalize the loopback exception.
This limitation note is part of the evidence packet, not an embarrassment to hide.
8. Delete local references and prove retrieval by digest
docker image rm "$REF" da-ch14-checkpoint:1.0.0
PINNED="$REGISTRY/$REPO@$DIGEST"
docker pull "$PINNED" 2>&1 | tee "$EVIDENCE/pull-by-digest.log"
docker image inspect "$PINNED" \
--format 'ID={{.Id}} RepoDigests={{json .RepoDigests}} Architecture={{.Architecture}} OS={{.Os}}' \
| tee "$EVIDENCE/retrieved-image.txt"
docker run --rm "$PINNED" | tee "$EVIDENCE/runtime-output.txt"
Compare the digest in the pull output and
RepoDigests with pushed-digest.txt. This
independently verifies Prediction B.
9. Optional fake credential handling evidence
export DOCKER_CONFIG="$LAB/fake-docker-config"
mkdir -p "$DOCKER_CONFIG"
printf '%s\n' 'fake-local-password' \
| docker login "$REGISTRY" --username localstudent --password-stdin \
| tee "$EVIDENCE/fake-login.txt"
test -s "$DOCKER_CONFIG/config.json" && echo 'client config exists'
docker logout "$REGISTRY" | tee "$EVIDENCE/fake-logout.txt"
unset DOCKER_CONFIG
Do not include the generated config file in the evidence archive. Even fake examples train the right habit: evidence records the method and result, not secret material.
10. Verification checklist
- Tool/context versions are recorded.
- Registry 3.1.1 tag and its resolved RepoDigest are recorded.
- Registry is loopback-only and labeled for Chapter 14.
- Source hashes and build log are present.
- Push output yielded an immutable digest.
- Local image references were removed before the digest pull.
- Pulled RepoDigest matches the pushed digest.
- Runtime output matches the synthetic source.
- Registry logs/API evidence are retained without auth headers/tokens.
- Auth/TLS limitations are explicitly documented.
11. Evidence packet and review
printf '%s\n' \
'docker-version.txt' 'docker-info.txt' 'context.txt' \
'buildx-version.txt' 'compose-version.txt' \
'registry-image.txt' 'registry-state.txt' \
'source-sha256.txt' 'build.log' 'pre-push-image.txt' \
'push.log' 'pushed-digest.txt' 'post-push-image.txt' \
'registry-requests.log' 'pull-by-digest.log' \
'retrieved-image.txt' 'runtime-output.txt' 'assumptions.txt' \
| tee "$EVIDENCE/expected-files.txt"
ls -lah "$EVIDENCE"
Review the packet before sharing it. Remove host-specific information that is unnecessary for the audience, but do not delete the object IDs/digests/timestamps needed to support your claims.
12. Cleanup and rollback with exact guards
# Verify ownership label before force-removing the disposable registry.
LABEL=$(docker inspect -f '{{ index .Config.Labels "devops-academy.lab" }}' "$REGISTRY_CONTAINER")
[ "$LABEL" = 'ch14-checkpoint' ]
docker container rm -f "$REGISTRY_CONTAINER"
docker volume rm "$REGISTRY_VOLUME"
docker image rm "$REGISTRY/$REPO@$DIGEST" 2>/dev/null || true
docker image rm "$REGISTRY/$REPO:1.0.0" da-ch14-checkpoint:1.0.0 2>/dev/null || true
docker ps -a --filter label=devops-academy.lab=ch14-checkpoint
docker volume ls --filter label=devops-academy.lab=ch14-checkpoint
Do not run a broad system/image/volume prune. The evidence directory is intentionally left on disk until review is complete.
13. What this adds to the production operating model
Chapter 14 turns image identity into a distribution discipline: authenticated/scoped registry access, trusted transport, immutable digest evidence, content-aware blob transfer, provider/retention awareness, and exact consumer verification. You can now distinguish “built,” “pushed,” “tagged,” “digest verified,” “pulled,” and “running” as separate states.
Chapter 15 builds on this by introducing Docker Compose, where multiple services, images, networks, volumes, environment values, and a project lifecycle must be coordinated without losing those identity and trust boundaries.
Knowledge check
What evidence proves the checkpoint retrieved the same immutable release after local deletion?
The pull-by-digest reference resolves successfully and the resulting RepoDigest/pull digest matches the digest captured from the original push.
Why must assumptions.txt say the registry is
loopback HTTP/no-auth?
So the evidence does not misrepresent a development simulation as a production TLS/auth design.
What does the registry volume prove in the checkpoint?
It makes registry storage a separately identifiable resource with an explicit lifecycle, independent of the container object.
Why keep the evidence directory after Docker cleanup?
The Docker resources are disposable, but the learning/audit evidence is needed to verify predictions and explain what occurred.
What Chapter 15 concept becomes easier after this checkpoint?
Compose can coordinate multiple service image references while you preserve exact registry/digest identity and distinguish pull from container/project lifecycle.
Official references and version notes
-
docker login— authentication,--password-stdin, Docker Desktop native keychains,credsStore, and per-registrycredHelpers. -
docker image push— repository naming, layer reuse, push progress, and digest output. -
docker image pull— pull-by-tag versus pull-by-digest and registry-qualified references. - Registry certificates — platform-specific CA/client-certificate configuration and TLS verification.
- Docker daemon: insecure registries — why plaintext/untrusted registries are testing-only and why trusted CA configuration is preferred.
- Docker Hub pull usage and limits — current rate-limit behavior and authentication attribution.
- CNCF Distribution Registry — current Registry v3 documentation and local-registry workflow.
-
Registry v2 token authentication
—
401challenge, token service, repository scope, Bearer token, and retry flow. - Distribution HTTP API V2 — manifests, blobs, uploads, errors, and digest-addressed operations.
- Deploying Distribution Registry — local development registry, production TLS/auth expectations, and storage.
- Registry garbage collection — shared blobs, reference-aware deletion, mark/sweep behavior, and read-only guidance.
- OCI Distribution Specification v1.1.1 — latest OCI Distribution Specification release used as the standards baseline.
- Distribution Registry v3.1.1 — current stable registry release used as the local-lab baseline.
- Docker Engine 29 release notes — Engine 29.8.1 baseline used when authoring this chapter.
- Buildx releases, BuildKit releases, and Compose releases — current build/orchestration 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, Dockerfile frontend 1.27.0, Compose 5.5.1, CNCF Distribution Registry 3.1.1, and OCI Distribution Specification 1.1.1. The executable labs still record the versions, context, image digests, registry endpoint, and credential/TLS assumptions actually present. Docker Hub limits and hosted-registry policies are service policy and can change independently of the Docker Engine.
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.
0x716c4Ab160C4B66F31a28AE2448BfF68fc3a2ef0Send only Ethereum/ERC-20 compatible assets to this
address.