Docker Compose Foundations: Services, Images, Builds, Networks, Volumes, Environment, and Project Lifecycle: Concepts, Architecture, and Mental Model
Compose is a declarative application model that resolves configuration into a project-scoped set of containers, networks, volumes, labels, and lifecycle operations. This lesson builds that model before changing runtime state.
Learning objectives
-
Explain how
compose.yaml, interpolation inputs, and the active Compose CLI become one normalized application model. - Distinguish a Compose project, service definition, service container, network, named volume, build/image input, and host-published port.
-
Identify project-scoped resource names and canonical
com.docker.compose.*labels before changing state. - Separate Compose model resolution from Engine runtime state and separate “started” from “ready”.
- Use read-only commands to establish version, context, project, configuration, image, network, volume, and lifecycle evidence.
1. The problem: a multi-container application has more state than a
list of docker run commands
By Chapter 14 you can build, identify, distribute, and retrieve
images. Real applications often need several related containers plus
networks, persistent storage, environment-specific configuration,
health observations, and repeatable lifecycle commands. Hand-writing
independent docker run commands makes those
relationships easy to drift.
Compose solves the declaration problem. A Compose file describes desired application components; the Compose CLI resolves interpolation and file rules into a normalized model, chooses a project identity, and asks the active Docker Engine to create or reconcile concrete resources. The project name is not cosmetic: it groups and isolates resources and appears in canonical Compose labels.
2. Mental model: file + interpolation → normalized model → project → Engine resources → observed state
flowchart TD
A[compose.yaml + optional override files] --> B[Interpolation inputs shell / --env-file / .env]
B --> C[docker compose config normalized model]
C --> D[Project identity -p / COMPOSE_PROJECT_NAME / name]
D --> E[Services]
D --> F[Project networks]
D --> G[Project volumes]
E --> H[Image pull or build]
H --> I[Service containers]
F --> I
G --> I
I --> J[Runtime evidence ps logs inspect health ports]
The Compose file is declarative input, not runtime evidence.
docker compose config proves what Compose resolved.
Engine inspection proves what exists. Application probes and health
evidence prove what the workload can actually do.
3. Define the objects before operating them
| Concept | Meaning | Best evidence | Do not confuse with |
|---|---|---|---|
| Compose file |
Source declaration, normally compose.yaml.
|
File path/revision plus docker compose config.
|
A guarantee that resources already exist. |
| Project | One deployment instance of the Compose model. | Project name plus canonical project labels. | A service or container name. |
| Service | Reusable container configuration in the model. | Normalized service config. | One specific container instance. |
| Image/build | Input artifact or build recipe used for a service. | Image digest/ID and build trace. | The running service process. |
| Network | Connectivity boundary. Compose creates a default project network unless configured otherwise. | Network ID/name, labels, attached endpoints. | Host port publication. |
| Named volume | Engine-managed persistent storage object. | Volume name/ID, labels, mount target. | Container writable layer. |
| Environment | Two separate concerns: values used to interpolate the Compose model and values injected into containers. |
config --environment plus resolved service
environment.
|
Secret storage. |
| Lifecycle state | Created/running/exited/health state of concrete containers. | compose ps, logs, inspect, health. |
Readiness merely because a container started. |
4. Project naming is an isolation control
Current Compose project-name precedence is: -p on the
CLI, then COMPOSE_PROJECT_NAME, then top-level
name:, then the project-directory basename, then the
current-directory basename when no file is specified. The same
Compose model can therefore create two isolated application
instances by using two project names.
Compose uses the project identity to scope default resource names
and sets canonical labels such as
com.docker.compose.project. Network and volume
resources also receive Compose resource labels. These labels are
often safer diagnostic selectors than guessing generated names.
docker compose version
docker compose config --services
docker compose config --networks
docker compose config --volumes
# After a project exists, inspect by canonical label rather than by name guessing:
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
5. Interpolation environment is not the same as the container environment
Compose can substitute variables into YAML values before creating
resources. Current Docker Compose gives shell variables higher
interpolation precedence than values from --env-file,
which in turn override the default project .env path.
You can inspect interpolation inputs with
docker compose config --environment.
Container environment precedence is a separate problem. CLI
run -e overrides relevant Compose-file values; Compose
environment generally outranks env_file;
image ENV is lower when Compose provides a value. A
file named .env is therefore configuration input, not a
secret manager. Chapter 15 deliberately uses only synthetic
non-secret values.
6. Default networking: service-name discovery, not fixed container IPs
For ordinary local development, Compose creates one project default bridge network. Containers attached to that network are discoverable by service name through Docker's internal DNS. Recreated containers can receive new IP addresses, so application configuration should prefer stable service names rather than persisted IPs.
A host-published port is a separate path. Service-to-service traffic
normally targets the container port through the Compose network;
host users reach the published host address/port. Publishing
127.0.0.1:8080:80 intentionally bounds the lab listener
to loopback.
7. Named volumes outlive ordinary container replacement
A named volume is an Engine storage object attached to a service
container. docker compose down removes project
containers and ordinary project networks by default, but it does
not remove named volumes unless volume deletion is
explicitly requested. This is a crucial lifecycle boundary:
replacing a container is not the same as deleting its persistent
data.
Bind mounts instead couple the service to a host path. They can be appropriate for editable source code or explicit host integration, but they reduce portability because the host path and permissions become part of runtime correctness.
8. Read-only preflight: prove client, context, Compose, and model state first
docker version
docker info
docker context show
docker compose version
# In a Compose project directory, before creating anything:
docker compose config --quiet
docker compose config --environment
docker compose config --services
docker compose config --networks
docker compose config --volumes
# If a project already exists:
docker compose ps -a
docker compose images
docker compose config is particularly valuable because
it merges files, interpolates variables, expands short syntax, and
renders the model that Compose intends to apply. It does not prove
the Engine accepted or is currently running that model; follow it
with runtime evidence.
9. Compose is not a magical production orchestrator
Compose gives a portable application model and excellent local/single-Engine lifecycle ergonomics. It does not, by itself, add a scheduler across hosts, distributed consensus, automatic multi-node rescheduling, or a complete secrets/identity/observability platform. Some Compose specification attributes can map to richer platforms, but the local Docker Engine execution path remains a concrete single-platform implementation.
This course therefore treats Compose as a declarative application model whose outputs must still be verified at the image, container, network, storage, security, and application layers.
10. Common misconceptions to reject early
- “Service name equals container hostname everywhere.” Service-name discovery is network-scoped; custom network modes, aliases, multiple replicas, and hostname settings change details.
-
“
.envis a secret vault.” It is configuration/interpolation input and can be accidentally committed or exposed. -
“
upmeans ready.” It proves Compose created/started resources, not that an application dependency is healthy. -
“
downdeletes all data.” Named volumes are preserved by default; explicit volume deletion is a different action. - “Directory name is harmless.” It can become the project name and therefore affect which resources a command targets.
Knowledge check
What does docker compose config prove?
It proves the Compose model after file merging, interpolation, and normalization. It does not prove those resources currently exist or that the application is healthy.
Why is the project name operationally significant?
It groups and isolates resources and appears in Compose labels/naming. A different project name can target a different set of containers, networks, and volumes even with the same Compose file.
Does a running service container prove the application is ready?
No. Process start and application readiness are different states. Use health checks or application-level probes where readiness matters.
What normally happens to a named volume on
docker compose down?
It is preserved unless volume deletion is explicitly requested. External volumes are never removed by ordinary down semantics.
Why should service-to-service connections normally use the service name rather than a recorded IP?
Container IPs can change on recreation while service-name discovery remains the stable network-level abstraction.
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.