07 - Docker Compose
Docker Compose
In previous tutorials, we learned how to create and manage a single container with Docker. In real-world scenarios, we usually need to run multiple related containers to build a complete application. For example, a web app might include a web server, database, and cache. Manually managing these containers is tedious and error-prone—this is where Docker Compose helps.
What is Docker Compose?
Docker Compose is a tool for defining and running multi-container Docker applications. With Compose, you configure your app’s services in a YAML file, then start everything with a single command.
Install Docker Compose
On Windows and macOS
If you installed Docker Desktop (Windows or macOS), Docker Compose is included—no extra installation needed.
On Linux
# Download Docker Compose
sudo curl -L "https://github.com/docker/compose/releases/download/v2.18.1/docker-compose-$(uname -s)-$(uname -m)" -o /usr/local/bin/docker-compose
# Add execute permission
sudo chmod +x /usr/local/bin/docker-compose
# Verify installation
docker-compose --version
Docker Compose key concepts
docker-compose.yml
Docker Compose uses a YAML file (commonly docker-compose.yml) to define services, networks, and volumes. A simple example:
version: '3'
services:
web:
image: nginx:latest
ports:
- "8080:80"
volumes:
- ./html:/usr/share/nginx/html
db:
image: mysql:5.7
environment:
MYSQL_ROOT_PASSWORD: example
MYSQL_DATABASE: myapp
volumes:
- db-data:/var/lib/mysql
volumes:
db-data:
Services
Services are the building blocks of your app—typically one container per service. A service can be created from an image or built via a Dockerfile.
Networks
Compose creates a default network so services can talk to each other by service name. You can also customize network settings.
Volumes
Volumes are used to persist data or share data between services.
Common Docker Compose commands
Start services
# Run in the directory containing docker-compose.yml
docker-compose up
# Run in the background
docker-compose up -d
Stop services
docker-compose down
# Remove volumes as well
docker-compose down -v
View service status
docker-compose ps
View service logs
docker-compose logs
# Logs for a specific service
docker-compose logs web
# Tail logs
docker-compose logs -f
Run commands
# Execute a command inside a service container
docker-compose exec web bash
Build services
# Build or rebuild services
docker-compose build
# Build and start services
docker-compose up --build
docker-compose.yml explained
version
Specifies the Compose file format version.
version: '3'
services
Defines the services in your application.
services:
web:
image: nginx:latest
# more config...
db:
image: postgres:13
# more config...
Common service options
image
Specify the image to use.
image: redis:6
build
Build an image from a Dockerfile.
build:
context: ./dir # build context path
dockerfile: Dockerfile.dev # optional, specify Dockerfile
ports
Expose ports.
ports:
- "3000:3000" # host:container
volumes
Mount volumes or bind mounts.
volumes:
- ./data:/app/data # bind mount
- logs:/app/logs # named volume
environment
Set environment variables.
environment:
NODE_ENV: production
API_KEY: secret
depends_on
Define service dependencies.
depends_on:
- db
- redis
networks
Specify networks a service connects to.
networks:
- frontend
- backend
restart
Set the container restart policy.
restart: always # options: no, always, on-failure, unless-stopped
networks
Define networks used by the app.
networks:
frontend:
driver: bridge
backend:
driver: bridge
volumes
Define volumes used by the app.
volumes:
db-data:
logs:
Practical examples
Web app + database + Redis cache
version: '3'
services:
web:
build: ./app
ports:
- "3000:3000"
depends_on:
- db
- redis
environment:
- NODE_ENV=production
- DB_HOST=db
- REDIS_HOST=redis
networks:
- app-network
db:
image: postgres:13
environment:
- POSTGRES_USER=myuser
- POSTGRES_PASSWORD=mypassword
- POSTGRES_DB=myapp
volumes:
- db-data:/var/lib/postgresql/data
networks:
- app-network
redis:
image: redis:6
networks:
- app-network
networks:
app-network:
driver: bridge
volumes:
db-data:
WordPress + MySQL
version: '3'
services:
wordpress:
image: wordpress:latest
ports:
- "8080:80"
environment:
WORDPRESS_DB_HOST: db
WORDPRESS_DB_USER: wordpress
WORDPRESS_DB_PASSWORD: wordpress
WORDPRESS_DB_NAME: wordpress
volumes:
- wordpress:/var/www/html
depends_on:
- db
db:
image: mysql:5.7
environment:
MYSQL_ROOT_PASSWORD: rootpassword
MYSQL_DATABASE: wordpress
MYSQL_USER: wordpress
MYSQL_PASSWORD: wordpress
volumes:
- db:/var/lib/mysql
volumes:
wordpress:
db:
Best practices for Docker Compose
-
Use environment variables: Put secrets and environment-specific configs in a
.envfile rather than hard-coding them indocker-compose.yml. -
Organize services logically: Group related services and define proper dependencies.
-
Use version control: Track
docker-compose.ymlin version control, but exclude.env. -
Add health checks: Add health checks to ensure services are healthy.
healthcheck:
test: ["CMD", "curl", "-f", "http://localhost"]
interval: 1m
timeout: 10s
retries: 3
- Use named volumes: Prefer named volumes for persistent data instead of anonymous volumes.
Summary
Docker Compose greatly simplifies managing multi-container applications. With a single YAML file you can define services, networks, and volumes, then start and manage the entire stack with simple commands. This boosts developer productivity and keeps dev, test, and production environments consistent. In the next tutorial, we’ll cover Docker production best practices including security, monitoring, and performance tuning.