Chapter 31Lesson 05~200 minutes

Checkpoint Lab — Containerd Image Store, Snapshotters, Runtime Internals, OCI Runtime Specs, and Docker Engine Evolution

Trace one pulled image and running container from Docker reference and digest through image-store, snapshot, task, shim, OCI/runtime concepts, then document which state Docker must continue to own.

CheckpointDigest traceRuntime traceEvidence packetChapter 32 bridge

Learning objectives

  • Trace one pulled image from registry index/digest through local image-store evidence, container object, runtime task/process, and cleanup state.
  • Capture current Engine, Buildx, Compose, containerd/runc evidence without assuming every component is independently installed on the host shell.
  • Predict at least two state changes before pulling/starting and verify both independently.
  • Produce an evidence packet that names the storage architecture and documents which internal state remains Docker-managed.
  • Bridge the runtime-internals model into Chapter 32 storage-driver/copy-on-write/disk troubleshooting.

1. Checkpoint outcome

You will trace alpine:3.22.1 through a complete but bounded chain: registry metadata → local Docker image identity → reported store/snapshotter mode → Docker container object → running process → optional read-only containerd correlation → exact cleanup. The checkpoint is successful only if every observation is labeled with the layer it proves.

2. Assumptions and platform matrix

Item Checkpoint assumption How to verify
Docker Engine/CLI Engine 29.8.1 is current baseline; actual host may differ docker version
Buildx/Compose Installed plugin versions vary by Desktop/distro bundle docker buildx version, docker compose version
BuildKit Engine 29.8.0 packaging updated to 0.33.0; actual builder can differ docker buildx inspect / builder evidence
containerd 29.8.1 static binaries list 2.3.5; installed/bundled instance can differ Docker info + optional host binary/managed endpoint evidence
runc 29.8.0 static binaries list 1.5.1; actual runtime can differ Docker info / optional runc --version
OCI specs Image 1.1.1; Runtime 1.3.0 current published baselines Reference links below
Image alpine:3.22.1 human-readable source; capture resolved digest imagetools + pull + inspect

3. Preflight: host, context, credentials, disk, and preexisting resources

set -eu
LAB=dca31-checkpoint
EVIDENCE="$LAB/evidence"
mkdir -p "$EVIDENCE"

date -u +%Y-%m-%dT%H:%M:%SZ | tee "$EVIDENCE/time.txt"
docker context show | tee "$EVIDENCE/context.txt"
docker version | tee "$EVIDENCE/docker-version.txt"
docker info | tee "$EVIDENCE/docker-info.txt"
docker buildx version 2>/dev/null | tee "$EVIDENCE/buildx-version.txt" || true
docker compose version 2>/dev/null | tee "$EVIDENCE/compose-version.txt" || true
docker system df | tee "$EVIDENCE/system-df-before.txt"

# Guard exact lab name.
if docker container inspect dca31-checkpoint >/dev/null 2>&1; then
  echo 'Refusing to overwrite existing container dca31-checkpoint' >&2
  exit 1
fi

if docker image inspect alpine:3.22.1 >/dev/null 2>&1; then
  echo preexisting > "$EVIDENCE/image-preflight.txt"
else
  echo absent > "$EVIDENCE/image-preflight.txt"
fi

The lab uses public read-only image pulls and no credentials. If your environment requires an authenticated registry mirror, use a disposable training account and do not save credentials inside the evidence directory.

4. Prediction sheet: write before acting

cat > "$EVIDENCE/predictions.md" <<'EOF'
# Predictions
1. Pulling alpine:3.22.1 will create/update local image/content metadata but will not create a Docker container or running process.
2. docker create will create a container object with State.Status=created and PID=0; docker start will transition to a running task/process with a nonzero host PID.
3. The immutable registry/image digest should not change merely because a container starts.
4. If DriverStatus reports io.containerd.snapshotter.v1, Engine is using the containerd snapshotter-backed image store; if not, document the classic/other reported mode rather than forcing a change.
EOF
cat "$EVIDENCE/predictions.md"

If your host differs, do not rewrite the prediction after seeing the result. Record the mismatch and explain it.

5. Registry-side image evidence

docker buildx imagetools inspect alpine:3.22.1   | tee "$EVIDENCE/registry-index.txt"
docker buildx imagetools inspect alpine:3.22.1 --raw   > "$EVIDENCE/registry-index-raw.json"
sha256sum "$EVIDENCE/registry-index-raw.json"   | tee "$EVIDENCE/registry-index-raw.sha256"

This captures OCI index/manifest metadata before local rootfs state exists. Record which platform matches the daemon host.

6. Pull, identify, and record storage mode

docker pull alpine:3.22.1 | tee "$EVIDENCE/pull.txt"

docker image inspect alpine:3.22.1 > "$EVIDENCE/image-inspect.json"
docker image inspect alpine:3.22.1 \
  --format 'id={{.Id}} repoDigests={{json .RepoDigests}} platform={{.Os}}/{{.Architecture}}'   | tee "$EVIDENCE/image-summary.txt"

docker info --format '{{json .DriverStatus}}'   | tee "$EVIDENCE/driver-status.json"
docker info --format 'driver={{.Driver}} root={{.DockerRootDir}} runtime={{.DefaultRuntime}}'   | tee "$EVIDENCE/store-runtime-summary.txt"

Now verify prediction 1: docker ps -a --filter name=dca31-checkpoint should still show no lab container. The pull changed image/content state, not container/process state.

7. Create without starting: capture the object boundary

docker create \
  --name dca31-checkpoint \
  --label devops-academy.lab=chapter31-checkpoint   alpine:3.22.1   sh -c 'printf "checkpoint-runtime\n"; sleep 180'   | tee "$EVIDENCE/container-id.txt"

