Checkpoint Lab — Docker Compose Foundations: Services, Images, Builds, Networks, Volumes, Environment, and Project Lifecycle
Bring up a disposable Compose application, capture normalized configuration and project resource evidence, verify service connectivity and persistent data, then tear it down with data-preservation intent explicit.
Learning objectives
- Create a reproducible Compose checkpoint project with explicit non-secret inputs and a recorded normalized model.
- Predict and verify concrete project resources: images, containers, network, named volume, labels, ports, health, and lifecycle state.
- Prove service-to-service connectivity independently from host-port publication and prove named-volume data survives service/container replacement.
- Capture an evidence packet containing versions/context, Compose configuration, build/image identity, container/network/volume state, logs, and assumptions.
- Tear down the project while deliberately preserving or explicitly deleting data according to stated intent, then bridge to advanced Compose behavior.
docker compose up
returned zero.” You must explain the resolved model, predict the
resources that should change, verify those changes independently,
preserve image/container/network/volume identities, and demonstrate
that teardown matches the declared data-retention intent.
1. Scenario and constraints
You are preparing a local integration environment for a release candidate. It has a built static web service, a writer that places a synthetic marker into a named volume, and a probe that reaches the web service by Compose service name. The entire lab is local, free, disposable, and contains no real credential.
- No privileged containers, host namespaces, Docker socket mounts, broad capabilities, or daemon mutation.
- No cloud/paid registry is required.
- Host publication is loopback-only.
- Named data is preserved by ordinary teardown; deletion is a separate explicit decision.
- Record actual component versions; do not assume the upstream baseline equals the local installation.
2. Record tool/runtime assumptions before creating resources
mkdir -p da-compose15-checkpoint/web da-compose15-checkpoint/evidence
cd da-compose15-checkpoint
date -u +%Y-%m-%dT%H:%M:%SZ | tee evidence/start-utc.txt
docker version | tee evidence/docker-version.txt
docker info | tee evidence/docker-info.txt
docker context show | tee evidence/docker-context.txt
docker compose version | tee evidence/compose-version.txt
docker buildx version | tee evidence/buildx-version.txt
Document whether Docker Desktop or native Engine is in use, host OS/architecture, and any limitation that affects paths/networking. Compose v5.5.1 is the upstream baseline checked for this lesson, but your evidence is authoritative for your run.
3. Predict state changes before executing them
Write these predictions into
evidence/predictions.txt before up:
- Prediction A: model validation changes no Engine resources; it only resolves/prints the Compose model.
-
Prediction B:
up -d --buildwill build one image, create three service containers, one default project network, and one named volume, then start the containers. -
Prediction C: recreating only
webchanges its container ID while the named volume ID and stored marker remain. -
Prediction D: ordinary
downremoves service containers and project network but preserves the named volume.
4. Create the exact checkpoint configuration
Use the same web/index.html, BusyBox-based
web/Dockerfile, and three-service
compose.yaml from Lesson 2. For this checkpoint, set:
WEB_PORT=18081
LAB_MESSAGE=checkpoint-compose15-persistent-marker
Copy the following source identities into evidence:
sha256sum compose.yaml web/Dockerfile web/index.html .env | tee evidence/source-sha256.txt 2>/dev/null || true
# On PowerShell use Get-FileHash for the same files.
5. Normalize and inspect without mutation
docker compose config --quiet
docker compose config --environment | tee evidence/interpolation.txt
docker compose config | tee evidence/compose-normalized.yaml
docker compose config --hash | tee evidence/config-hashes.txt
docker compose config --services | tee evidence/services.txt
docker compose config --networks | tee evidence/networks-model.txt
docker compose config --volumes | tee evidence/volumes-model.txt
Verify Prediction A by confirming there are still no resources with
project label da-compose15 (or use a unique checkpoint
project name if you changed name:).
6. Build and launch; capture BuildKit and project evidence
docker compose build --progress=plain web 2>&1 | tee evidence/build.log
docker compose up -d
docker compose ps -a | tee evidence/ps-after-up.txt
docker compose images | tee evidence/images-after-up.txt
docker ps -a --filter label=com.docker.compose.project=da-compose15 | tee evidence/containers-by-label.txt
docker network ls --filter label=com.docker.compose.project=da-compose15 | tee evidence/networks-by-label.txt
docker volume ls --filter label=com.docker.compose.project=da-compose15 | tee evidence/volumes-by-label.txt
Record the built image ID and, where available, RepoDigests. A local-only image can legitimately have no repository digest; that is an explicit limitation, not missing evidence.
docker image inspect da-compose15-web:lab --format '{{json .Id}} {{json .RepoDigests}}' | tee evidence/web-image.txt
7. Capture container IDs, PIDs, health, mounts, networks, ports, and labels
WEB_ID=$(docker compose ps -q web)
WRITER_ID=$(docker compose ps -q writer)
PROBE_ID=$(docker compose ps -q probe)
printf 'web=%s
writer=%s
probe=%s
' "$WEB_ID" "$WRITER_ID" "$PROBE_ID" | tee evidence/container-ids.txt
docker inspect "$WEB_ID" > evidence/web-inspect.json
docker inspect "$WRITER_ID" > evidence/writer-inspect.json
docker inspect "$PROBE_ID" > evidence/probe-inspect.json
docker compose ps --format json > evidence/ps.json
docker compose logs --no-color --timestamps > evidence/logs.txt
8. Verify the two connectivity paths independently
docker compose exec probe sh -c 'nslookup web || true; wget -q -O - http://web:8080/' | tee evidence/internal-http.txt
curl -fsS http://127.0.0.1:18081/ | tee evidence/host-http.txt
If the host lacks curl, use a browser or another
trusted local HTTP client and record that limitation. Internal
service DNS and host-published reachability are separate checks.
9. Prove persistent data and record the volume identity
docker compose exec writer cat /state/message.txt | tee evidence/message-from-writer.txt
docker compose exec web cat /site/state/message.txt | tee evidence/message-from-web.txt
docker volume ls --filter label=com.docker.compose.project=da-compose15 --format '{{.Name}}' | tee evidence/volume-name.txt
VOL=$(docker volume ls --filter label=com.docker.compose.project=da-compose15 --format '{{.Name}}' | head -n1)
docker volume inspect "$VOL" > evidence/volume-inspect-before.json
10. Recreate only the web service and verify Prediction C
Record the old web container ID, make an intentional harmless edit
to web/index.html, then:
OLD_WEB=$(docker compose ps -q web)
docker compose build web
docker compose up -d web
NEW_WEB=$(docker compose ps -q web)
printf 'old=%s
new=%s
' "$OLD_WEB" "$NEW_WEB" | tee evidence/web-recreation.txt
docker compose exec web cat /site/state/message.txt | tee evidence/message-after-recreate.txt
docker volume inspect "$VOL" > evidence/volume-inspect-after.json
The container ID should change if reconciliation recreated the service. The named volume identity and marker should remain. If the service was not recreated, inspect the build/image/config evidence rather than forcing recreation blindly.
11. Exercise lifecycle without deleting resources
docker compose stop probe
docker compose ps -a | tee evidence/ps-probe-stopped.txt
docker compose start probe
docker compose ps | tee evidence/ps-probe-restarted.txt
Explain in your notes: stop/start changes process/container lifecycle state, not the image, project model, network definition, or named-volume identity.
12. Tear down with retention intent explicit and verify Prediction D
docker compose down
docker ps -a --filter label=com.docker.compose.project=da-compose15 | tee evidence/containers-after-down.txt
docker network ls --filter label=com.docker.compose.project=da-compose15 | tee evidence/networks-after-down.txt
docker volume ls --filter label=com.docker.compose.project=da-compose15 | tee evidence/volumes-after-down.txt
The checkpoint's declared intent is to preserve the named volume after ordinary teardown. To remove it later, identify the exact disposable volume from your evidence and remove that exact resource after confirming no other workload needs it. Do not use broad prune.
13. Verification checklist
- ☐ Actual Docker/Compose/Buildx versions and active context recorded.
- ☐ Source/config hashes and normalized Compose model recorded.
- ☐ Project name and canonical resource labels verified.
- ☐ Web build trace and local image ID/digest state recorded.
- ☐ Container IDs, health/state, mounts, network attachments, ports, and logs captured.
- ☐ Service-to-service DNS/HTTP and host-published HTTP verified separately.
- ☐ Named-volume ID and marker verified before and after web replacement.
- ☐ Stop/start behavior explained as lifecycle state, not deployment mutation.
- ☐ Ordinary teardown verified to preserve named data.
- ☐ Assumptions/limitations note explains any platform-specific deviations.
14. What Chapter 15 adds to the production operating model
You can now reason about a Compose application as a resolved project model with independently verifiable image/build, container, network, storage, environment, and lifecycle states. That prevents the two most common conceptual errors: treating Compose as magic and treating every resource created by Compose as one indivisible thing.
Chapter 16 builds on this foundation with profiles, dependency conditions, overrides, includes, watch, and multi-file design. Those advanced features are only safe when the project/configuration precedence and state boundaries from this chapter are already clear.
Knowledge check
Why is the normalized Compose model part of the checkpoint evidence?
It records the actual configuration Compose resolved after interpolation/normalization, allowing runtime resources to be compared with intended input.
The web container ID changes but the named volume ID does not. What boundary did the experiment prove?
Container lifecycle/replacement is separate from named-volume storage identity and persistence.
Internal http://web:8080 works but host
127.0.0.1:18081 fails. Which evidence should you
inspect next?
Published-port mapping, host binding/listener path, active context and host networking/firewall evidence—not the named volume or service DNS first.
Why does the checkpoint use an explicit synthetic
LAB_MESSAGE rather than a credential?
The lab needs observable environment and persistence behavior,
not a real secret. Real secrets should not be stored in
.env or evidence files.
What is the safe meaning of ordinary
docker compose down in this lab?
Remove the project service containers and ordinary project network while preserving the named volume because data deletion was not the teardown intent.
What concept from Chapter 15 is prerequisite for Chapter 16 dependency conditions?
Container start, health/readiness, project identity, and normalized model are distinct states; dependency conditions operate on top of those distinctions.
Official references and version notes
- Docker Docs — Compose application model: projects, services, networks, volumes, and lifecycle.
- Docker Docs — Compose Specification reference: current declarative model and attributes.
-
Docker Docs —
docker compose config: canonical rendering, interpolation environment, service/network/volume views, hashes and digest resolution. - Docker Docs — project naming: precedence and isolation.
- Docker Docs — interpolation and container environment precedence.
- Docker Docs — Compose networking: default network and service-name discovery.
-
Docker Docs —
docker compose down: default teardown and explicit volume deletion semantics. - Docker Compose v5.5.1 release (2026-09-03). Labs record the actually installed version and do not assume every host matches upstream.
Upstream
Compose is v5.5.1. The course still treats
docker compose version, docker version,
docker info, and the active context as execution
evidence. The top-level Compose version: field is
obsolete/informative; the current Compose implementation validates
against the current schema.
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.