Checkpoint Lab — Developer Workflows, Dev Containers, Inner Loop Optimization, Compose-Based Labs, and Local Parity
Onboard a clean workspace into a pinned containerized development environment, prove the inner loop, record identities, build production separately, and document parity gaps.
Learning objectives
- Onboard a clean synthetic workspace into a pinned, non-root development environment.
- Exercise an edit/test inner loop while recording source, runtime, user, tool, cache, and port evidence.
- Build the production image independently from the development container and record its immutable identity.
- Create an explicit parity-gap list covering kernel/platform, mounts, ports, secrets, tooling, and data services.
- Clean only checkpoint-owned resources while retaining the evidence packet.
1. Checkpoint contract
The checkpoint succeeds only when another developer could reconstruct what you used: source revision/checksum, Compose model, base-image reference and observed identity, runtime user, Python version, cache volume, local port, test result, production image identity, and a written list of differences between the developer environment and production. The dev service itself is not promoted.
2. Workspace and preflight
set -eu
LAB=dca37-checkpoint
mkdir -p "$LAB/src" "$LAB/evidence"
date -u +%Y-%m-%dT%H:%M:%SZ | tee "$LAB/evidence/time-start.txt"
docker context show | tee "$LAB/evidence/context.txt"
docker version | tee "$LAB/evidence/docker-version.txt"
docker compose version | tee "$LAB/evidence/compose-version.txt"
docker buildx version | tee "$LAB/evidence/buildx-version.txt"
3. Create clean source
# dca37-checkpoint/src/app.py
import sys
print("checkpoint-app=ready")
print(f"python={sys.version_info.major}.{sys.version_info.minor}")
# dca37-checkpoint/src/test_app.py
from pathlib import Path
text = Path("/workspace/src/app.py").read_text()
assert "checkpoint-app=ready" in text
print("checkpoint-test=pass")
sha256sum dca37-checkpoint/src/* | tee dca37-checkpoint/evidence/source.sha256
git rev-parse HEAD 2>/dev/null | tee dca37-checkpoint/evidence/source-revision.txt || printf 'synthetic-checksums-above
' | tee dca37-checkpoint/evidence/source-revision.txt
4. Create pinned-readable development definition
# dca37-checkpoint/Dockerfile.dev
# syntax=docker/dockerfile:1
FROM python:3.13-alpine
RUN addgroup -g 10001 dev && adduser -D -u 10001 -G dev dev && mkdir -p /workspace/src /home/dev/.cache && chown -R dev:dev /workspace /home/dev
WORKDIR /workspace
USER dev
CMD ["sh", "-lc", "python /workspace/src/app.py && sleep infinity"]
# dca37-checkpoint/compose.yaml
services:
dev:
build:
context: .
dockerfile: Dockerfile.dev
working_dir: /workspace
volumes:
- ./src:/workspace/src
- dca37-checkpoint-cache:/home/dev/.cache
ports:
- "127.0.0.1:18039:8000"
labels:
academy.lab: dca37-checkpoint
volumes:
dca37-checkpoint-cache:
name: dca37-checkpoint-cache
labels:
academy.lab: dca37-checkpoint
5. Predict state changes before execution
Prediction 1: Compose will create one project service plus the exact named cache volume dca37-checkpoint-cache.
Prediction 2: the dev process will run as UID/GID 10001 inside the container unless the definition is changed.
Prediction 3: editing the host source bind will immediately change /workspace/src in the dev container.
Prediction 4: the production image built later will contain copied source but no source bind mount or development cache volume.
Prediction 5: cleanup will remove only the checkpoint Compose objects, exact cache volume, and exact production image tag.
6. Render configuration before starting
docker compose -p dca37-checkpoint -f dca37-checkpoint/compose.yaml config | tee dca37-checkpoint/evidence/compose.rendered.yaml
docker compose -p dca37-checkpoint -f dca37-checkpoint/compose.yaml up -d --build
7. Record dev runtime and tool identities
CID=$(docker compose -p dca37-checkpoint -f dca37-checkpoint/compose.yaml ps -q dev)
printf '%s
' "$CID" | tee dca37-checkpoint/evidence/dev-container-id.txt
docker inspect "$CID" \
--format 'image={{.Image}} user={{.Config.User}} mounts={{json .Mounts}} ports={{json .NetworkSettings.Ports}}' | tee dca37-checkpoint/evidence/dev-inspect.txt
docker compose -p dca37-checkpoint -f dca37-checkpoint/compose.yaml exec dev id | tee dca37-checkpoint/evidence/dev-id.txt
docker compose -p dca37-checkpoint -f dca37-checkpoint/compose.yaml exec dev python --version | tee dca37-checkpoint/evidence/python-version.txt
docker volume inspect dca37-checkpoint-cache | tee dca37-checkpoint/evidence/cache-volume.json
8. Exercise edit/test inner loop
printf '
# checkpoint-edit=1
' >> dca37-checkpoint/src/app.py
docker compose -p dca37-checkpoint -f dca37-checkpoint/compose.yaml exec dev tail -n 2 /workspace/src/app.py | tee dca37-checkpoint/evidence/edit-visible.txt
docker compose -p dca37-checkpoint -f dca37-checkpoint/compose.yaml exec dev python /workspace/src/test_app.py | tee dca37-checkpoint/evidence/test.txt
9. Optional Compose Watch variant
# Replace the source bind with this in a copy of the Compose file if Compose >= 2.22:
develop:
watch:
- action: sync
path: ./src
target: /workspace/src
initial_sync: true
If you exercise this optional variant, capture the Watch output and final file checksum. Do not claim you tested Watch if you only used the bind-mounted checkpoint path.
10. Build production separately
# dca37-checkpoint/Dockerfile
# syntax=docker/dockerfile:1
FROM python:3.13-alpine AS runtime
RUN addgroup -g 10001 app && adduser -D -u 10001 -G app app
WORKDIR /app
COPY --chown=app:app src/app.py /app/app.py
USER app
CMD ["python", "/app/app.py"]
docker build -f dca37-checkpoint/Dockerfile -t dca37-checkpoint-prod:1 dca37-checkpoint | tee dca37-checkpoint/evidence/prod-build.log
docker image inspect dca37-checkpoint-prod:1 \
--format 'id={{.Id}} repoDigests={{json .RepoDigests}} user={{.Config.User}}' | tee dca37-checkpoint/evidence/prod-image.txt
docker run --rm dca37-checkpoint-prod:1 | tee dca37-checkpoint/evidence/prod-run.txt
11. Record the parity-gap list
Required parity-gap note:
- Source: production image contains source as of the production build; dev sees live host edits.
- User: both examples are non-root, but dev UID ownership and production runtime ownership serve different goals.
- Filesystem: dev has source bind + cache volume; production image has neither.
- Kernel/host: Docker Desktop/host development kernel may differ from production.
- Ports: checkpoint publishes only loopback; production ingress is not modeled.
- Secrets: none are required; real secret-provider behavior is not modeled.
- Tooling: dev may gain editor/debug tools; production target intentionally does not.
- Data services/scale: no production database, replicas, load balancer, or failover is modeled.
12. Verify predictions
| Prediction | Verification |
|---|---|
| Exact cache volume exists |
docker volume inspect dca37-checkpoint-cache
|
| Dev is non-root | captured id output |
| Edit reaches dev workspace | captured tail/test output |
| Production has no dev bind/cache | production container/image inspect and Dockerfile |
| Cleanup is bounded | only project, named volume, exact image tag removed |
13. Exact cleanup
docker compose -p dca37-checkpoint -f dca37-checkpoint/compose.yaml down
docker volume rm dca37-checkpoint-cache 2>/dev/null || true
docker image rm dca37-checkpoint-prod:1 2>/dev/null || true
printf 'Retain dca37-checkpoint/evidence for review.
'
14. Required evidence packet
| Evidence family | Required record |
|---|---|
| Source | revision or synthetic checksums; dirty-state note if applicable |
| Docker host | context, Engine, Compose and Buildx versions |
| Dev definition | rendered Compose; Dockerfile.dev checksum |
| Identity | dev container ID/image ID; runtime UID/GID; Python/tool versions |
| Workspace | mount source/target or Watch rule and observed edit |
| Cache | named volume identity and intended retention |
| Network | loopback published port or forwarding mechanism |
| Test | inner-loop test output |
| Production | production Dockerfile; image ID/digest evidence; runtime output |
| Parity | explicit gap list; no claim of full environment equivalence |
| Cleanup | exact project/volume/image objects removed |
15. What Chapter 37 adds to the operating model
You can now make onboarding and the inner loop reproducible without conflating them with production delivery. Source, developer tooling, workspace synchronization, caches, identities and local ports are all explicit evidence. Production remains a separately built artifact with a documented parity contract.
Knowledge check
What proves the developer environment is reproducible enough to review?
Versioned definitions plus recorded Docker/tool/image/user/mount/cache/port evidence—not merely “it opened in my editor.”
Why does the checkpoint build production after the inner-loop test?
To prove production is a separate controlled build boundary rather than the mutable dev container filesystem.
If you did not run Compose Watch, may you claim Watch behavior was verified?
No. Record it as an optional design path and state that the checkpoint used a bind mount.
What is the correct cleanup unit?
The exact Compose project, exact named checkpoint volume, exact image tag, and optional generated workspace after evidence review—not global Docker state.
What should the final parity note contain?
Specific equivalences and specific gaps across source, user, filesystem, kernel/platform, ports, secrets, tooling, data services, and scale.
Official references and version notes
Checkpoint baseline: 2026-09-22. The runnable path requires only Docker/Compose and local files. Dev Container tooling and Docker Desktop premium synchronized sharing are optional; the evidence and parity contract does not depend on them.
- Docker Docs — Use Compose Watch — current Watch workflow, sync/rebuild behavior, ownership guidance, and command forms.
-
Docker Docs — Compose Develop Specification
—
develop.watch, actions, paths, targets, ignore/include, and version gates. - Docker Docs — Docker Desktop settings — host/VM file sharing and resource behavior.
- Docker Docs — Synchronized file shares — optional Desktop acceleration for large repositories and its constraints.
- Docker Docs — Sharing local files — bind-mount semantics and host-side effects.
- Development Containers Specification — open development-container specification and reference ecosystem.
-
Dev Container Spec — Overview
—
devcontainer.jsonas development metadata layered onto container technologies. - Dev Container Spec — Dockerfile and Compose guide — using Dockerfile/Compose as the underlying environment definition.
-
Dev Container Spec — Supporting tools and services
— support boundaries for properties such as
remoteUserandforwardPorts. - Dev Container Features index — current Feature registry and versioned references.
- Dev Container Spec — Feature updates and lockfiles — resolved Feature identities and lockfile maintenance.
- Docker Docs — Multi-stage builds — keep development tooling out of the production target.
- Docker Engine 29 release notes — current Engine-era context used by this course.
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.