Multi-Container Apps with Docker Compose
Define and run your whole stack from one file, with one command.
Real applications arenβt one container β theyβre an app plus a database, maybe a cache, maybe a queue. Starting each by hand with long docker run commands is error-prone. Docker Compose lets you describe the whole stack in one YAML file and start it all with a single command.
π― Learning Objectives
By the end of this lesson you will:
- Understand what Docker Compose solves
- Read and write a
docker-compose.ymlfile - Connect multiple services together
- Manage the whole stack with
compose upanddown
Why Compose?
Without Compose, launching an app + database means several long commands, a shared network, and correct startup order β every single time. Compose captures all of that in a file you can version-control and share.
π‘ The one-line version
Compose is a recipe for your whole application: every service, its config, and how they connect β reproducible with one command.
A Compose File, Explained
Hereβs a typical stack: a web app talking to a PostgreSQL database.
services:
web:
build: . # build from the local Dockerfile
ports:
- "3000:3000"
environment:
DATABASE_URL: postgres://user:pass@db:5432/app
depends_on:
- db
db:
image: postgres:16
environment:
POSTGRES_USER: user
POSTGRES_PASSWORD: pass
POSTGRES_DB: app
volumes:
- pgdata:/var/lib/postgresql/data
volumes:
pgdata:Key ideas:
- Each entry under
servicesis a container. depends_oncontrols startup order.- The web app reaches the database using the service name
dbas the hostname β Compose creates a private network where services find each other by name. - The named volume
pgdatakeeps database data safe across restarts.
β Never commit real secrets
The passwords above are fine for a local demo, but never put real credentials in a committed Compose file. Use a .env file (git-ignored) or a secrets manager for anything real.
Running the Stack
| Command | What it does |
|---|---|
docker compose up -d |
Build and start all services (detached) |
docker compose ps |
List the stackβs containers |
docker compose logs -f |
Follow logs from all services |
docker compose down |
Stop and remove everything |
docker compose down -v |
β¦and delete the volumes too |
One command brought up a private network, the database, and the web app in the right order.
Service Discovery by Name
This is the part that trips up beginners: inside a Compose network, you connect to another service by its service name, not localhost.
# Correct β 'db' is the service name
DATABASE_URL=postgres://user:pass@db:5432/app
# Wrong β localhost points at the app's own container
DATABASE_URL=postgres://user:pass@localhost:5432/appπ‘ Remember
Each container has its own localhost. To reach another container, use its service name as the hostname.
π§ͺ Hands-on Lab
Stand Up an App + Redis Stack
- Write a
docker-compose.ymlwith awebservice (nginx) and acacheservice (redis) - Start the stack in detached mode
- Confirm both containers are running, then tear it all down
π§ Knowledge Check
Inside a Docker Compose network, how does the web service connect to a database service named 'db'?
Which command stops the stack AND deletes its named volumes?
πΌ Interview Preparation
When would you use Docker Compose, and when would you reach for Kubernetes instead?
Summary
Youβve completed the Docker track: containers, images, everyday commands, writing Dockerfiles, and orchestrating multi-container stacks with Compose. You can now package and run whole applications reproducibly. Next, we scale up to running containers across a cluster with Kubernetes.