Chapter 11Lesson 05~145 minutes

Checkpoint Lab — Build Cache, Cache Mounts, Bind Mounts, Secret Mounts, SSH Mounts, and Cache Import/Export

The checkpoint builds a small dependency-using application on an isolated builder, measures cold/warm behavior, proves secret and SSH inputs remain ephemeral, exports a local external cache, imports it into a fresh builder, and records whether the clean builder reuses cache without treating cache as release identity.

Checkpoint labFresh builderCache import/exportEvidence packetChapter 12 bridge

Learning objectives

  • Capture a complete cold/warm/fresh-builder cache timeline with exact Buildx, BuildKit, frontend, builder, source, and output evidence.
  • Prove that a fake secret and an SSH agent are available only to the intended RUN step and do not appear in the final image configuration/history.
  • Export local cache from one isolated builder, import it into another, and identify which vertices are reused without assuming the image was already loaded.
  • Verify that the application output is identical across cached and uncached paths while cache directories remain disposable performance state.
  • Produce a concise cache trust dossier and bridge naturally to Chapter 12 multi-platform build behavior.
Chapter 11 evidence baseline — verified 2026-09-21. Mandatory exercises use only synthetic source/data, a fake token, an ephemeral local SSH identity, isolated chapter-owned Buildx builders, a local cache directory, and public base images. At verification time Docker Engine 29.8.1, Buildx 0.37.1, and BuildKit 0.33.0 with built-in Dockerfile frontend 1.27.0 are the current course baselines, but every lab records the actual installed versions, builder driver, worker platform, and frontend behavior. Docker currently documents bind/cache/secret/SSH RUN mounts; cache sharing modes shared/private/locked; secret values excluded from cache checksum; and local/inline/registry/GHA cache backends with driver-dependent support. Cache is never treated as release identity, and no real credentials, production registry, production daemon, or broad prune operation is required.

1. Checkpoint scenario and success criteria

You are preparing an ephemeral CI build design. Dependency downloads are expensive, builders may be short-lived, and the release path must remain explainable when cache is absent. The checkpoint therefore treats cache as optional performance state, keeps secret and SSH material ephemeral, and proves that a fresh builder can reuse a trusted external cache without confusing that cache with release identity.

Your deliverable is an evidence packet. Success means you can explain four independent states: internal instruction/result cache, mutable package cache, ephemeral sensitive mounts, and external cache import/export. You must also prove that application behavior remains correct and that the final output identity is captured independently of cache identity.

2. Write predictions before execution

Create evidence/00-predictions.txt before building. Include at least these predictions:

  1. The first build on a new builder executes dependency and application vertices.
  2. An unchanged second build reports instruction/result cache hits and should execute less work.
  3. If only application source changes, the dependency-install result should remain reusable because the requirements input did not change.
  4. The fake secret and SSH agent are accessible only to their intended RUN vertices and are absent from runtime state.
  5. A second fresh builder can reuse the exported local cache even though it starts without the original builder’s internal cache.
  6. The final image/OCI output identity is evidence distinct from the cache directory itself.

Afterward, mark each prediction confirmed, rejected, or qualified. Do not rewrite predictions to match the outcome.

3. Preflight and exact assumptions

mkdir -p ch11-checkpoint/{evidence,cache}
cd ch11-checkpoint

docker version | tee evidence/01-docker-version.txt
docker context show | tee evidence/02-context.txt
docker buildx version | tee evidence/03-buildx-version.txt
docker buildx ls | tee evidence/04-builders-before.txt

docker buildx create \
  --name devops-academy-ch11-checkpoint \
  --driver docker-container \
  --use

docker buildx inspect --bootstrap \
  | tee evidence/05-builder.txt

Record BuildKit version, driver, endpoint, and worker platform. If Docker or Buildx is unavailable, use the static simulation path: produce the Dockerfile, expected state transitions, and evidence schema while marking live IDs/digests/timings as not observed.

4. Create synthetic source and fake sensitive input

cat > requirements.txt <<'REQ'
requests==2.32.5
REQ

cat > app.py <<'PYAPP'
import requests
print("chapter11-checkpoint", requests.__version__)
PYAPP

printf '%s\n' 'checkpoint-fake-secret-v1' > fake-secret.txt
printf '%s\n' 'bind-input-v1' > bind-input.txt

sha256sum requirements.txt app.py bind-input.txt \
  | tee evidence/06-inputs-sha256.txt

The exercise pins the Python package version for stable teaching, but a production build would also record package hashes/index identity, exact base-image digest, platform, and source revision.

5. Dockerfile with cache, bind, secret, and SSH mounts

# syntax=docker/dockerfile:1
FROM python:3.13-alpine AS build
WORKDIR /src

COPY requirements.txt .
RUN --mount=type=cache,id=ch11-checkpoint-pip,target=/root/.cache/pip,sharing=locked \
    pip install --prefix=/install -r requirements.txt

RUN --mount=type=bind,source=bind-input.txt,target=/mnt/input.txt,ro \
    sha256sum /mnt/input.txt > /bind-input.sha256

