Docker Compose
Docker Compose orchestrates multi-container applications. Learn to define and manage complex application stacks with Docker Compose.
Challenge
Section titled “Challenge”Define and manage a complete multi-service application stack using Docker Compose with proper networking, volumes, and orchestration.
Explanation
Section titled “Explanation”Docker Compose Concepts
Section titled “Docker Compose Concepts”- Services: Individual containers
- Networks: Container communication
- Volumes: Data persistence
- Environments: Configuration
- Dependencies: Service ordering
Key Features
Section titled “Key Features”- Simple YAML Syntax: Easy configuration
- Local Development: Full-stack locally
- Networking: Automatic service discovery
- Volume Management: Data persistence
- Environment Management: Configuration
Code Examples
Section titled “Code Examples”1. Complete Application Stack
Section titled “1. Complete Application Stack”version: '3.9'
services: # Node.js Application app: build: context: . dockerfile: Dockerfile container_name: nodejs-app ports: - "3000:3000" environment: NODE_ENV: development DATABASE_URL: postgresql://user:password@db:5432/appdb REDIS_URL: redis://cache:6379 ELASTICSEARCH_URL: http://search:9200 RABBITMQ_URL: amqp://guest:guest@queue:5672 depends_on: db: condition: service_healthy cache: condition: service_healthy search: condition: service_healthy queue: condition: service_healthy volumes: - ./src:/app/src - ./logs:/app/logs networks: - app-network restart: unless-stopped
# PostgreSQL Database db: image: postgres:15-alpine container_name: postgres-db environment: POSTGRES_USER: user POSTGRES_PASSWORD: password POSTGRES_DB: appdb volumes: - postgres_data:/var/lib/postgresql/data - ./scripts/init.sql:/docker-entrypoint-initdb.d/init.sql ports: - "5432:5432" healthcheck: test: ["CMD-SHELL", "pg_isready -U user -d appdb"] interval: 10s timeout: 5s retries: 5 networks: - app-network
# Redis Cache cache: image: redis:7-alpine container_name: redis-cache command: redis-server --appendonly yes volumes: - redis_data:/data ports: - "6379:6379" healthcheck: test: ["CMD", "redis-cli", "ping"] interval: 10s timeout: 5s retries: 5 networks: - app-network
# Elasticsearch search: image: docker.elastic.co/elasticsearch/elasticsearch:8.0.0 container_name: elasticsearch environment: - discovery.type=single-node - xpack.security.enabled=false - ES_JAVA_OPTS=-Xms512m -Xmx512m volumes: - elasticsearch_data:/usr/share/elasticsearch/data ports: - "9200:9200" healthcheck: test: ["CMD-SHELL", "curl -s http://localhost:9200/_cluster/health"] interval: 10s timeout: 5s retries: 5 networks: - app-network
# RabbitMQ Message Queue queue: image: rabbitmq:3-management container_name: rabbitmq environment: RABBITMQ_DEFAULT_USER: guest RABBITMQ_DEFAULT_PASS: guest volumes: - rabbitmq_data:/var/lib/rabbitmq ports: - "5672:5672" - "15672:15672" healthcheck: test: ["CMD", "rabbitmq-diagnostics", "-q", "ping"] interval: 10s timeout: 5s retries: 5 networks: - app-network
# Nginx Reverse Proxy nginx: image: nginx:alpine container_name: nginx-proxy ports: - "80:80" - "443:443" volumes: - ./nginx.conf:/etc/nginx/nginx.conf:ro - ./ssl:/etc/nginx/ssl:ro depends_on: - app networks: - app-network
volumes: postgres_data: redis_data: elasticsearch_data: rabbitmq_data:
networks: app-network: driver: bridge2. Environment-Specific Configuration
Section titled “2. Environment-Specific Configuration”# docker-compose.override.yml (Development)version: '3.9'
services: app: build: context: . args: - ENV=development environment: DEBUG: "true" volumes: - ./src:/app/src - /app/node_modules command: npm run dev
db: environment: POSTGRES_PASSWORD: devpassword ports: - "5432:5432"
---
# docker-compose.prod.yml (Production)version: '3.9'
services: app: build: context: . args: - ENV=production environment: NODE_ENV: production DEBUG: "false" restart: always deploy: resources: limits: cpus: '0.5' memory: 512M reservations: cpus: '0.25' memory: 256M
db: environment: POSTGRES_PASSWORD: ${DB_PASSWORD}3. Service Orchestration Script
Section titled “3. Service Orchestration Script”#!/bin/bashset -e
COMPOSE_FILE=${COMPOSE_FILE:-docker-compose.yml}ENV=${ENV:-development}
function build() { echo "Building services..." docker-compose -f $COMPOSE_FILE build}
function up() { echo "Starting services..." docker-compose -f $COMPOSE_FILE up -d echo "Services are running"}
function down() { echo "Stopping services..." docker-compose -f $COMPOSE_FILE down echo "Services stopped"}
function logs() { echo "Showing logs..." docker-compose -f $COMPOSE_FILE logs -f}
function ps() { echo "Service status:" docker-compose -f $COMPOSE_FILE ps}
function migrate() { echo "Running database migrations..." docker-compose -f $COMPOSE_FILE exec app npm run migrate}
function health() { echo "Checking service health..." services=$(docker-compose -f $COMPOSE_FILE config --services) for service in $services; do if docker-compose -f $COMPOSE_FILE ps $service | grep -q "Up"; then echo "✓ $service is running" else echo "✗ $service is not running" fi done}
case $1 in build) build ;; up) build && up && migrate && health ;; down) down ;; logs) logs ;; ps) ps ;; migrate) migrate ;; health) health ;; restart) down && up ;; *) echo "Usage: $0 {build|up|down|logs|ps|migrate|health|restart}" exit 1 ;;esac4. Local Development Setup
Section titled “4. Local Development Setup”version: '3.9'
services: app: build: context: . target: development environment: NODE_ENV: development DEBUG: "true" volumes: - ./src:/app/src - ./tests:/app/tests - /app/node_modules ports: - "3000:3000" - "9229:9229" # Debugger command: npm run dev
db: environment: POSTGRES_PASSWORD: devpassword volumes: - postgres_data:/var/lib/postgresql/data
# Development tools adminer: image: adminer ports: - "8080:8080" depends_on: - db
redis-commander: image: rediscommander/redis-commander:latest environment: - REDIS_HOSTS=local:cache:6379 ports: - "8081:8081" depends_on: - cache
volumes: postgres_data:5. Health Checks and Monitoring
Section titled “5. Health Checks and Monitoring”version: '3.9'
services: app: healthcheck: test: ["CMD", "curl", "-f", "http://localhost:3000/health"] interval: 30s timeout: 10s retries: 3 start_period: 40s
db: healthcheck: test: ["CMD-SHELL", "pg_isready -U user"] interval: 10s timeout: 5s retries: 5
cache: healthcheck: test: ["CMD", "redis-cli", "ping"] interval: 10s timeout: 3s retries: 3
# Monitoring with Prometheus prometheus: image: prom/prometheus volumes: - ./prometheus.yml:/etc/prometheus/prometheus.yml ports: - "9090:9090"
# Visualization with Grafana grafana: image: grafana/grafana ports: - "3001:3000" environment: - GF_SECURITY_ADMIN_PASSWORD=adminBest Practices
Section titled “Best Practices”-
Service Definition
- One service per container
- Clear naming conventions
- Document dependencies
- Set resource limits
-
Networking
- Define custom networks
- Use service names for discovery
- Expose only needed ports
- Secure communication
-
Volumes
- Named volumes for data
- Bind mounts for development
- Proper permissions
- Backup strategy
-
Configuration
- Environment variables
- Separate dev/prod configs
- Secrets management
- Documentation
-
Operations
- Health checks
- Restart policies
- Logging
- Monitoring
Real-World Applications
Section titled “Real-World Applications”- Local Development: Full-stack locally
- CI/CD Testing: Consistent test environment
- Demo Environments: Pre-configured demos
- Microservices: Local service topology
- Training: Reproducible setups