Docker Compose
Multi-service orchestration for development and production
📋 Overview
Docker Compose orchestrates all Izri services, handling networking, volumes, and service dependencies. We maintain separate configurations for development and production environments.
🐳 Compose Files
File Structure
project-root/
├── docker-compose.yml # Production configuration
├── docker-compose.dev.yml # Development configuration (with hot reload)
└── docker/
├── web/Dockerfile
├── api/Dockerfile
└── ai-service/Dockerfile
📦 Production Configuration
File: docker-compose.yml
services:
postgres:
image: postgres:15
environment:
POSTGRES_DB: izri
POSTGRES_USER: postgres
POSTGRES_PASSWORD: password
ports:
- "5433:5432"
volumes:
- postgres_data:/var/lib/postgresql/data
healthcheck:
test: ["CMD-SHELL", "pg_isready -U postgres"]
interval: 10s
timeout: 5s
retries: 5
redis:
image: redis:7-alpine
ports:
- "6380:6379"
healthcheck:
test: ["CMD", "redis-cli", "ping"]
interval: 10s
timeout: 5s
retries: 5
api:
build:
context: .
dockerfile: docker/api/Dockerfile
ports:
- "4000:4000"
environment:
- DATABASE_URL=postgresql://postgres:password@postgres:5432/izri
- REDIS_URL=redis://redis:6379
- LOG_LEVEL=info
- NODE_ENV=production
depends_on:
postgres:
condition: service_healthy
redis:
condition: service_healthy
web:
build:
context: .
dockerfile: docker/web/Dockerfile
ports:
- "3000:3000"
environment:
- VITE_API_URL=http://api:4000
- NODE_ENV=production
depends_on:
- api
ai-service:
build:
context: .
dockerfile: docker/ai-service/Dockerfile
ports:
- "8000:8000"
environment:
- OPENAI_API_KEY=${OPENAI_API_KEY}
- ANTHROPIC_API_KEY=${ANTHROPIC_API_KEY}
volumes:
postgres_data:
🔧 Development Configuration
File: docker-compose.dev.yml
services:
postgres:
image: postgres:15
environment:
POSTGRES_DB: izri_dev
POSTGRES_USER: postgres
POSTGRES_PASSWORD: password
ports:
- "5433:5432"
volumes:
- postgres_dev_data:/var/lib/postgresql/data
healthcheck:
test: ["CMD-SHELL", "pg_isready -U postgres"]
interval: 10s
timeout: 5s
retries: 5
redis:
image: redis:7-alpine
ports:
- "6380:6379"
volumes:
- redis_dev_data:/data
healthcheck:
test: ["CMD", "redis-cli", "ping"]
interval: 10s
timeout: 5s
retries: 5
# API with hot reload
api:
build:
context: .
dockerfile: docker/api/Dockerfile.dev
ports:
- "4000:4000"
volumes:
- ./apps/api:/app/apps/api
- ./packages:/app/packages
- /app/node_modules
environment:
- DATABASE_URL=postgresql://postgres:password@postgres:5432/izri_dev
- REDIS_URL=redis://redis:6379
- LOG_LEVEL=debug
- NODE_ENV=development
depends_on:
postgres:
condition: service_healthy
# Web with hot reload
web:
build:
context: .
dockerfile: docker/web/Dockerfile.dev
ports:
- "5173:5173"
volumes:
- ./apps/web:/app/apps/web
- ./packages:/app/packages
- /app/node_modules
environment:
- VITE_API_URL=http://localhost:4000
- NODE_ENV=development
depends_on:
- api
ai-service:
build:
context: .
dockerfile: docker/ai-service/Dockerfile
ports:
- "8000:8000"
volumes:
- ./packages/ai-service:/app/packages/ai-service
- /app/packages/ai-service/__pycache__
environment:
- OPENAI_API_KEY=${OPENAI_API_KEY}
- ANTHROPIC_API_KEY=${ANTHROPIC_API_KEY}
- LOG_LEVEL=debug
volumes:
postgres_dev_data:
redis_dev_data:
🚀 Common Commands
Starting Services
# Start all services (production)
docker compose up
# Start in detached mode (background)
docker compose up -d
# Start specific services
docker compose up postgres redis
# Development mode (with hot reload)
docker compose -f docker-compose.dev.yml up
Stopping Services
# Stop all services
docker compose down
# Stop and remove volumes
docker compose down -v
# Stop specific service
docker compose stop api
Building Services
# Build all services
docker compose build
# Build specific service
docker compose build web
# Build with no cache
docker compose build --no-cache
# Parallel builds
docker compose build --parallel
Viewing Logs
# All services
docker compose logs
# Follow logs (live)
docker compose logs -f
# Specific service
docker compose logs api
# Last 100 lines
docker compose logs --tail=100
# Since timestamp
docker compose logs --since 2024-01-01T00:00:00
Service Status
# List running services
docker compose ps
# Check service health
docker compose ps
# View service details
docker inspect <service-name>
🔍 Service Management
Restart Services
# Restart all
docker compose restart
# Restart specific service
docker compose restart api
# Restart with rebuild
docker compose up -d --build api
Scale Services
# Run multiple instances
docker compose up -d --scale api=3
# Check scaled services
docker compose ps
Exec into Containers
# API container
docker compose exec api sh
# Postgres container
docker compose exec postgres psql -U postgres -d izri
# Redis container
docker compose exec redis redis-cli
🌐 Networking
Default Network
Docker Compose creates a default network where all services can communicate:
services:
api:
# Can access postgres at: postgres:5432
# Can access redis at: redis:6379
postgres:
# Accessible from other services as 'postgres'
Service Discovery
Internal communication:
// API connects to postgres
const DATABASE_URL = 'postgresql://postgres:password@postgres:5432/izri'
// API connects to redis
const REDIS_URL = 'redis://redis:6379'
External access:
# From host machine
psql -h localhost -p 5433 -U postgres -d izri
redis-cli -h localhost -p 6380
Custom Networks
networks:
frontend:
backend:
database:
services:
web:
networks:
- frontend
api:
networks:
- frontend
- backend
postgres:
networks:
- backend
💾 Volume Management
Named Volumes
volumes:
postgres_data: # Managed by Docker
redis_data: # Persists between restarts
# List volumes
docker volume ls
# Inspect volume
docker volume inspect izri_postgres_data
# Remove volume
docker volume rm izri_postgres_data
# Remove all unused volumes
docker volume prune
Bind Mounts (Development)
services:
api:
volumes:
- ./apps/api:/app/apps/api # Source code
- /app/node_modules # Anonymous volume (don't override)
How it works:
- Host directory
./apps/apimounted into container - Changes on host immediately reflected in container
- Enables hot reload for development
Volume Backup
# Backup postgres volume
docker run --rm \
-v izri_postgres_data:/data \
-v $(pwd):/backup \
alpine tar czf /backup/postgres-backup.tar.gz /data
# Restore postgres volume
docker run --rm \
-v izri_postgres_data:/data \
-v $(pwd):/backup \
alpine tar xzf /backup/postgres-backup.tar.gz -C /
🔐 Environment Variables
Using .env File
Create .env file (root directory):
# Database
POSTGRES_USER=postgres
POSTGRES_PASSWORD=secure_password_here
POSTGRES_DB=izri
# API Keys
OPENAI_API_KEY=sk-...
ANTHROPIC_API_KEY=sk-ant-...
GITHUB_CLIENT_ID=github_client_id
GITHUB_CLIENT_SECRET=github_secret
# JWT
JWT_SECRET=your_secure_jwt_secret_here
# Environment
NODE_ENV=production
LOG_LEVEL=info
Load Environment Variables
services:
api:
env_file:
- .env
environment:
- DATABASE_URL=postgresql://${POSTGRES_USER}:${POSTGRES_PASSWORD}@postgres:5432/${POSTGRES_DB}
Override with Shell
# Set variable for this command only
OPENAI_API_KEY=sk-... docker compose up
# Export for all commands
export OPENAI_API_KEY=sk-...
docker compose up
🏥 Health Checks
Postgres Health Check
postgres:
healthcheck:
test: ["CMD-SHELL", "pg_isready -U postgres"]
interval: 10s # Check every 10 seconds
timeout: 5s # Fail if takes >5s
retries: 5 # Try 5 times before marking unhealthy
Redis Health Check
redis:
healthcheck:
test: ["CMD", "redis-cli", "ping"]
interval: 10s
timeout: 5s
retries: 5
API Health Check
api:
healthcheck:
test: ["CMD", "curl", "-f", "http://localhost:4000/health"]
interval: 30s
timeout: 10s
retries: 3
start_period: 40s # Don't check for first 40s
Using Health Checks in depends_on
services:
api:
depends_on:
postgres:
condition: service_healthy # Wait for postgres to be healthy
redis:
condition: service_healthy
web:
depends_on:
api:
condition: service_started # Just wait for api to start
🔧 Development Workflow
Daily Development
# 1. Start services
pnpm docker:up
# or: docker compose -f docker-compose.dev.yml up -d
# 2. Check status
docker compose ps
# 3. View logs
pnpm docker:logs
# or: docker compose logs -f
# 4. Run migrations
pnpm db:migrate
# 5. Stop services
pnpm docker:down
# or: docker compose down
Rebuilding After Changes
# Rebuild specific service
docker compose up -d --build api
# Rebuild all
docker compose up -d --build
# Force complete rebuild
docker compose down
docker compose build --no-cache
docker compose up -d
🐛 Troubleshooting
Service Won't Start
Check logs:
docker compose logs <service-name>
Common issues:
- Port already in use: Change port mapping
- Health check failing: Check service logs
- Volume permission issues: Check file ownership
Port Conflicts
Problem: Port 5433 already in use
Solution:
postgres:
ports:
- "5434:5432" # Change external port
Database Connection Issues
Problem: API can't connect to postgres
Solutions:
# 1. Check postgres is healthy
docker compose ps
# 2. Check network
docker compose exec api ping postgres
# 3. Verify connection string
docker compose exec api env | grep DATABASE_URL
Volume Permission Errors
Problem: Permission denied on mounted volumes
Solution:
# In Dockerfile, match host user ID
RUN adduser --uid 1000 --disabled-password appuser
USER appuser
Stale Data in Volumes
Problem: Old data persisting
Solution:
# Remove volumes and recreate
docker compose down -v
docker compose up -d
📊 Monitoring Services
Resource Usage
# CPU and memory usage
docker stats
# Specific services
docker stats api web
Container Inspection
# Detailed container info
docker compose exec api env
# Network details
docker network inspect izri_default
# Volume mount points
docker compose exec api df -h
🔗 Related Documentation
- Docker Setup: Dockerfile configuration
- Production: Production deployment
- Environment: Environment variables
- Monitoring: Monitoring and logging
Ready for production? Continue with Production Deployment →