Running docker run is fine for one container. But what if your app needs a database? And a cache? And a frontend? Do you really want to run 4 commands in a specific order every time you restart your laptop?
Enter Docker Compose.
Introduction
Docker Compose is a tool that lets you define and run multi-container Docker applications. You create a single file called docker-compose.yml, define everything your app needs (containers, networks, volumes), and start it all with one command.
- What
docker-compose.ymllooks like - How to define services (apps, databases)
- Networking magic (how containers talk to each other)
- Key commands:
up,down,logs
- Docker containers are individual musicians (violin, cello, drums).
- Docker Compose is the conductor and the sheet music.
- It tells everyone: βYou sit here,β βYou start playing only after the drums start,β βYou use this instrument.β
- One flick of the baton (
docker compose up) and the whole orchestra starts in sync.
The docker-compose.yml File
This is where the magic happens. It uses YAML (Yet Another Markup Language), which relies on indentation.
A Real Example: Ghost Blog + MySQL
Here is a full stack for a Ghost blog. It needs the Ghost app AND a MySQL database.
version: '3.8'
services:
ghost-app:
image: ghost:latest
ports:
- "8080:2368"
environment:
- database__client=mysql
- database__connection__host=db
- database__connection__user=root
- database__connection__password=secret
- database__connection__database=ghost
depends_on:
- db
db:
image: mysql:8.0
environment:
- MYSQL_ROOT_PASSWORD=secret
- MYSQL_DATABASE=ghost
volumes:
- db-data:/var/lib/mysql
volumes:
db-data:
Notice database__connection__host=db?
Docker Compose automatically creates a network where containers can reach each other by their service name.
We named the database service db, so the app can just connect to hostname db. No IP addresses needed!
Essential Commands
Once you have your docker-compose.yml file, you only need these commands:
Start Everything
Start all containers in the foreground (shows all logs)
Start in 'detached' mode (background) - The most common way
Check Status
List all containers managed by this Compose file and their status
Follow the logs of all services (Ctrl+C to stop following)
Follow logs for just one specific service
Stop and Clean Up
Stop the containers (preserves them)
Stop and REMOVE containers and networks
WARNING: Also removes volumes (deletes your database data!)
Key Concepts Explained
1. Services
A βserviceβ is just a fancy name for a container in the context of your app. In the example above, ghost-app and db are services.
2. Ports ("Host:Container")
"8080:2368" means βForward port 8080 on my laptop to port 2368 inside the container.β
You open localhost:8080 in your browser.
3. Environment Variables
Inject configuration like passwords, API keys, or debug flags without changing the image code.
4. Volumes
volumes: - db-data:/var/lib/mysql
This maps a persistent storage area to the database folder. Even if you destroy the db container, the data in db-data survives. When you restart, your blog posts are still there.
5. depends_on
Tells Docker to start the db before the ghost-app.
depends_on only waits for the container to start, not for the database inside it to be fully ready.
Your app may still crash on startup if it tries to connect before MySQL finishes initializing (~2-5 seconds).
Fix: Add retry logic in your app, or use a health-check with depends_on: condition: service_healthy.
Hands-On Challenge
- Create a folder
my-blogand enter it. - Create a file named
docker-compose.ymland paste the Ghost example code above. - Run
docker compose up -d. - Open
http://localhost:8080in your browser. You should see the Ghost blog! - Run
docker compose downto clean up.
Key Takeaways
- One File: Define your whole stack (app, db, cache) in
docker-compose.yml. - One Command:
docker compose up -dlaunches everything. - Networking: Containers talk to each other by service name (e.g.,
db), not IP. - Persistence: Use Volumes to keep database data safe even if containers crash.
- Production: Docker Compose is great for dev and small servers. For massive scale, youβd upgrade to Kubernetes (which uses similar YAML concepts).
Test Your Knowledge
Take a quick 5-question quiz to check your understanding.