docker inspect dca31-checkpoint > "$EVIDENCE/container-created.json"
docker inspect dca31-checkpoint \
  --format 'status={{.State.Status}} pid={{.State.Pid}} image={{.Image}} runtime={{.HostConfig.Runtime}}'   | tee "$EVIDENCE/container-created-summary.txt"

Prediction 2 says PID should be zero before start. If your platform reports something different, preserve it and explain the product/version behavior instead of forcing expected output.

8. Start and trace runtime/process state

docker start dca31-checkpoint | tee "$EVIDENCE/start.txt"

docker inspect dca31-checkpoint > "$EVIDENCE/container-running.json"
docker inspect dca31-checkpoint \
  --format 'status={{.State.Status}} pid={{.State.Pid}} started={{.State.StartedAt}} image={{.Image}} runtime={{.HostConfig.Runtime}}'   | tee "$EVIDENCE/container-running-summary.txt"

docker top dca31-checkpoint -eo pid,ppid,user,args   | tee "$EVIDENCE/docker-top.txt"
docker logs --timestamps dca31-checkpoint   | tee "$EVIDENCE/logs.txt"

At this point the chain has crossed into task/shim/runc/kernel execution. The image digest is still artifact identity; the PID proves a current process instance only.

9. Capture component/runtime evidence

docker info --format 'default={{.DefaultRuntime}} runtimes={{json .Runtimes}}'   | tee "$EVIDENCE/runtimes.txt"
containerd --version 2>/dev/null | tee "$EVIDENCE/containerd-binary.txt" || true
runc --version 2>/dev/null | tee "$EVIDENCE/runc-binary.txt" || true

docker system df | tee "$EVIDENCE/system-df-after.txt"

Do not claim the optional binaries are the exact daemon-managed components unless you can prove that relationship. The evidence packet should say “host binary reported X” versus “Docker release packaging baseline Y.”

10. Optional Linux-only correlation with ctr

# OPTIONAL READ-ONLY DIAGNOSTIC; skip on Desktop/remote contexts.
sudo ctr --address /var/run/docker/containerd/containerd.sock   --namespace moby containers list   | tee "$EVIDENCE/ctr-containers.txt"

sudo ctr --address /var/run/docker/containerd/containerd.sock   --namespace moby tasks list   | tee "$EVIDENCE/ctr-tasks.txt"

Find the Docker container ID/task correlation if available. Stop there. The evidence packet must explicitly state: Docker Engine owns this namespace; no ctr mutation was performed.

11. Verify the predictions independently

cat > "$EVIDENCE/verification.md" <<'EOF'
# Verification
- Pull changed local image/content state: compare image-preflight, pull output, and image inspect.
- Create produced a Docker object before a running PID: compare container-created-summary with container-running-summary.
- Start produced runtime/process evidence: docker top + logs + StartedAt.
- Image identity remained artifact identity: compare .Image / RepoDigests before and after start.
- Store mode came from Docker info DriverStatus; no backend switch was performed.
- No Docker-managed containerd state was mutated through ctr.
EOF
cat "$EVIDENCE/verification.md"

12. Evidence packet manifest

Evidence family Required fields
Environment UTC time, Docker client/server, context, OS/arch, Engine store mode, DockerRootDir
Build/runtime tooling Buildx, Compose, reported runtime, optional containerd/runc binary versions
Image human reference, registry index/platforms, local image ID, RepoDigest/platform
Storage DriverStatus, snapshotter/classic interpretation, system df before/after
Container/runtime container ID, created state, running PID, runtime, StartedAt, top/logs
Low-level optional read-only ctr containers/tasks listing + endpoint/namespace
Assumptions Engine 29 current baseline, packaging-version caveats, Desktop/remote-context notes
Ownership statement Docker Engine controls managed containerd; no direct mutation

13. Cleanup and rollback

docker rm -f dca31-checkpoint

# Respect preexisting image state.
if grep -qx absent "$EVIDENCE/image-preflight.txt"; then
  docker image rm alpine:3.22.1 || true
fi

docker system df | tee "$EVIDENCE/system-df-cleanup.txt"

Keep the evidence directory if you want an audit trail. The cleanup intentionally does not prune unrelated images, build cache, networks, volumes, or containerd content.

14. What Chapter 31 adds to the production operating model

You can now trace Docker’s high-level object model into its Engine 29-era storage/runtime internals without confusing implementation state for a supported operator API. That gives production runbooks a sharper rule: verify immutable OCI identity at the registry/image layer, verify materialization at the snapshot layer, verify execution at the task/shim/runtime layer, and preserve Docker as the owner of its managed containerd state.

Chapter 32

Storage drivers, overlay2, copy-on-write, disk usage, pruning, and storage troubleshooting

Next we turn this architecture into disk behavior: copy-on-write costs, writable layers, storage accounting, safe cleanup, and diagnosing capacity/performance without destructive pruning.

Knowledge check

Which checkpoint evidence proves the registry offered multiple platforms?

Which evidence proves a process actually existed?

The tag was present before the lab. Why does cleanup leave it alone?

Why can the optional ctr listing be useful but still not be a lifecycle command path?

A learner’s Engine 29 host reports classic overlay2. Did the checkpoint fail?

Official references and version notes

Checkpoint baseline date:

2026-09-22. Engine 29.8.1 is current. The static-binary release baseline lists containerd 2.3.5; Engine 29.8.0 lists BuildKit 0.33.0 and runc 1.5.1. OCI Image 1.1.1 and Runtime 1.3.0 are the current published specification baselines. Actual Desktop/distribution component versions remain part of the required evidence.

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
0x716c4Ab160C4B66F31a28AE2448BfF68fc3a2ef0Send only Ethereum/ERC-20 compatible assets to this address.