Docker Compose
Multi-container application orchestration with Docker Compose configurations and commands.
Basic Docker Compose
Simple docker-compose.yml
version: '3.8'
services:
web:
build: .
ports:
- '3000:3000'
environment:
- NODE_ENV=production
depends_on:
- db
db:
image: postgres:13
environment:
POSTGRES_DB: myapp
POSTGRES_USER: user
POSTGRES_PASSWORD: password
volumes:
- postgres_data:/var/lib/postgresql/data
volumes:
postgres_data:
Multi-Service Application
version: '3.8'
services:
web:
build:
context: .
dockerfile: Dockerfile
ports:
- '3000:3000'
environment:
- NODE_ENV=production
- DATABASE_URL=postgresql://user:password@db:5432/myapp
depends_on:
db:
condition: service_healthy
redis:
condition: service_started
networks:
- app-network
restart: unless-stopped
db:
image: postgres:13-alpine
environment:
POSTGRES_DB: myapp
POSTGRES_USER: user
POSTGRES_PASSWORD: password
volumes:
- postgres_data:/var/lib/postgresql/data
- ./init.sql:/docker-entrypoint-initdb.d/init.sql
networks:
- app-network
healthcheck:
test: ['CMD-SHELL', 'pg_isready -U user -d myapp']
interval: 30s
timeout: 10s
retries: 3
redis:
image: redis:7-alpine
ports:
- '6379:6379'
networks:
- app-network
command: redis-server --appendonly yes
volumes:
- redis_data:/data
nginx:
image: nginx:alpine
ports:
- '80:80'
- '443:443'
volumes:
- ./nginx.conf:/etc/nginx/nginx.conf
- ./ssl:/etc/nginx/ssl
depends_on:
- web
networks:
- app-network
volumes:
postgres_data:
redis_data:
networks:
app-network:
driver: bridge
Compose Commands
Basic Operations
# Start services
docker-compose up
# Start in background (detached)
docker-compose up -d
# Build and start
docker-compose up --build
# Start specific services
docker-compose up web db
# Stop services
docker-compose down
# Stop and remove volumes
docker-compose down -v
# Stop and remove images
docker-compose down --rmi all
Service Management
# List running services
docker-compose ps
# Show service logs
docker-compose logs
# Follow logs for specific service
docker-compose logs -f web
# Follow logs for multiple services
docker-compose logs -f web db
# Show logs with timestamps
docker-compose logs -t web
# Restart services
docker-compose restart
# Restart specific service
docker-compose restart web
Scaling Services
# Scale service to multiple instances
docker-compose up --scale web=3
# Scale multiple services
docker-compose up --scale web=3 --scale worker=2
# Scale down
docker-compose up --scale web=1
Build Operations
# Build or rebuild services
docker-compose build
# Build specific service
docker-compose build web
# Build without cache
docker-compose build --no-cache
# Build with progress output
docker-compose build --progress plain
# Pull latest images
docker-compose pull
# Pull specific service image
docker-compose pull db
Advanced Compose Configuration
Environment Variables
version: '3.8'
services:
web:
build: .
environment:
# Direct assignment
- NODE_ENV=production
- DEBUG=false
# From host environment
- API_KEY=${API_KEY}
- DATABASE_URL
# From .env file
- POSTGRES_PASSWORD=${POSTGRES_PASSWORD}
# Environment file
env_file:
- .env
- .env.local
Using .env File
# .env file
NODE_ENV=production
POSTGRES_PASSWORD=secretpassword
API_KEY=your-api-key
COMPOSE_PROJECT_NAME=myapp
Volume Configurations
version: '3.8'
services:
web:
image: nginx
volumes:
# Named volume
- web_data:/var/www/html
# Bind mount
- ./src:/app/src
- ./config:/app/config:ro # Read-only
# Anonymous volume
- /app/node_modules
# Tmpfs mount
- type: tmpfs
target: /tmp
tmpfs:
size: 1000000000 # 1GB
volumes:
web_data:
driver: local
driver_opts:
type: nfs
o: addr=10.40.0.199,rw
device: ':/path/to/dir'
Network Configuration
version: '3.8'
services:
web:
image: nginx
networks:
- frontend
- backend
ports:
- '80:80'
db:
image: postgres
networks:
backend:
aliases:
- database
- postgres-server
networks:
frontend:
driver: bridge
backend:
driver: bridge
ipam:
config:
- subnet: 172.20.0.0/16
external-network:
external: true
Health Checks
version: '3.8'
services:
web:
build: .
healthcheck:
test: ['CMD', 'curl', '-f', 'http://localhost:3000/health']
interval: 30s
timeout: 10s
retries: 3
start_period: 60s
db:
image: postgres:13
healthcheck:
test: ['CMD-SHELL', 'pg_isready -U postgres']
interval: 10s
timeout: 5s
retries: 5
redis:
image: redis:alpine
healthcheck:
test: ['CMD', 'redis-cli', 'ping']
interval: 10s
timeout: 3s
retries: 3
Resource Limits
version: '3.8'
services:
web:
image: nginx
deploy:
resources:
limits:
cpus: '0.5'
memory: 512M
reservations:
cpus: '0.25'
memory: 256M
restart_policy:
condition: on-failure
delay: 5s
max_attempts: 3
window: 120s
Development vs Production
Development Configuration
# docker-compose.dev.yml
version: '3.8'
services:
web:
build:
context: .
target: development
volumes:
- ./src:/app/src # Live code reloading
- ./package.json:/app/package.json
environment:
- NODE_ENV=development
- DEBUG=true
ports:
- '3000:3000'
- '9229:9229' # Debug port
command: npm run dev
db:
image: postgres:13
ports:
- '5432:5432' # Expose for debugging
Production Configuration
# docker-compose.prod.yml
version: '3.8'
services:
web:
build:
context: .
target: production
environment:
- NODE_ENV=production
restart: unless-stopped
# No volume mounts or debug ports
db:
image: postgres:13
restart: unless-stopped
# No exposed ports
Override Files
# Use development override
docker-compose -f docker-compose.yml -f docker-compose.dev.yml up
# Use production override
docker-compose -f docker-compose.yml -f docker-compose.prod.yml up -d
# Multiple override files
docker-compose -f docker-compose.yml -f docker-compose.override.yml -f docker-compose.local.yml up
Compose File Validation
Validate Configuration
# Validate compose file
docker-compose config
# Validate and show resolved configuration
docker-compose config --services
# Validate specific file
docker-compose -f docker-compose.prod.yml config
# Check for unused volumes
docker-compose config --volumes
# Resolve and display environment variables
docker-compose config --resolve-env-vars
Debugging Compose Applications
Debugging Commands
# Run command in service
docker-compose exec web /bin/bash
# Run one-off command
docker-compose run web npm test
# Run without dependencies
docker-compose run --no-deps web npm install
# Override entrypoint
docker-compose run --entrypoint /bin/bash web
# Check service status
docker-compose ps
# View service events
docker-compose events
Troubleshooting
# Check service health
docker-compose ps
docker-compose logs service_name
# Recreate services
docker-compose up --force-recreate
# Remove everything and start fresh
docker-compose down -v --remove-orphans
docker-compose up --build
# Debug networking
docker-compose exec web ping db
docker-compose exec web nslookup db
Production Deployment
Production Best Practices
version: '3.8'
services:
web:
image: myapp:${VERSION:-latest}
restart: unless-stopped
environment:
- NODE_ENV=production
secrets:
- api_key
- db_password
logging:
driver: 'json-file'
options:
max-size: '10m'
max-file: '3'
healthcheck:
test: ['CMD', 'curl', '-f', 'http://localhost:3000/health']
interval: 30s
timeout: 10s
retries: 3
secrets:
api_key:
external: true
db_password:
external: true
Deploy Commands
# Deploy with specific version
VERSION=1.2.3 docker-compose up -d
# Rolling update
docker-compose up -d --no-deps web
# Update specific service
docker-compose pull web
docker-compose up -d --no-deps web
Quick Reference
Essential Commands
docker-compose up -d- Start services in backgrounddocker-compose down- Stop and remove servicesdocker-compose logs -f- Follow service logsdocker-compose exec service bash- Access service shelldocker-compose ps- List running servicesdocker-compose build- Build/rebuild services
File Structure
project/
├── docker-compose.yml # Base configuration
├── docker-compose.override.yml # Local development overrides
├── docker-compose.prod.yml # Production configuration
├── .env # Environment variables
└── .env.example # Environment template
Best Practices
- Use specific image tags in production
- Implement health checks for all services
- Use secrets for sensitive data
- Set resource limits for production
- Use multi-stage builds for optimization
- Implement proper logging configuration
- Always use restart policies in production