Docker Compose Foundations: Services, Images, Builds, Networks, Volumes, Environment, and Project Lifecycle: Diagnostics, Failure Modes, Security, and Performance
Diagnose Compose failures without hiding first-failure evidence: project-name drift, environment/interpolation mistakes, readiness assumptions, unsafe volume teardown, service-name/network confusion, and build/image mismatch.
Learning objectives
- Preserve Compose source, normalized config, project identity, image IDs/digests, container state, logs, network/volume evidence, and application symptoms before correcting a failure.
- Diagnose project-name mismatch, interpolation mistakes, service-start versus readiness problems, network/service-name confusion, and data-lifecycle mistakes causally.
-
Explain why
down --volumes, broad prune, forced recreation, privileged containers, and secret printing are poor first-line troubleshooting shortcuts. - Use one intentionally broken configuration to demonstrate failure at model-validation time and one runtime example to distinguish internal connectivity from published-port failure.
- Apply the least destructive correction and rerun only the smallest safe scope.
1. Diagnostic sequence: move from cheapest boundary to deepest runtime state
-
Preserve the original error, command, timestamp, Compose source,
and
docker compose configoutput if it can be rendered safely. -
Confirm
docker version,docker info, active context, anddocker compose version. - Confirm the exact project name and Compose file set.
- Confirm source/build/image identity: build trace, image ID/digest, pull policy.
-
Inspect
compose ps -a, container inspect, exit code, health, and logs. - Inspect mounts/volumes/resources/security settings.
- Inspect project networks, DNS/service names, published ports, and application listeners.
- Inspect registry/external dependencies only when local evidence points outward.
- Apply the smallest correction and rerun the smallest affected scope.
2. Capture a compact evidence packet before mutation
docker version
docker context show
docker compose version
docker compose config > evidence/compose-config-before.yaml
docker compose config --environment > evidence/interpolation-before.txt
docker compose ps -a --format json > evidence/ps-before.json
docker compose images > evidence/images-before.txt
docker compose logs --no-color --timestamps --tail=200 > evidence/logs-before.txt
docker ps -a --filter label=com.docker.compose.project=da-compose15
docker network ls --filter label=com.docker.compose.project=da-compose15
docker volume ls --filter label=com.docker.compose.project=da-compose15
Do not dump real secret values into an evidence packet. Record the source/mechanism and whether a value was present, not the secret itself.
3. Intentionally broken example: fail safely at model-resolution time
Create a disposable copy of the lab and temporarily remove
WEB_PORT from its interpolation inputs while the
Compose file uses ${WEB_PORT:?set WEB_PORT}. Then run:
docker compose config --quiet
The expected failure says the required variable is unset. That is valuable: no container, network, or volume needs to be created. The cause is the Compose interpolation/configuration layer, not BuildKit, Nginx/BusyBox, the Docker daemon, or a firewall.
Repair: restore the synthetic non-secret
WEB_PORT value in the intended source, re-run
config --environment and config --quiet,
then proceed. Do not “fix” this by hard-coding a secret or deleting
Docker state.
4. Failure mode: the same files target a different project
If yesterday you used project da-compose15 but today
execute with -p da-compose15-debug,
compose ps can appear empty or up can
create a second set of resources. Before claiming Docker “lost
containers,” prove the project identity.
docker compose ls
docker compose -p da-compose15 ps -a
docker compose -p da-compose15-debug ps -a
docker ps -a --filter label=com.docker.compose.project=da-compose15
docker ps -a --filter label=com.docker.compose.project=da-compose15-debug
5. Failure mode: container started, dependency not ready
A process can be running while the application is still initializing
or unhealthy. docker compose ps may show
Up before a service-level probe succeeds. Preserve logs
and health state; do not immediately restart every service.
docker compose ps -a
docker inspect "$(docker compose ps -q web)" --format '{{json .State}}'
docker compose logs --no-color --timestamps web
docker compose exec probe wget -S -O - http://web:8080/
If Chapter 15 uses a health check, inspect it. Chapter 16 will teach dependency health conditions in depth. The core lesson here is that ordering and readiness are different.
6. Failure mode: assuming a service name works in every network scenario
Service-name DNS is available to containers attached to the relevant
Compose network. It is not a universal hostname on the host, on
unrelated networks, or in network_mode: host. First
inspect network attachments, then resolve from the failing
consumer's network namespace.
docker compose exec probe sh -c 'cat /etc/resolv.conf; nslookup web || true'
docker inspect "$(docker compose ps -q probe)" --format '{{json .NetworkSettings.Networks}}'
docker inspect "$(docker compose ps -q web)" --format '{{json .NetworkSettings.Networks}}'
7. Failure mode: deleting data to troubleshoot an unrelated service problem
docker compose down and volume deletion are
deliberately separate. If the web endpoint is failing, deleting the
application data volume is rarely a justified first action. Preserve
the exact volume identity, inspect mounts, and verify whether the
symptom is even storage-related.
compose down to remove project named/anonymous volumes
is destructive. Use it only when data deletion is the explicit,
authorized objective and the exact project/volume has been verified.
Never use broad prune as a troubleshooting shortcut.
8. Failure mode: the Compose source changed but the service is still using an older image
Compose source, build context, built image, and running container
are separate states. Compare them rather than assuming
up rebuilt anything you changed.
docker compose config --hash web
docker compose images web
docker inspect "$(docker compose ps -q web)" --format 'container={{.Id}} image={{.Image}}'
docker image inspect da-compose15-web:lab --format 'image={{.Id}} created={{.Created}}'
If the intended change is in the build context, rebuild the specific service and reconcile only that service. Preserve the before/after image IDs and build trace.
9. Performance diagnosis: locate the slow layer before changing concurrency or cache
Slow compose up --build can be a BuildKit/cache issue,
image pull issue, health/readiness delay, application startup issue,
or an overloaded Engine. Use timestamps and component-specific
evidence. Do not delete the builder cache merely because a build is
slow; Chapter 11 established that cache state itself is evidence and
can be shared.
10. Shortcuts this course does not recommend
-
Do not commit real credentials into
.envor print them in logs. - Do not use privileged containers, Docker socket mounts, broad capabilities, or host networking merely to “make Compose work.”
- Do not disable TLS, firewall controls, seccomp, AppArmor, or SELinux as a generic diagnosis.
- Do not blindly restart the daemon or all services before preserving evidence.
- Do not use broad image/container/volume prune as routine repair.
- Do not remove persistent volumes to solve a network, image, or project-name problem.
11. Smallest-safe-scope examples
| Observed cause | Smallest correction | Evidence after correction |
|---|---|---|
| Required interpolation variable missing |
Restore the non-secret configuration source; rerun
compose config.
|
Normalized model plus interpolation environment. |
| Wrong project name | Invoke the intended project name; do not recreate unrelated resources. | Project labels and compose ps. |
| Only web image stale | Build/reconcile web only. |
Before/after image ID and web container ID. |
| Internal DNS works, host port fails | Inspect port binding/host path. | Container port mapping, host listener/request result. |
| Application not ready | Fix/readiness logic or application startup cause. | Health/application probe and logs. |
Knowledge check
A compose config required-variable error appears
before any containers exist. Which layer failed?
Compose model/interpolation resolution. Do not troubleshoot runtime networking or delete Engine resources.
Why can an empty docker compose ps be a
project-name problem rather than lost containers?
Compose commands target a project identity. A different
-p, environment value, top-level name, or
directory-derived name can select another project.
A service shows Running but its health probe fails. What does Running prove?
Only that the container main process is running. It does not prove application readiness or dependency success.
Why is deleting a named volume a poor generic fix?
It destroys persistent state and is unrelated to many failures such as interpolation, image identity, DNS, port publication, or readiness.
A rebuilt image exists but the running container reports an older image ID. Which state must be reconciled?
The service container/runtime state. Preserve both IDs, then recreate/reconcile the smallest affected service using the intended image.
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.