Chapter 03Lesson 05~140 minutes

Checkpoint Lab — Docker Engine Components: dockerd, containerd, runc, BuildKit, APIs, and Container Lifecycle

Capture an end-to-end evidence packet for one BuildKit build and one container lifecycle, including versions, API state, builder identity, image identity, container PID, events, logs, cleanup, and stated limitations.

Checkpoint labLifecycle timelineBuild evidenceRuntime evidenceCleanup

Learning objectives

  • Capture a reproducible baseline for Engine/API, builder, image, container, process, events, and runtime versions.
  • Predict and verify state transitions before build/create/start/stop/cleanup.
  • Separate local image ID from registry digest and build success from runtime success.
  • Document platform limitations rather than fabricating unavailable host evidence.
  • Produce guarded cleanup and hand off naturally to Chapter 04 image identity.
Chapter 03 platform baseline — verified 2026-09-20. Docker Engine 29.8.1 is current. The 29.8 API matrix lists API 1.55 maximum / 1.40 minimum. Engine 29.8 packages BuildKit 0.33.0 and runc 1.5.1; the 29.8.1 static-binary packaging update carries containerd 2.3.5. Treat these as dated reference points only: capture docker version, docker info, docker buildx version, and platform-specific runtime evidence on the machine that actually runs the lab.

1. Checkpoint outcome and safety envelope

You will produce one evidence packet that connects a BuildKit build to an Engine image object and then to a container object's runtime process and event timeline. The checkpoint is intentionally local and disposable: no registry push, no external secrets, no privileged container, no socket mount, no daemon reconfiguration, and no broad prune.

2. Preflight and assumptions record

set -eu
LAB=da-ch03-checkpoint
IMAGE=da-ch03-checkpoint:local
LABEL='devops-academy.lab=chapter03-checkpoint'
WORK="${TMPDIR:-/tmp}/da-ch03-checkpoint"
EVIDENCE="$WORK/evidence"
mkdir -p "$EVIDENCE"

date -u | tee "$EVIDENCE/00-time.txt"
docker context show | tee "$EVIDENCE/01-context.txt"
docker version | tee "$EVIDENCE/02-version.txt"
docker info | tee "$EVIDENCE/03-info.txt"
docker buildx version | tee "$EVIDENCE/04-buildx-version.txt"
docker buildx ls | tee "$EVIDENCE/05-builders.txt"
docker buildx inspect --bootstrap | tee "$EVIDENCE/06-builder-inspect.txt"

Prediction 1: the build will create BuildKit progress evidence and, because --load is used, a local Engine image object. Prediction 2: docker create will create a container object with no running PID; docker start will then create a running task/process.

3. Create the bounded build input

cat > "$WORK/Dockerfile" <<'EOF'
FROM busybox:1.36.1
RUN printf 'chapter03-checkpoint\n' > /evidence.txt
CMD ["sh", "-c", "echo runtime-pid1=$$; cat /evidence.txt; trap 'echo TERM-received; exit 0' TERM; while :; do sleep 5; done"]
EOF
sha256sum "$WORK/Dockerfile" | tee "$EVIDENCE/07-dockerfile-sha256.txt"
docker pull busybox:1.36.1 | tee "$EVIDENCE/08-base-pull.txt"
docker image inspect busybox:1.36.1 --format 'ID={{.Id}} RepoDigests={{json .RepoDigests}}' | tee "$EVIDENCE/09-base-image.txt"

4. Build and prove the output contract

START=$(date -u +%Y-%m-%dT%H:%M:%SZ)
docker buildx build --progress=plain --load   --label "$LABEL"   -t "$IMAGE" "$WORK" 2>&1 | tee "$EVIDENCE/10-build.log"

docker image inspect "$IMAGE"   --format 'ID={{.Id}} Created={{.Created}} Labels={{json .Config.Labels}}'   | tee "$EVIDENCE/11-image.txt"

Do not call this a registry digest: a locally built image can have an image/config ID without a registry RepoDigest. The checkpoint records exactly the identity it can prove.

5. Create, inspect, and start the container

docker create --name "$LAB" --label "$LABEL" "$IMAGE"   | tee "$EVIDENCE/12-container-id.txt"
docker inspect "$LAB" --format 'Status={{.State.Status}} PID={{.State.Pid}} Image={{.Image}}'   | tee "$EVIDENCE/13-created-state.txt"

docker start "$LAB" | tee "$EVIDENCE/14-start.txt"
sleep 1
PID=$(docker inspect -f '{{.State.Pid}}' "$LAB")
docker inspect "$LAB" > "$EVIDENCE/15-running-inspect.json"
docker logs "$LAB" > "$EVIDENCE/16-container.log" 2>&1
printf 'Docker-reported PID=%s
' "$PID" | tee "$EVIDENCE/17-pid.txt"

