What Is Docker Compose?
Docker Compose is a tool for defining and running multi-container Docker applications. It uses YAML files (docker-compose.yml) to configure your application's services, networks, and volumes in a single, declarative format. Instead of running multiple docker run commands, you define everything in one file and launch your entire stack with a single command.
Quick Answer
docker-compose.yml with services (api, db, redis, etc.), then run docker compose up -d. Compose handles networking, volumes, environment variables, and service startup order automatically.
Installing Docker Compose
Ubuntu 24.04 & Debian 12
Docker Compose comes built-in with modern Docker installations. Verify your installation:
docker compose version
If not installed:
- Add Docker repository
- Update package lists
- Install docker-compose-plugin
- Verify installation
Real-World Production Example
Here's a production stack with nginx, Node.js API, PostgreSQL, and Redis:
version: '3.8'
services:
nginx:
image: nginx:latest
ports:
- "80:80"
- "443:443"
volumes:
- ./nginx.conf:/etc/nginx/nginx.conf
depends_on:
- api
networks:
- backend
api:
build: .
expose:
- 3000
environment:
- NODE_ENV=production
- DATABASE_URL=postgres://user:pass@postgres:5432/app
- REDIS_URL=redis://redis:6379
depends_on:
- postgres
- redis
networks:
- backend
postgres:
image: postgres:16
environment:
- POSTGRES_USER=user
- POSTGRES_PASSWORD=secure_password
- POSTGRES_DB=app
volumes:
- postgres_data:/var/lib/postgresql/data
networks:
- backend
redis:
image: redis:7-alpine
networks:
- backend
volumes:
postgres_data:
networks:
backend:
driver: bridge
Architecture Overview:
- Reverse proxy: nginx on ports 80/443
- Application: Node.js API on port 3000 (internal)
- Database: PostgreSQL with persistent volume
- Cache: Redis for sessions and caching
- Network: All services on internal backend network for security
Common Operations
Start all services
docker compose up -d
View logs
docker compose logs api -f
Scale a service
docker compose up -d --scale worker=4
Restart a specific service
docker compose restart api
Execute command in container
docker compose exec api npm run migrate
Stop and remove everything (with volumes)
docker compose down -v
Environment Variables
Create a .env file in the same directory as docker-compose.yml:
DATABASE_URL=postgres://user:password@postgres:5432/myapp
REDIS_URL=redis://redis:6379
API_PORT=3000
NODE_ENV=production
Reference variables in docker-compose.yml:
services:
api:
environment:
- DATABASE_URL=${DATABASE_URL}
- REDIS_URL=${REDIS_URL}
Health Checks
Ensure services start in the correct order:
services:
postgres:
image: postgres:16
healthcheck:
test: ["CMD-SHELL", "pg_isready -U user"]
interval: 10s
timeout: 5s
retries: 5
api:
build: .
depends_on:
postgres:
condition: service_healthy
Networking Between Services
Services can communicate using service names as hostnames:
# From api service, connect to postgres:
const connection = await postgres.connect('postgres://user:pass@postgres:5432/app');
# From api service, connect to redis:
const redis = require('redis').createClient({host: 'redis', port: 6379});
Production Best Practices
- Use specific image versions - Never use
:latest - Set resource limits - Prevent runaway containers
- Use health checks - Ensure proper service startup order
- Separate concerns - One service per container
- Secure credentials - Use .env files, never commit secrets
- Volume backups - Regularly backup persistent data
- Log aggregation - Use logging drivers for centralized logs
Troubleshooting
Port already in use
docker compose down
# or change port mapping in docker-compose.yml
Service won't start
docker compose logs service_name
Can't reach service from another container
docker compose exec api ping postgres