Docker Compose

What is Docker Compose?

Docker Compose is a tool for defining and running multi-container Docker applications. Instead of manually starting multiple containers with individual docker run commands, Compose uses a YAML file to orchestrate all services, networks, and volumes as a single application unit.


Why Use Docker Compose?

Managing multiple containers manually becomes complex quickly. Docker Compose solves this by:

graph LR A["YAML File
docker-compose.yml"] -->B["Single Command
docker-compose up"] B -->C["Multiple Containers
Networked Together"] C -->D["Services Share
Network & Storage"] style A fill:#e1f5ff style B fill:#fff3e0 style C fill:#e8f5e9 style D fill:#f3e5f5

Basic Structure

Simple Web Application with Database

version: '3.8' services: web: build: . ports: - "5000:5000" environment: - DATABASE_URL=postgres://db:5432/myapp depends_on: - db db: image: postgres:15-alpine environment: - POSTGRES_DB=myapp - POSTGRES_PASSWORD=secret volumes: - db_data:/var/lib/postgresql/data volumes: db_data:

Start everything with one command:

docker-compose up

Key Components

Services

Individual containers that make up the application. Services can reference each other by name.

services: api: build: ./api ports: - "3000:3000" frontend: build: ./frontend ports: - "80:80" depends_on: - api

Containers communicate using service names:

// frontend connecting to api service const response = await fetch('http://api:3000/data');

Networks

Services automatically join a shared network. This enables service-to-service communication.

services: web: networks: - frontend api: networks: - frontend - backend db: networks: - backend networks: frontend: backend:

Volumes

Persist data across container restarts or share data between containers.

services: database: image: postgres:15-alpine volumes: # Named volume (managed by Docker) - postgres_data:/var/lib/postgresql/data # Bind mount (host directory) - ./init.sql:/docker-entrypoint-initdb.d/init.sql volumes: postgres_data:

Common Commands

Command Purpose
docker-compose up Start all services
docker-compose up -d Start in background (detached)
docker-compose down Stop and remove containers
docker-compose ps List running containers
docker-compose logs View container logs
docker-compose exec SERVICE CMD Run command in service
docker-compose build Build/rebuild images

Real-World Example: Full Stack Application

version: '3.8' services: frontend: build: context: ./frontend dockerfile: Dockerfile ports: - "3000:3000" environment: - REACT_APP_API_URL=http://localhost:5000 depends_on: - api api: build: context: ./api dockerfile: Dockerfile ports: - "5000:5000" environment: - DATABASE_URL=postgres://db:5432/myapp - REDIS_URL=redis://cache:6379 depends_on: - db - cache volumes: - ./api:/app db: image: postgres:15-alpine environment: - POSTGRES_DB=myapp - POSTGRES_USER=appuser - POSTGRES_PASSWORD=secure_password volumes: - postgres_data:/var/lib/postgresql/data - ./scripts/init.sql:/docker-entrypoint-initdb.d/init.sql healthcheck: test: ["CMD-SHELL", "pg_isready -U appuser"] interval: 10s timeout: 5s retries: 5 cache: image: redis:7-alpine volumes: - redis_data:/data healthcheck: test: ["CMD", "redis-cli", "ping"] interval: 10s timeout: 5s retries: 5 volumes: postgres_data: redis_data: networks: default: name: app_network

Start the full application:

docker-compose up -d # Check status docker-compose ps # View logs docker-compose logs -f api # Execute command docker-compose exec db psql -U appuser -d myapp

Environment Variables

Use .env file for configuration:

# .env POSTGRES_PASSWORD=production_password API_PORT=5000 DEBUG=false

Reference in compose file:

services: db: environment: - POSTGRES_PASSWORD=${POSTGRES_PASSWORD} api: ports: - "${API_PORT}:5000"

Development vs Production

Development Setup (docker-compose.yml)

services: api: build: . volumes: - .:/app environment: - DEBUG=true

Production Setup (docker-compose.prod.yml)

services: api: image: myregistry.azurecr.io/api:v1.0 restart: always healthcheck: test: ["CMD", "curl", "-f", "http://localhost:5000/health"]

Deploy production version:

docker-compose -f docker-compose.prod.yml up -d

Common Pitfalls


Key Takeaways

Next Steps: Create docker-compose.yml for current projects, implement health checks for all services, and establish separate development and production configurations.