Docker Compose
A single docker run with a pile of flags is hard to maintain, and multiple containers more so. Docker Compose declares the whole app (services, networks, volumes) in one compose.yaml and brings it all up with one command.
Click the keys in compose.yaml to see what each block does:
Top-level structure
Common service keys
Creating networks
docker compose up automatically creates a project-specific bridge network (named <project>_default) and joins every service. A service name is its DNS hostname on that network, so web reaches the database at db:5432, no IP needed. To isolate tiers, declare your own networks:
proxy and db are on different networks and cannot talk directly; only app touches both.
Container group (project) name
Compose ties the set together with a “project name” and uses it as a naming prefix:
Precedence (high to low):
docker compose -p <name> > COMPOSE_PROJECT_NAME env var > top-level name: > the directory containing compose.yaml.
Environment configuration
Interpolation:
${VAR}, ${VAR:-default} (fall back when unset or empty), ${VAR:?msg} (error out when unset). In-container env var precedence (high to low): docker compose run -e > environment: > env_file: > host shell inheritance > Dockerfile ENV.
Using GPUs
The official way is to declare it under a service’sdeploy.resources.reservations.devices (the host needs the NVIDIA Container Toolkit first):
Performance and startup order
depends_onwithhealthcheck: usecondition: service_healthyto wait until a dependency is actually ready, so the app does not race a database that is not up yet.- Resource limits:
deploy.resources.limitscpus/memoryalso take effect in standalone (non-Swarm) mode. pull_policyand build cache: control whether to pull every time and reuse build cache.- Startup:
up -d(background),--build(rebuild first),--scale web=3(run 3 copies),--wait(wait until everything is healthy).
Volume and bind mount mapping
Compose’svolumes: handles both bind mounts and named volumes, distinguished by how the source is written (see Where data lives):
A complete compose.yaml
Common docker compose commands
The commands above all assume a default filename in the current directory.
docker compose looks for compose.yaml (preferred), compose.yml, docker-compose.yaml, then docker-compose.yml, searching the working directory and walking up to parent directories. When the filename is not a default (for example docker-compose.dev.yml or my-stack.yaml), you must name it explicitly with -f. -f is a top-level option and goes before the subcommand (up / down …); multiple -f flags merge in order (later overrides earlier). The COMPOSE_FILE environment variable does the same. This is exactly how the official CLI docs define it.compose.yaml up looks like this:
Next
- Where data lives: the difference between volumes and bind mounts.
- How to write a Dockerfile: writing the Dockerfile that
build:points to.