Docker Compose
Docker Compose is a tool for defining and running multi-container applications using a YAML file.
docker-compose.yml Structure
version: '3.8'
services:
web:
image: nginx:alpine
ports:
- "80:80"
networks:
- frontend
api:
build: ./backend
environment:
- DB_HOST=database
- DB_PORT=5432
depends_on:
- database
networks:
- backend
database:
image: postgres:15
environment:
POSTGRES_DB: myapp
POSTGRES_USER: admin
POSTGRES_PASSWORD: secret123
volumes:
- db-data:/var/lib/postgresql/data
networks:
- backend
networks:
frontend:
backend:
volumes:
db-data:
Docker Compose Commands
# Run all services
docker-compose up -d
# Stop all services
docker-compose down
# View status
docker-compose ps
# View logs
docker-compose logs -f
# Rebuild
docker-compose up -d --build
# Scale a service
docker-compose up -d --scale api=3
# Execute a command in a container
docker-compose exec api bash
docker-compose exec database psql -U admin myapp
Service Configuration
services:
app:
build:
context: ./app
dockerfile: Dockerfile
args:
NODE_ENV: production
image: myapp:1.0
container_name: myapp-app
restart: unless-stopped
ports:
- "3000:3000"
environment:
- NODE_ENV=production
- DB_HOST=database
env_file:
- .env
volumes:
- ./app/src:/app/src
- app-data:/app/data
depends_on:
- database
- redis
networks:
- frontend
- backend
deploy:
resources:
limits:
cpus: '0.5'
memory: 512M
healthcheck:
test: ["CMD", "curl", "-f", "http://localhost:3000/health"]
interval: 30s
timeout: 10s
retries: 3
Use Case: Application
version: '3.8'
services:
# Frontend
frontend:
build: ./frontend
ports:
- "80:80"
networks:
- frontend
depends_on:
- api
# Backend API
api:
build: ./backend
environment:
- DB_HOST=database
- DB_PORT=5432
- DB_NAME=myapp
- REDIS_HOST=cache
volumes:
- ./backend/src:/app/src
networks:
- frontend
- backend
depends_on:
- database
- cache
# Database
database:
image: postgres:15
environment:
POSTGRES_DB: myapp
POSTGRES_USER: admin
POSTGRES_PASSWORD: ${DB_PASSWORD}
volumes:
- db-data:/var/lib/postgresql/data
- ./database/init.sql:/docker-entrypoint-initdb.d/init.sql
networks:
- backend
# Cache
cache:
image: redis:7-alpine
volumes:
- cache-data:/data
networks:
- backend
# Queue
queue:
image: rabbitmq:3-management
environment:
RABBITMQ_DEFAULT_USER: admin
RABBITMQ_DEFAULT_PASS: ${RABBIT_PASSWORD}
ports:
- "15672:15672"
networks:
- backend
networks:
frontend:
backend:
volumes:
db-data:
cache-data:
Environment Variables
# .env file
DB_PASSWORD=secret123
RABBIT_PASSWORD=rabbit456
REDIS_PASSWORD=redis789
# docker-compose.yml
services:
db:
environment:
POSTGRES_PASSWORD: ${DB_PASSWORD}
Profiles
services:
web:
image: nginx:alpine
debug:
image: busybox
profiles:
- debug
# Run: docker-compose --profile debug up
Everyday Use Case
Case: A developer needs to run the stack for development.
# Run all services
docker-compose up -d
# View real-time logs
docker-compose logs -f api
# Enter a container
docker-compose exec api bash
# Run a migration
docker-compose exec api npm run migrate
# Stop all services
docker-compose down
Best Practices
- Use the latest version:
version: '3.8' - Define depends_on: For startup order
- Use healthchecks: To ensure a service is ready
- Separate environments: Use a
.envfile - Use volumes: For persistent data
- Define networks: For isolation
Troubleshooting
Service won't start
# Check the logs
docker-compose logs service_name
# Check status
docker-compose ps
# Rebuild
docker-compose up -d --build
Port conflict
# Check which ports are in use
docker-compose ps
# Stop everything
docker-compose down
# Use a different port
docker-compose up -d -p 8080:80
Conclusion
Docker Compose makes managing multi-container applications easy. For applications, Compose ensures all services run correctly and are easy to maintain.