Chapter 15Lesson 05~135 minutes

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.

Checkpoint labEvidence packetPersistenceConnectivityLifecycle

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.
Checkpoint rule. A passing checkpoint is not “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:

  1. Prediction A: model validation changes no Engine resources; it only resolves/prints the Compose model.
  2. Prediction B: up -d --build will build one image, create three service containers, one default project network, and one named volume, then start the containers.
  3. Prediction C: recreating only web changes its container ID while the named volume ID and stored marker remain.
  4. Prediction D: ordinary down removes 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?

The web container ID changes but the named volume ID does not. What boundary did the experiment prove?

Internal http://web:8080 works but host 127.0.0.1:18081 fails. Which evidence should you inspect next?

Why does the checkpoint use an explicit synthetic LAB_MESSAGE rather than a credential?

What is the safe meaning of ordinary docker compose down in this lab?

What concept from Chapter 15 is prerequisite for Chapter 16 dependency conditions?

Next lesson

Next: Advanced Compose: Profiles, depends_on, Health Conditions, Overrides, Includes, Watch, and Multi-File Design: Concepts, Architecture, and Mental Model

Continue with the next lesson in the course sequence and carry forward the evidence-first Docker operating model.

Official references and version notes

Version baseline checked 2026-09-21.

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.

Ethereum / ERC-20
0x716c4Ab160C4B66F31a28AE2448BfF68fc3a2ef0Send only Ethereum/ERC-20 compatible assets to this address.