The Compose File
The Docker Compose file is a YAML configuration file that defines your entire application stack. This lesson covers all major configuration options.
File Structure Overview
# Top-level keys
services: # Container definitions (required)
volumes: # Named volume definitions
networks: # Network definitions
configs: # Configuration file definitions
secrets: # Secret file definitions
Service Configuration
Basic Service
services:
web:
image: nginx:alpine
ports:
- "80:80"
Building from Dockerfile
services:
api:
build: ./backend # Directory with Dockerfile
# With options
frontend:
build:
context: ./frontend # Build context
dockerfile: Dockerfile.prod # Specific Dockerfile
args: # Build arguments
NODE_ENV: production
target: production # Multi-stage target
Image Configuration
services:
web:
image: nginx:alpine
custom:
build: .
image: myregistry/myapp:latest # Tag built image
Port Mapping
services:
web:
image: nginx
ports:
# HOST:CONTAINER
- "80:80"
- "443:443"
# Random host port
- "80"
# Bind to specific interface
- "127.0.0.1:8080:80"
# UDP ports
- "53:53/udp"
# Long syntax
- target: 80
published: 8080
protocol: tcp
mode: host
Environment Variables
services:
api:
image: myapi
environment:
# Map syntax
NODE_ENV: production
DATABASE_URL: postgresql://db:5432/mydb
# List syntax
- NODE_ENV=production
- DATABASE_URL=postgresql://db:5432/mydb
# From file
env_file:
- .env
- .env.local
Environment File
# .env
POSTGRES_PASSWORD=secret
API_KEY=abc123
DEBUG=false
services:
db:
image: postgres
env_file: .env
Volumes
services:
db:
image: postgres
volumes:
# Named volume
- postgres-data:/var/lib/postgresql/data
# Bind mount
- ./init.sql:/docker-entrypoint-initdb.d/init.sql
# Read-only
- ./config:/app/config:ro
# Anonymous volume
- /var/lib/postgresql/data
# Long syntax
- type: volume
source: postgres-data
target: /var/lib/postgresql/data
- type: bind
source: ./data
target: /app/data
read_only: true
volumes:
postgres-data: # Define named volume
driver: local
Networks
services:
web:
networks:
- frontend
api:
networks:
- frontend
- backend
db:
networks:
- backend
networks:
frontend:
backend:
driver: bridge
ipam:
config:
- subnet: 172.20.0.0/24
Network Aliases
services:
db:
image: postgres
networks:
backend:
aliases:
- database
- primary
Dependencies
services:
web:
depends_on:
- api # Simple: start api before web
api:
depends_on:
db:
condition: service_healthy # Wait for health check
redis:
condition: service_started # Just started
db:
image: postgres
healthcheck:
test: ["CMD-SHELL", "pg_isready -U postgres"]
interval: 5s
timeout: 5s
retries: 5
Health Checks
services:
api:
image: myapi
healthcheck:
test: ["CMD", "curl", "-f", "http://localhost:3000/health"]
interval: 30s # Time between checks
timeout: 10s # Timeout for single check
retries: 3 # Failures before unhealthy
start_period: 40s # Grace period on startup
# Disable health check from image
db:
image: postgres
healthcheck:
disable: true
Resource Limits
services:
api:
image: myapi
deploy:
resources:
limits:
cpus: '0.50' # 50% of one CPU
memory: 512M # 512 MB RAM
reservations:
cpus: '0.25'
memory: 256M
Restart Policies
services:
web:
restart: "no" # Never restart (default)
api:
restart: always # Always restart
worker:
restart: on-failure # Only on error
db:
restart: unless-stopped # Unless manually stopped
Command and Entrypoint
services:
api:
image: node:18
working_dir: /app
# Override CMD
command: npm run dev
# Or as array
command: ["npm", "run", "dev"]
# Override ENTRYPOINT
entrypoint: /custom-entrypoint.sh
Logging
services:
api:
image: myapi
logging:
driver: json-file
options:
max-size: "10m"
max-file: "3"
# Disable logging
worker:
logging:
driver: none
Labels
services:
web:
image: nginx
labels:
- "traefik.enable=true"
- "traefik.http.routers.web.rule=Host(`example.com`)"
# Or map syntax
labels:
com.example.description: "Web server"
com.example.environment: "production"
Profiles
Run different service sets:
services:
web:
image: nginx
api:
image: myapi
debug:
image: debug-tools
profiles:
- debug # Only starts with debug profile
monitoring:
image: prometheus
profiles:
- monitoring
# Start default services
docker compose up -d
# Start with debug profile
docker compose --profile debug up -d
# Multiple profiles
docker compose --profile debug --profile monitoring up -d
Extends and Anchors
YAML Anchors
x-common: &common
restart: always
logging:
driver: json-file
options:
max-size: "10m"
services:
api:
<<: *common # Inherit common settings
image: myapi
worker:
<<: *common
image: myworker
Extends (from other files)
# base.yml
services:
api:
build: .
environment:
NODE_ENV: production
# docker-compose.yml
services:
api:
extends:
file: base.yml
service: api
ports:
- "3000:3000"
Complete Example
version: "3.8"
x-common-env: &common-env
TZ: UTC
LOG_LEVEL: info
services:
web:
build:
context: ./frontend
target: production
ports:
- "80:80"
depends_on:
api:
condition: service_healthy
restart: unless-stopped
api:
build:
context: ./backend
args:
NODE_ENV: production
environment:
<<: *common-env
DATABASE_URL: postgresql://postgres:${DB_PASSWORD}@db:5432/app
REDIS_URL: redis://redis:6379
ports:
- "3000:3000"
depends_on:
db:
condition: service_healthy
redis:
condition: service_started
healthcheck:
test: ["CMD", "curl", "-f", "http://localhost:3000/health"]
interval: 10s
timeout: 5s
retries: 3
restart: unless-stopped
db:
image: postgres:15
environment:
POSTGRES_PASSWORD: ${DB_PASSWORD}
POSTGRES_DB: app
volumes:
- postgres-data:/var/lib/postgresql/data
- ./init.sql:/docker-entrypoint-initdb.d/init.sql:ro
healthcheck:
test: ["CMD-SHELL", "pg_isready -U postgres"]
interval: 5s
timeout: 5s
retries: 5
restart: unless-stopped
redis:
image: redis:alpine
volumes:
- redis-data:/data
restart: unless-stopped
volumes:
postgres-data:
redis-data:
Key Takeaways
- Services define containers with their configuration
- Use
buildfor custom images,imagefor pre-built - Environment variables can come from files or inline
- Define networks for isolation between service groups
- Use
depends_onwith conditions for proper startup order - Health checks ensure dependencies are truly ready
- YAML anchors reduce configuration duplication
- Profiles enable optional services for different scenarios