If you are on native Linux Engine, optionally add read-only host correlation. On Docker Desktop, state that the PID lives inside the managed Linux VM boundary.

ps -fp "$PID" > "$EVIDENCE/18-host-process.txt" 2>&1 || true
ls -l "/proc/$PID/ns" > "$EVIDENCE/19-namespaces.txt" 2>&1 || true
cat "/proc/$PID/cgroup" > "$EVIDENCE/20-cgroup.txt" 2>&1 || true
ps -eo pid,ppid,comm,args | grep '[c]ontainerd-shim' > "$EVIDENCE/21-shims.txt" 2>&1 || true

6. Stop, capture events, and preserve exit evidence

docker stop --time 10 "$LAB" | tee "$EVIDENCE/22-stop.txt"
END=$(date -u +%Y-%m-%dT%H:%M:%SZ)
docker events --since "$START" --until "$END" --filter "container=$LAB"   > "$EVIDENCE/23-events.txt"
docker inspect "$LAB" \
  --format 'Status={{.State.Status}} Exit={{.State.ExitCode}} Started={{.State.StartedAt}} Finished={{.State.FinishedAt}}'   | tee "$EVIDENCE/24-final-state.txt"

7. Record runtime component evidence where the platform exposes it

(containerd --version || true) > "$EVIDENCE/25-containerd.txt" 2>&1
(runc --version || true) > "$EVIDENCE/26-runc.txt" 2>&1
(systemctl status docker --no-pager || true) > "$EVIDENCE/27-docker-service.txt" 2>&1
(journalctl -u docker --since "$START" --no-pager || true) > "$EVIDENCE/28-daemon-log.txt" 2>&1

On Docker Desktop, several host-level files can correctly say “command not available” or show no service manager. That is a documented limitation, not a reason to enter the VM or weaken Desktop boundaries for this checkpoint.

8. Evidence review: what each success proves

Evidence Proves Does not prove
Build log exits 0 Selected BuildKit builder completed the graph/exporter. Registry publication or runtime health.
Image inspect succeeds Result exists in local Engine image store. Registry digest or signature.
Created state has no running PID Container object exists before workload start. Runtime create/start success.
Running inspect has PID Docker reports a running task/process. Application readiness or external reachability.
Events timeline Docker recorded ordered lifecycle transitions in the bounded window. Every internal syscall or application event.

9. Guarded cleanup and proof

docker rm "$LAB"
docker image rm "$IMAGE"

docker ps -a --filter "label=$LABEL" | tee "$EVIDENCE/29-post-cleanup-containers.txt"
docker images --filter "label=$LABEL" | tee "$EVIDENCE/30-post-cleanup-images.txt"

tar -C "$WORK" -czf "$WORK/chapter03-evidence.tgz" evidence
printf 'Evidence archive: %s
' "$WORK/chapter03-evidence.tgz"
Keep the evidence archive only if it contains no secrets or sensitive host details. Operational logs and inspect output can reveal paths, endpoints, environment variables, labels, usernames, and infrastructure metadata. Review before sharing.

10. Operational review and Chapter 04 handoff

You can now localize a Docker operation across client/API, dockerd, Docker-managed containerd, shim/runc, kernel process, and BuildKit builder state. Chapter 04 takes the image identity captured here and decomposes it into content-addressable layers, configuration objects, manifests/indexes, tags, image IDs, and digests.

Next chapter

Next: Images, Layers, Content-Addressable Storage, Manifests, Config Objects, and Image Identity: Concepts, Architecture, and Mental Model

Chapter 04 turns the runtime evidence you captured into a precise model of image content, manifests, configuration objects, layers, IDs, and digests.

Knowledge check

Why does the checkpoint preserve both image ID and container ID?

What should the evidence packet say if the learner cannot inspect host PIDs because they use Docker Desktop?

What does a successful docker buildx build prove?

Why perform exact-name/label cleanup instead of docker system prune?

Which Chapter 04 concept naturally follows this checkpoint?

Official references and version notes

Current baseline, not a frozen requirement

Verified 2026-09-20: Docker Engine 29.8.1 is current; the Engine 29.8 API matrix lists maximum API 1.55 and minimum API 1.40. Engine 29.8 packaging includes BuildKit 0.33.0 and runc 1.5.1; 29.8.1 updates the static-binary containerd package to 2.3.5. Package-managed distributions and Docker Desktop can bundle or expose components differently. Record the actual client/server/API/component/builder versions on the learner's environment before diagnosing compatibility.

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.