RUN --mount=type=secret,id=demo,required=true \
    test -s /run/secrets/demo && echo secret-ok > /secret-status

RUN --mount=type=ssh,required=true \
    test -n "$SSH_AUTH_SOCK" && test -S "$SSH_AUTH_SOCK" && echo ssh-ok > /ssh-status

COPY app.py .

FROM python:3.13-alpine
COPY --from=build /install /usr/local
COPY --from=build /src/app.py /app.py
COPY --from=build /bind-input.sha256 /evidence/bind-input.sha256
COPY --from=build /secret-status /evidence/secret-status
COPY --from=build /ssh-status /evidence/ssh-status
USER 65532:65532
ENTRYPOINT ["python", "/app.py"]
sha256sum Dockerfile | tee evidence/07-dockerfile-sha256.txt

Only intentional non-secret outputs cross into the runtime image. The package cache, bind source, secret file, and SSH socket do not.

6. Create a disposable SSH-agent identity

eval "$(ssh-agent -s)"
ssh-keygen -q -t ed25519 -N '' -f ./checkpoint_key
ssh-add ./checkpoint_key
ssh-add -l | tee evidence/08-ssh-agent.txt

No remote connection occurs. The agent exists only to prove that BuildKit can mount an SSH agent socket for one RUN. If OpenSSH tooling is unavailable, mark live SSH evidence not observed and complete the rest of the checkpoint.

7. Cold build and local cache export

START=$(date +%s)
docker buildx build \
  --builder devops-academy-ch11-checkpoint \
  --progress=plain \
  --secret id=demo,src=fake-secret.txt \
  --ssh default="$SSH_AUTH_SOCK" \
  --cache-to type=local,dest=cache,mode=max \
  --metadata-file evidence/09-cold-metadata.json \
  --load \
  -t devops-academy-ch11-checkpoint:app \
  . 2>&1 | tee evidence/09-cold-build.txt
END=$(date +%s)
printf 'cold_seconds=%s\n' "$((END-START))" \
  | tee evidence/10-cold-time.txt

Record which vertices execute and which external resources are contacted. The cache directory is an optimization artifact; the locally loaded image is a separate result.

8. Warm build with no source changes

START=$(date +%s)
docker buildx build \
  --builder devops-academy-ch11-checkpoint \
  --progress=plain \
  --secret id=demo,src=fake-secret.txt \
  --ssh default="$SSH_AUTH_SOCK" \
  --load \
  -t devops-academy-ch11-checkpoint:app \
  . 2>&1 | tee evidence/11-warm-build.txt
END=$(date +%s)
printf 'warm_seconds=%s\n' "$((END-START))" \
  | tee evidence/12-warm-time.txt

Count cached and executed vertices from plain progress. Timing is supporting evidence, not the sole proof, because host CPU/disk/network contention can change between runs.

9. Change only application source

cat > app.py <<'PYAPP'
import requests
print("chapter11-checkpoint-v2", requests.__version__)
PYAPP
sha256sum app.py | tee evidence/13-app-v2-sha256.txt

docker buildx build \
  --builder devops-academy-ch11-checkpoint \
  --progress=plain \
  --secret id=demo,src=fake-secret.txt \
  --ssh default="$SSH_AUTH_SOCK" \
  --load -t devops-academy-ch11-checkpoint:app-v2 \
  . 2>&1 | tee evidence/14-source-change-build.txt

The dependency-install vertex should remain reusable because requirements.txt and earlier inputs did not change. If it executes, inspect the log and input identities before concluding cache malfunction.

10. Verify runtime and sensitive-input boundaries

docker run --rm devops-academy-ch11-checkpoint:app-v2 \
  | tee evidence/15-runtime.txt

docker image inspect devops-academy-ch11-checkpoint:app-v2 \
  --format 'ID={{.Id}} User={{.Config.User}} Env={{json .Config.Env}}' \
  | tee evidence/16-image-inspect.txt

docker image history --no-trunc devops-academy-ch11-checkpoint:app-v2 \
  | tee evidence/17-history.txt

docker run --rm --entrypoint /bin/sh devops-academy-ch11-checkpoint:app-v2 -c \
  'test ! -e /run/secrets/demo; test -z "$SSH_AUTH_SOCK"; ls -l /evidence; cat /evidence/*' \
  | tee evidence/18-sensitive-boundary.txt

Search the captured history/configuration for the literal fake secret. The runtime should contain only secret-ok and ssh-ok status files—not secret bytes, private keys, or an agent socket.

11. Import cache into a fresh builder

docker buildx create \
  --name devops-academy-ch11-checkpoint-fresh \
  --driver docker-container

docker buildx inspect devops-academy-ch11-checkpoint-fresh --bootstrap \
  | tee evidence/19-fresh-builder.txt

START=$(date +%s)
docker buildx build \
  --builder devops-academy-ch11-checkpoint-fresh \
  --progress=plain \
  --secret id=demo,src=fake-secret.txt \
  --ssh default="$SSH_AUTH_SOCK" \
  --cache-from type=local,src=cache \
  --metadata-file evidence/20-fresh-metadata.json \
  --output type=oci,dest=app-fresh.oci.tar \
  . 2>&1 | tee evidence/20-fresh-build.txt
