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.
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.
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"
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.
Knowledge check
Why does the checkpoint preserve both image ID and container ID?
They identify different objects. The image is immutable build content/config identity in the local store; the container is a runtime object created from that image with its own configuration and lifecycle.
What should the evidence packet say if the learner cannot inspect host PIDs because they use Docker Desktop?
State that host-process correlation is limited by the Desktop VM boundary, retain Docker-reported PID/runtime evidence, and do not invent an outer-host PID mapping.
What does a successful docker buildx build prove?
It proves the selected builder completed the requested build and exporter path. It does not automatically prove local loading, registry publication, signature verification, scan status, or successful runtime execution.
Why perform exact-name/label cleanup instead of docker system prune?
The lab must remove only resources it owns. Broad prune can delete unrelated images, caches, networks, and volumes and also destroys diagnostic evidence.
Which Chapter 04 concept naturally follows this checkpoint?
Image identity: layers, manifests, config objects, content-addressable storage, and the distinction between tags, image IDs, and immutable digests.
Official references and version notes
- Docker architecture overview — client/server ownership and the daemon's responsibility for Docker objects.
- Docker Engine API — API negotiation and the current Engine/API compatibility matrix.
- Docker Engine 29 release notes — current Engine 29 packaging, component, security, and compatibility changes.
- Alternative container runtimes — Docker Engine's use of containerd for container lifecycle and runc as the default OCI runtime.
- containerd image store with Docker Engine — current Engine 29 storage architecture and upgrade/fresh-install differences.
- Run containerd in the Docker daemon — current experimental embedded-containerd boundary introduced in Engine 29.7.
- BuildKit — Docker's modern build backend and its graph/cache model.
- Builders — default and custom BuildKit builder ownership.
- Docker build driver — integrated BuildKit behavior and local-image loading.
- Docker-container build driver — isolated, configurable BuildKit builder behavior and output semantics.
- Live restore — daemon-unavailability behavior, scope, caveats, and upgrade constraints.
- docker system events — event-stream evidence for object lifecycle transitions.
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.
0x716c4Ab160C4B66F31a28AE2448BfF68fc3a2ef0
Send only Ethereum/ERC-20 compatible assets to this
address.