docker-compose-orchestration
Container orchestration with Docker Compose for multi-container applications, networking, volumes, and production deployment
- Category: discovered
- Tags: github, community
- Version: 1.0.0
- Author: walid
- Downloads: 0
- Updated: 2025-11-22
Download the latest version (v1.0.0) from this page.
SKILL.md
---
name: docker-compose-orchestration
description: Container orchestration with Docker Compose for multi-container applications, networking, volumes, and production deployment
---
# Docker Compose Orchestration
A comprehensive skill for orchestrating multi-container applications using Docker Compose. This skill enables rapid development, deployment, and management of containerized applications with service definitions, networking strategies, volume management, health checks, and production-ready configurations.
## When to Use This Skill
Use this skill when:
- Building multi-container applications (microservices, full-stack apps)
- Setting up development environments with databases, caching, and services
- Orchestrating frontend, backend, and database services together
- Managing service dependencies and startup order
- Configuring networks and inter-service communication
- Implementing persistent storage with volumes
- Deploying applications to development, staging, or production
- Creating reproducible development environments
- Managing application lifecycle (start, stop, rebuild, scale)
- Monitoring application health and implementing health checks
- Migrating from single containers to multi-service architectures
- Testing distributed systems locally
## Core Concepts
### Docker Compose Philosophy
Docker Compose simplifies multi-container application management through:
- **Declarative Configuration**: Define entire application stacks in YAML
- **Service Abstraction**: Each component is a service with its own configuration
- **Automatic Networking**: Services can communicate by name automatically
- **Volume Management**: Persistent data and shared storage across containers
- **Environment Isolation**: Each project gets its own network namespace
- **Reproducibility**: Same configuration works across all environments
### Key Docker Compose Entities
1. **Services**: Individual containers and their configurations
2. **Networks**: Communication channels between services
3. **Volumes**: Persistent storage and data sharing
4. **Configs**: Non-sensitive configuration files
5. **Secrets**: Sensitive data (passwords, API keys)
6. **Projects**: Collection of services under a single namespace
### Compose File Structure
```yaml
version: "3.8" # Compose file format version
services: # Define containers
service-name:
# Service configuration
networks: # Define custom networks
network-name:
# Network configuration
volumes: # Define named volumes
volume-name:
# Volume configuration
configs: # Application configs (optional)
config-name:
# Config source
secrets: # Sensitive data (optional)
secret-name:
# Secret source
```
## Service Definition Patterns
### Basic Service Definition
```yaml
services:
web:
image: nginx:alpine # Use existing image
container_name: my-web # Custom container name
restart: unless-stopped # Restart policy
ports:
- "80:80" # Host:Container port mapping
environment:
- ENV_VAR=value # Environment variables
volumes:
- ./html:/usr/share/nginx/html # Volume mount
networks:
- frontend # Connect to network
```
### Build-Based Service
```yaml
services:
app:
build:
context: ./app # Build context directory
dockerfile: Dockerfile # Custom Dockerfile
args: # Build arguments
NODE_ENV: development
target: development # Multi-stage build target
image: myapp:latest # Tag resulting image
ports:
- "3000:3000"
```
### Service with Dependencies
```yaml
services:
web:
image: nginx
depends_on:
db:
condition: service_healthy # Wait for health check
redis:
condition: service_started # Wait for start only
db:
image: postgres:15
healthcheck:
test: ["CMD-SHELL", "pg_isready -U postgres"]
interval: 10s
timeout: 5s
retries: 5
start_period: 30s
redis:
image: redis:alpine
```
### Service with Advanced Configuration
```yaml
services:
backend:
build: ./backend
command: npm run dev # Override default command
working_dir: /app # Set working directory
user: "1000:1000" # Run as specific user
hostname: api-server # Custom hostname
domainname: example.com # Domain name
env_file:
- .env # Load env from file
- .env.local
environment:
DATABASE_URL: "postgresql://db:5432/myapp"
REDIS_URL: "redis://cache:6379"
volumes:
- ./backend:/app # Source code mount
- /app/node_modules # Preserve node_modules
- app-data:/data # Named volume
ports:
- "3000:3000" # Application port
- "9229:9229" # Debug port
expose:
- "8080" # Expose to other services only
networks:
- backend
- frontend
labels:
- "com.example.description=Backend API"
- "com.example.version=1.0"
logging:
driver: json-file
options:
max-size: "10m"
max-file: "3"
deploy:
resources:
limits:
cpus: '2'
memory: 1G
reservations:
cpus: '0.5'
memory: 512M
```
## Multi-Container Application Patterns
### Pattern 1: Full-Stack Web Application
**Scenario:** React frontend + Node.js backend + PostgreSQL database
```yaml
version: "3.8"
services:
# Frontend React Application
frontend:
build:
context: ./frontend
dockerfile: Dockerfile
target: development
ports:
- "3000:3000"
volumes:
- ./frontend/src:/app/src
- /app/node_modules
environment:
- REACT_APP_API_URL=http://localhost:4000/api
- CHOKIDAR_USEPOLLING=true # For hot reload
networks:
- frontend
depends_on:
- backend
# Backend Node.js API
backend:
build:
context: ./backend
dockerfile: Dockerfile
ports:
- "4000:4000"
- "9229:9229" # Debugger
volumes:
- ./backend:/app
- /app/node_modules
environment:
- NODE_ENV=development
- DATABASE_URL=postgresql://postgres:password@db:5432/myapp
- REDIS_URL=redis://cache:6379
- JWT_SECRET=dev-secret
env_file:
- ./backend/.env.local
networks:
- frontend
- backend
depends_on:
db:
condition: service_healthy
cache:
condition: service_started
command: npm run dev
# PostgreSQL Database
db:
image: postgres:15-alpine
container_name: postgres-db
restart: unless-stopped
ports:
- "5432:5432"
environment:
- POSTGRES_USER=postgres
- POSTGRES_PASSWORD=password
- POSTGRES_DB=myapp
volumes:
- postgres-data:/var/lib/postgresql/data
- ./database/init.sql:/docker-entrypoint-initdb.d/init.sql
networks:
- backend
healthcheck:
test: ["CMD-SHELL", "pg_isready -U postgres"]
interval: 10s
timeout: 5s
retries: 5
# Redis Cache
cache:
image: redis:7-alpine
container_name: redis-cache
restart: unless-stopped
ports:
- "6379:6379"
volumes:
- redis-data:/data
networks:
- backend
command: redis-server --appendonly yes
healthcheck:
test: ["CMD", "redis-cli", "ping"]
interval: 10s
timeout: 3s
retries: 5
networks:
frontend:
driver: bridge
backend:
driver: bridge
volumes:
postgres-data:
driver: local
redis-data:
driver: local
```
### Pattern 2: Microservices Architecture
**Scenario:** Multiple services with reverse proxy and service discovery
```yaml
version: "3.8"
services:
# NGINX Reverse Proxy
proxy:
image: nginx:alpine
container_name: reverse-proxy
ports:
- "80:80"
- "443:443"
volumes:
- ./nginx/nginx.conf:/etc/nginx/nginx.conf:ro
- ./nginx/conf.d:/etc/nginx/conf.d:ro
- ./ssl:/etc/nginx/ssl:ro
networks:
- public
depends_on:
- auth-service
- user-service
- order-service
restart: unless-stopped
# Authentication Service
auth-service:
build: ./services/auth
container_name: auth-service
expose:
- "8001"
environment:
- SERVICE_NAME=auth
- DATABASE_URL=postgresql://db:5432/auth_db
- JWT_SECRET=${JWT_SECRET}
networks:
- public
- internal
depends_on:
db:
condition: service_healthy
healthcheck:
test: ["CMD", "curl", "-f", "http://localhost:8001/health"]
interval: 30s
timeout: 10s
retries: 3
# User Service
user-service:
build: ./services/user
container_name: user-service
expose:
- "8002"
environment:
- SERVICE_NAME=user
- DATABASE_URL=postgresql://db:5432/user_db
- AUTH_SERVICE_URL=http://auth-service:8001
networks:
- public
- internal
depends_on:
- auth-service
- db
healthcheck:
test: ["CMD", "curl", "-f", "http://localhost:8002/health"]
interval: 30s
timeout: 10s
retries: 3
# Order Service
order-service:
build: ./services/order
container_name: order-service
expose:
- "8003"
environment:
- SERVICE_NAME=order
- DATABASE_URL=postgresql://db:5432/order_db
- USER_SERVICE_URL=http://user-service:8002
- RABBITMQ_URL=amqp://rabbitmq:5672
networks:
- public
- internal
depends_on:
- user-service
- db
- rabbitmq
healthcheck:
test: ["CMD", "curl", "-f", "http://localhost:8003/health"]
interval: 30s
timeout: 10s
retries: 3
# Shared PostgreSQL Database
db:
image: postgres:15-alpine
container_name: postgres-db
environment:
- POSTGRES_USER=postgres
- POSTGRES_PASSWORD=${DB_PASSWORD}
volumes:
- postgres-data:/var/lib/postgresql/data
- ./database/init-multi-db.sql:/docker-entrypoint-initdb.d/init.sql
networks:
- internal
healthcheck:
test: ["CMD-SHELL", "pg_isready -U postgres"]
interval: 10s
timeout: 5s
retries: 5
# RabbitMQ Message Broker
rabbitmq:
image: rabbitmq:3-management-alpine
container_name: rabbitmq
ports:
- "5672:5672" # AMQP
- "15672:15672" # Management UI
environment:
- RABBITMQ_DEFAULT_USER=admin
- RABBITMQ_DEFAULT_PASS=${RABBITMQ_PASSWORD}
volumes:
- rabbitmq-data:/var/lib/rabbitmq
networks:
- internal
healthcheck:
test: ["CMD", "rabbitmq-diagnostics", "ping"]
interval: 30s
timeout: 10s
retries: 5
networks:
public:
driver: bridge
internal:
driver: bridge
internal: true # No external access
volumes:
postgres-data:
rabbitmq-data:
```
### Pattern 3: Development Environment with Hot Reload
**Scenario:** Development setup with live code reloading and debugging
```yaml
version: "3.8"
services:
# Development Frontend
frontend-dev:
build:
context: ./frontend
dockerfile: Dockerfile.dev
ports:
- "3000:3000"
- "9222:9222" # Chrome DevTools
volumes:
- ./frontend:/app
- /app/node_modules
- /app/.next # Next.js build cache
environment:
- NODE_ENV=development
- WATCHPACK_POLLING=true
- NEXT_PUBLIC_API_URL=http://localhost:4000
networks:
- dev-network
stdin_open: true
tty: true
command: npm run dev
# Development Backend
backend-dev:
build:
context: ./backend
dockerfile: Dockerfile.dev
ports:
- "4000:4000"
- "9229:9229" # Node.js debugger
volumes:
- ./backend:/app
- /app/node_modules
environment:
- NODE_ENV=development
- DEBUG=app:*
- DATABASE_URL=postgresql://postgres:dev@db:5432/dev_db
networks:
- dev-network
depends_on:
- db
- mailhog
command: npm run dev:debug
# PostgreSQL with pgAdmin
db:
image: postgres:15-alpine
environment:
- POSTGRES_PASSWORD=dev
- POSTGRES_DB=dev_db
ports:
- "5432:5432"
volumes:
- dev-db-data:/var/lib/postgresql/data
networks:
- dev-network
pgadmin:
image: dpage/pgadmin4:latest
environment:
- PGADMIN_DEFAULT_EMAIL=admin@dev.local
- PGADMIN_DEFAULT_PASSWORD=admin
ports:
- "5050:80"
networks:
- dev-network
depends_on:
- db
# MailHog for Email Testing
mailhog:
image: mailhog/mailhog:latest
ports:
- "1025:1025" # SMTP
- "8025:8025" # Web UI
networks:
- dev-network
networks:
dev-network:
driver: bridge
volumes:
dev-db-data:
```
## Networking Strategies
### Default Bridge Network
```yaml
services:
web:
image: nginx
# Automatically connected to default network
app:
image: myapp
# Can communicate with 'web' via service name
```
### Custom Bridge Networks
```yaml
version: "3.8"
services:
frontend:
image: react-app
networks:
- public
backend:
image: api-server
networks:
- public # Accessible from frontend
- private # Accessible from database
database:
image: postgres
networks:
- private # Isolated from frontend
networks:
public:
driver: bridge
private:
driver: bridge
internal: true # No internet access
```
### Network Aliases
```yaml
services:
api:
image: api-server
networks:
backend:
aliases:
- api-server
- api.internal
- api-v1.internal
networks:
backend:
driver: bridge
```
### Host Network Mode
```yaml
services:
app:
image: myapp
network_mode: "host" # Use host network stack
# No port mapping needed, uses host ports directly
```
### Custom Network Configuration
```yaml
networks:
custom-network:
driver: bridge
driver_opts:
com.docker.network.bridge.name: br-custom
ipam:
driver: default
config:
- subnet: 172.28.0.0/16
gateway: 172.28.0.1
labels:
- "com.example.description=Custom network"
```
## Volume Management
### Named Volumes
```yaml
version: "3.8"
services:
db:
image: postgres:15
volumes:
- postgres-data:/var/lib/postgresql/data # Named volume
backup:
image: postgres:15
volumes:
- postgres-data:/backup:ro # Read-only mount
command: pg_dump -U postgres > /backup/dump.sql
volumes:
postgres-data:
driver: local
driver_opts:
type: none
o: bind
device: /path/on/host
```
### Bind Mounts
```yaml
services:
web:
image: nginx
volumes:
# Relative path bind mount
- ./html:/usr/share/nginx/html
# Absolute path bind mount
- /var/log/nginx:/var/log/nginx
# Read-only bind mount
- ./config/nginx.conf:/etc/nginx/nginx.conf:ro
```
### tmpfs Mounts (In-Memory)
```yaml
services:
app:
image: myapp
tmpfs:
- /tmp
- /run
# Or with options:
volumes:
- type: tmpfs
target: /app/cache
tmpfs:
size: 1000000000 # 1GB
```
### Volume Sharing Between Services
```yaml
services:
app:
image: myapp
volumes:
- shared-data:/data
worker:
image: worker
volumes:
- shared-data:/data
backup:
image: backup-tool
volumes:
- shared-data:/backup:ro
volumes:
shared-data:
```
### Advanced Volume Configuration
```yaml
volumes:
data:
driver: local
driver_opts:
type: "nfs"
o: "addr=10.40.0.199,nolock,soft,rw"
device: ":/docker/example"
cache:
driver: local
driver_opts:
type: tmpfs
device: tmpfs
o: "size=100m,uid=1000"
external-volume:
external: true # Volume created outside Compose
name: my-existing-volume
```
## Health Checks
### HTTP Health Check
```yaml
services:
web:
image: nginx
healthcheck:
test: ["CMD", "curl", "-f", "http://localhost/health"]
interval: 30s
timeout: 10s
retries: 3
start_period: 40s
```
### Database Health Check
```yaml
services:
postgres:
image: postgres:15
healthcheck:
test: ["CMD-SHELL", "pg_isready -U postgres"]
interval: 10s
timeout: 5s
retries: 5
start_period: 30s
mysql:
image: mysql:8
healthcheck:
test: ["CMD", "mysqladmin", "ping", "-h", "localhost"]
interval: 10s
timeout: 5s
retries: 3
mongodb:
image: mongo:6
healthcheck:
test: ["CMD", "mongosh", "--eval", "db.adminCommand('ping')"]
interval: 10s
timeout: 5s
retries: 5
```
### Application Health Check
```yaml
services:
app:
build: ./app
healthcheck:
test: ["CMD", "node", "healthcheck.js"]
interval: 30s
timeout: 10s
retries: 3
start_period: 60s
api:
build: ./api
healthcheck:
test: ["CMD-SHELL", "wget --no-verbose --tries=1 --spider http://localhost:3000/health || exit 1"]
interval: 30s
timeout: 10s
retries: 3
```
### Complex Health Checks
```yaml
services:
redis:
image: redis:alpine
healthcheck:
test: |
sh -c '
redis-cli ping | grep PONG &&
redis-cli --raw incr ping | grep 1
'
interval: 10s
timeout: 3s
retries: 5
```
## Development vs Production Configurations
### Base Configuration (compose.yaml)
```yaml
version: "3.8"
services:
web:
image: myapp:latest
environment:
- NODE_ENV=production
networks:
- app-network
db:
image: postgres:15-alpine
networks:
- app-network
networks:
app-network:
driver: bridge
```
### Development Override (compose.override.yaml)
```yaml
# Automatically merged with compose.yaml in development
version: "3.8"
services:
web:
build:
context: .
target: development
volumes:
- ./src:/app/src # Live code reload
- /app/node_modules
ports:
- "3000:3000" # Expose for local access
- "9229:9229" # Debugger port
environment:
- NODE_ENV=development
- DEBUG=*
command: npm run dev
db:
ports:
- "5432:5432" # Expose for local tools
environment:
- POSTGRES_PASSWORD=dev
volumes:
- ./init-dev.sql:/docker-entrypoint-initdb.d/init.sql
```
### Production Configuration (compose.prod.yaml)
```yaml
version: "3.8"
services:
web:
image: myapp:${VERSION:-latest}
restart: always
environment:
- NODE_ENV=production
deploy:
replicas: 3
resources:
limits:
cpus: '2'
memory: 2G
reservations:
cpus: '1'
memory: 1G
update_config:
parallelism: 1
delay: 10s
failure_action: rollback
rollback_config:
parallelism: 1
delay: 5s
logging:
driver: json-file
options:
max-size: "10m"
max-file: "5"
db:
image: postgres:15-alpine
restart: always
environment:
- POSTGRES_PASSWORD_FILE=/run/secrets/db_password
secrets:
- db_password
volumes:
- postgres-data:/var/lib/postgresql/data
deploy:
resources:
limits:
cpus: '2'
memory: 4G
# Production additions
nginx:
image: nginx:alpine
ports:
- "80:80"
- "443:443"
volumes:
- ./nginx/prod.conf:/etc/nginx/nginx.conf:ro
- ssl-certs:/etc/nginx/ssl:ro
restart: always
depends_on:
- web
secrets:
db_password:
external: true
volumes:
postgres-data:
driver: local
ssl-certs:
external: true
```
### Staging Configuration (compose.staging.yaml)
```yaml
version: "3.8"
services:
web:
image: myapp:staging-