END=$(date +%s)
printf 'fresh_seconds=%s\n' "$((END-START))" \
  | tee evidence/21-fresh-time.txt

Because the new builder had no internal history, reused vertices demonstrate external cache import. Because the output is an OCI tar, do not claim it is automatically a runnable local tag.

12. Required evidence packet

Evidence What it proves
Docker/context/Buildx/builder capture Exact execution context, driver, BuildKit version, worker platform.
Dockerfile/source hashes Declared input identity.
Cold/warm/source-change logs Which vertices executed or reused internal cache.
Timing files Observed performance on this machine.
Local cache directory/index External cache artifact exists separately from image output.
Image inspect/history/runtime Local result identity and functional non-root runtime.
Sensitive-boundary checks Secret and SSH mounts did not become runtime state.
Fresh-builder log Reuse came from imported external cache.
Metadata JSON / OCI output Build-result/exporter identity.
Prediction review Whether each predicted state transition was observed.

13. Prediction review

Create evidence/22-prediction-results.txt. For each prediction, record confirmed, rejected, or qualified plus the exact evidence file. A warm build can be slower because of unrelated host noise while still proving cache hits; in that case qualify timing and keep the cache conclusion tied to the progress trace.

14. Exact cleanup and rollback

docker image rm \
  devops-academy-ch11-checkpoint:app \
  devops-academy-ch11-checkpoint:app-v2 \
  2>/dev/null || true

docker buildx rm devops-academy-ch11-checkpoint-fresh
docker buildx rm devops-academy-ch11-checkpoint

ssh-add -D 2>/dev/null || true
ssh-agent -k 2>/dev/null || true
rm -f checkpoint_key checkpoint_key.pub

docker buildx ls | tee evidence/23-builders-after.txt

Retain evidence/, cache/, and the OCI tar only as long as needed for review. Cache artifacts still need retention and access-control policy even when they contain no intentional secrets.

15. Operational review and Chapter 12 handoff

Chapter 11 adds reusable performance state to the Docker evidence chain without weakening artifact identity. You can now explain whether a build was fast because a vertex was skipped, a package manager reused a cache directory, or a fresh builder imported external cache. You also proved that secret and SSH mounts are ephemeral inputs rather than image configuration.

Chapter 12 moves to Multi-Platform Images, QEMU Emulation, Native Builders, Manifest Lists, and Cross-Architecture Delivery. Cache evidence now gains a platform dimension: worker platform, build platform, target platform, emulation/native execution, and per-platform output identity must remain distinct.

Next chapter

Next: Multi-Platform Images, QEMU Emulation, Native Builders, Manifest Lists, and Cross-Architecture Delivery

Carry forward exact builder and cache evidence while adding target-platform and per-platform image identity.

Knowledge check

Why change only app.py during the checkpoint?

Why create a fresh builder before cache import?

What proves the fake secret did not become runtime state?

Does an OCI tar output imply a Docker local tag exists?

What new identity dimension becomes central in Chapter 12?

Official references and version notes

  • Docker build cache — current cache model, optimization guidance, invalidation, and storage backends.
  • Build cache invalidation — instruction matching, COPY/ADD/bind-input checksums, RUN behavior, and the rule that secret contents do not invalidate cache.
  • Optimize cache usage — instruction ordering, small contexts, build bind mounts, cache mounts, and external cache patterns.
  • Cache storage backends — inline, registry, local, GHA, and availability notes for other backends.
  • Local cache backend — OCI-layout local cache export/import used by the mandatory checkpoint.
  • Registry cache backend — separate cache artifacts, min/max modes, and driver/containerd-image-store requirements.
  • RUN --mount reference — bind, cache, tmpfs, secret, and SSH mount semantics and options.
  • Build secrets — passing and consuming secret/SSH mounts without baking credentials into image layers.
  • docker buildx build — --cache-from, --cache-to, --secret, --ssh, progress, metadata, and output behavior.
  • Build drivers — driver capabilities that affect cache backend availability and builder isolation.
  • Docker Engine 29 release notes — current Engine baseline and bundled component updates.
  • Buildx releases — current Buildx release history.
  • BuildKit releases — current BuildKit and built-in Dockerfile frontend release history.
Version and compatibility note

Version-sensitive statements were rechecked against primary documentation on 2026-09-21. The course baseline is Docker Engine 29.8.1, Buildx 0.37.1, BuildKit 0.33.0, and the built-in Dockerfile frontend 1.27.0, but each executable lab records the versions and builder driver actually present. Cache backend support varies by driver and image-store configuration; the mandatory path uses an isolated docker-container builder plus the local cache backend because it is free, inspectable, and does not require registry credentials.

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.

Ethereum / ERC-20
0x716c4Ab160C4B66F31a28AE2448BfF68fc3a2ef0 Send only Ethereum/ERC-20 compatible assets to this address.