Topic 5.1
Why Compose & Your First compose.yaml
In one line
Compose turns a page of docker run commands you'd have to remember and retype into one readable, version-controlled YAML file that anyone on your team can run identically.
Think of it like this
A restaurant's prep list versus one chef trying to remember 15 separate verbal instructions every single morning. Writing it all down ONCE as a checklist means anyone (a new chef, a substitute) can follow the exact same steps perfectly, every time, without relying on memory.
Key ideas
- 01
Without Compose, running a Spring Boot app + Postgres + Redis together means manually creating a network, then three separate long
docker runcommands with the right flags, env vars, and port mappings, in the right order, every single time you want to start your stack — tedious and error-prone to repeat or share with teammates. - 02
A
compose.yamlfile (the modern standard filename; you'll also see the olderdocker-compose.ymlin existing projects — both work) describes ALL of your services, their images/builds, ports, environment variables, volumes, and how they connect — declaratively, in one file. - 03
docker compose upreads that file and starts EVERYTHING it describes, in the correct dependency order, on an automatically-created shared network where every service can reach every other service BY NAME (exactly the DNS mechanism from Phase 4.3) — with zero manual network setup. - 04
docker compose downstops and removes everything Compose started (containers and the network it created) in one command — the exact reverse ofup, keeping your system clean between runs. - 05
Each top-level entry under
services:becomes one container, using its own service name as both the YAML key and the DNS name other services will use to reach it — this single naming convention is what makesjdbc:postgresql://db:5432/mydbwork with zero extra configuration whendbis a service name in the same file.
In your stack
- →
A realistic minimal Spring Boot + Postgres compose.yaml is genuinely just ~15 lines and replaces a network create, two docker run commands, and remembering which env vars and ports go where — every teammate runs
docker compose upand gets the identical local stack.
Code & diagrams
A complete, runnable Spring Boot + Postgres stack in one file.
services:
db:
image: postgres:16-alpine
environment:
POSTGRES_PASSWORD: secret
POSTGRES_DB: mydb
volumes:
- pgdata:/var/lib/postgresql/data # named volume, survives `compose down`
app:
build: . # build from the Dockerfile in this directory
ports:
- "8080:8080"
environment:
SPRING_DATASOURCE_URL: jdbc:postgresql://db:5432/mydb
SPRING_DATASOURCE_PASSWORD: secret
depends_on:
- db # start db before app
volumes:
pgdata: # declares the named volume Docker manages# Start everything (build images if needed, create network+volumes, start all services)
docker compose up
# Same, but detached (returns your terminal immediately)
docker compose up -d
# See logs from ALL services, combined and color-coded per service
docker compose logs -f
# Stop and remove everything Compose created (containers + network; volumes SURVIVE by default)
docker compose down
# Stop and remove EVERYTHING including named volumes — irreversible data loss, be careful
docker compose down -v
# Rebuild images before starting (after you changed your Dockerfile or source code)
docker compose up --buildExplain it without notes
Why does jdbc:postgresql://db:5432/mydb in the app service's environment work correctly with zero extra network configuration?
What's the practical difference between docker compose down and docker compose down -v, and why does that distinction matter enormously for a database service?
Practice
Write and run this exact compose.yaml (or an equivalent for any app+database pair you have) and confirm both services start and can reach each other.
Run docker compose down (without -v), then docker compose up again, and confirm your database data survived. Then run docker compose down -v and confirm it did NOT.
Trade-offs
- ↔
Compose is designed for single-host development and simple deployments — it is NOT a replacement for a real orchestrator (Kubernetes, Docker Swarm) when you need multi-host scaling, automated failover, or rolling deployments across a fleet of machines. Phase 8 draws this line clearly.
Done when you can
I can write a compose.yaml for a simple two-service app from memory.
I know exactly what down -v does and never run it carelessly on real data.
I understand that Compose service names double as DNS names automatically.