Real-World Docker Compose Projects and Implementation
This final section demonstrates complete production-ready implementations, combining all concepts learned throughout this guide into real-world systems with full CI/CD integration and operational excellence.
Project 1: Enterprise SaaS Platform
Complete Multi-Tenant Architecture
# docker-compose.prod.yml
version: '3.8'
services:
# Load Balancer with SSL Termination
traefik:
image: traefik:v2.9
ports:
- "80:80"
- "443:443"
- "8080:8080"
volumes:
- /var/run/docker.sock:/var/run/docker.sock:ro
- ./traefik/traefik.yml:/etc/traefik/traefik.yml:ro
- ./traefik/dynamic:/etc/traefik/dynamic:ro
- traefik_certs:/certs
networks:
- frontend
- monitoring
labels:
- "traefik.enable=true"
- "traefik.http.routers.dashboard.rule=Host(`traefik.${DOMAIN}`)"
- "traefik.http.routers.dashboard.tls.certresolver=letsencrypt"
# Frontend Application
frontend:
image: ${REGISTRY}/frontend:${VERSION}
deploy:
replicas: 3
resources:
limits:
memory: 512M
reservations:
memory: 256M
networks:
- frontend
labels:
- "traefik.enable=true"
- "traefik.http.routers.frontend.rule=Host(`${DOMAIN}`) || Host(`www.${DOMAIN}`)"
- "traefik.http.routers.frontend.tls.certresolver=letsencrypt"
- "traefik.http.services.frontend.loadbalancer.server.port=80"
healthcheck:
test: ["CMD", "curl", "-f", "http://localhost/health"]
interval: 30s
timeout: 10s
retries: 3
# API Gateway
api-gateway:
image: ${REGISTRY}/api-gateway:${VERSION}
deploy:
replicas: 2
resources:
limits:
memory: 1G
reservations:
memory: 512M
networks:
- frontend
- backend
environment:
- JWT_SECRET_FILE=/run/secrets/jwt_secret
- DATABASE_URL=postgresql://api_user:${API_DB_PASSWORD}@postgres-master:5432/api_db
- REDIS_URL=redis://redis-cluster:6379/0
secrets:
- jwt_secret
labels:
- "traefik.enable=true"
- "traefik.http.routers.api.rule=Host(`api.${DOMAIN}`)"
- "traefik.http.routers.api.tls.certresolver=letsencrypt"
healthcheck:
test: ["CMD", "curl", "-f", "http://localhost:8000/health"]
interval: 30s
timeout: 10s
retries: 3
# User Service
user-service:
image: ${REGISTRY}/user-service:${VERSION}
deploy:
replicas: 2
networks:
- backend
- database
environment:
- DATABASE_URL=postgresql://user_svc:${USER_DB_PASSWORD}@postgres-master:5432/users_db
- REDIS_URL=redis://redis-cluster:6379/1
- ENCRYPTION_KEY_FILE=/run/secrets/encryption_key
secrets:
- encryption_key
healthcheck:
test: ["CMD", "curl", "-f", "http://localhost:8001/health"]
interval: 30s
timeout: 10s
retries: 3
# Tenant Service
tenant-service:
image: ${REGISTRY}/tenant-service:${VERSION}
deploy:
replicas: 2
networks:
- backend
- database
environment:
- DATABASE_URL=postgresql://tenant_svc:${TENANT_DB_PASSWORD}@postgres-master:5432/tenants_db
- REDIS_URL=redis://redis-cluster:6379/2
healthcheck:
test: ["CMD", "curl", "-f", "http://localhost:8002/health"]
interval: 30s
timeout: 10s
retries: 3
# Billing Service
billing-service:
image: ${REGISTRY}/billing-service:${VERSION}
networks:
- backend
- database
environment:
- DATABASE_URL=postgresql://billing_svc:${BILLING_DB_PASSWORD}@postgres-master:5432/billing_db
- STRIPE_SECRET_KEY_FILE=/run/secrets/stripe_secret
- WEBHOOK_SECRET_FILE=/run/secrets/stripe_webhook_secret
secrets:
- stripe_secret
- stripe_webhook_secret
healthcheck:
test: ["CMD", "curl", "-f", "http://localhost:8003/health"]
interval: 30s
timeout: 10s
retries: 3
# Analytics Service
analytics-service:
image: ${REGISTRY}/analytics-service:${VERSION}
networks:
- backend
- database
environment:
- CLICKHOUSE_URL=http://clickhouse:8123
- KAFKA_BROKERS=kafka:9092
depends_on:
- clickhouse
- kafka
# Database Cluster
postgres-master:
image: postgres:14
environment:
- POSTGRES_REPLICATION_MODE=master
- POSTGRES_REPLICATION_USER=replicator
- POSTGRES_REPLICATION_PASSWORD_FILE=/run/secrets/replication_password
- POSTGRES_MULTIPLE_DATABASES=api_db,users_db,tenants_db,billing_db
- POSTGRES_MULTIPLE_USERS=api_user,user_svc,tenant_svc,billing_svc
volumes:
- postgres_master_data:/var/lib/postgresql/data
- ./postgres/init-multiple-databases.sh:/docker-entrypoint-initdb.d/init-multiple-databases.sh
- ./postgres/postgresql.conf:/etc/postgresql/postgresql.conf
networks:
- database
secrets:
- replication_password
command: postgres -c config_file=/etc/postgresql/postgresql.conf
postgres-replica:
image: postgres:14
environment:
- POSTGRES_REPLICATION_MODE=slave
- POSTGRES_MASTER_HOST=postgres-master
- POSTGRES_REPLICATION_USER=replicator
- POSTGRES_REPLICATION_PASSWORD_FILE=/run/secrets/replication_password
volumes:
- postgres_replica_data:/var/lib/postgresql/data
networks:
- database
secrets:
- replication_password
depends_on:
- postgres-master
# Redis Cluster
redis-cluster:
image: redis:7-alpine
command: |
redis-server
--cluster-enabled yes
--cluster-config-file nodes.conf
--cluster-node-timeout 5000
--appendonly yes
--maxmemory 1gb
--maxmemory-policy allkeys-lru
volumes:
- redis_data:/data
networks:
- backend
# ClickHouse for Analytics
clickhouse:
image: clickhouse/clickhouse-server:latest
environment:
- CLICKHOUSE_DB=analytics
- CLICKHOUSE_USER=analytics_user
- CLICKHOUSE_PASSWORD=${CLICKHOUSE_PASSWORD}
volumes:
- clickhouse_data:/var/lib/clickhouse
networks:
- database
# Kafka for Event Streaming
kafka:
image: confluentinc/cp-kafka:latest
environment:
- KAFKA_ZOOKEEPER_CONNECT=zookeeper:2181
- KAFKA_ADVERTISED_LISTENERS=PLAINTEXT://kafka:9092
- KAFKA_OFFSETS_TOPIC_REPLICATION_FACTOR=1
- KAFKA_AUTO_CREATE_TOPICS_ENABLE=true
volumes:
- kafka_data:/var/lib/kafka/data
networks:
- backend
depends_on:
- zookeeper
zookeeper:
image: confluentinc/cp-zookeeper:latest
environment:
- ZOOKEEPER_CLIENT_PORT=2181
- ZOOKEEPER_TICK_TIME=2000
volumes:
- zookeeper_data:/var/lib/zookeeper/data
networks:
- backend
# Background Workers
worker:
image: ${REGISTRY}/worker:${VERSION}
deploy:
replicas: 3
networks:
- backend
- database
environment:
- CELERY_BROKER_URL=redis://redis-cluster:6379/3
- DATABASE_URL=postgresql://worker:${WORKER_DB_PASSWORD}@postgres-master:5432/jobs_db
command: celery -A app worker -l info -c 4
scheduler:
image: ${REGISTRY}/worker:${VERSION}
networks:
- backend
environment:
- CELERY_BROKER_URL=redis://redis-cluster:6379/3
command: celery -A app beat -l info
networks:
frontend:
driver: bridge
backend:
driver: bridge
internal: true
database:
driver: bridge
internal: true
monitoring:
driver: bridge
volumes:
traefik_certs:
postgres_master_data:
postgres_replica_data:
redis_data:
clickhouse_data:
kafka_data:
zookeeper_data:
secrets:
jwt_secret:
external: true
encryption_key:
external: true
stripe_secret:
external: true
stripe_webhook_secret:
external: true
replication_password:
external: true
Monitoring and Observability Stack
# docker-compose.monitoring.yml
version: '3.8'
services:
# Prometheus
prometheus:
image: prom/prometheus:latest
ports:
- "9090:9090"
volumes:
- ./prometheus/prometheus.yml:/etc/prometheus/prometheus.yml
- ./prometheus/rules:/etc/prometheus/rules
- prometheus_data:/prometheus
networks:
- monitoring
command:
- '--config.file=/etc/prometheus/prometheus.yml'
- '--storage.tsdb.path=/prometheus'
- '--storage.tsdb.retention.time=30d'
- '--web.enable-lifecycle'
- '--web.enable-admin-api'
# Grafana
grafana:
image: grafana/grafana:latest
ports:
- "3000:3000"
environment:
- GF_SECURITY_ADMIN_PASSWORD=${GRAFANA_PASSWORD}
- GF_USERS_ALLOW_SIGN_UP=false
- GF_INSTALL_PLUGINS=grafana-piechart-panel,grafana-worldmap-panel
volumes:
- grafana_data:/var/lib/grafana
- ./grafana/provisioning:/etc/grafana/provisioning
networks:
- monitoring
# AlertManager
alertmanager:
image: prom/alertmanager:latest
ports:
- "9093:9093"
volumes:
- ./alertmanager/alertmanager.yml:/etc/alertmanager/alertmanager.yml
- alertmanager_data:/alertmanager
networks:
- monitoring
# Jaeger for Distributed Tracing
jaeger:
image: jaegertracing/all-in-one:latest
ports:
- "16686:16686"
- "14268:14268"
environment:
- COLLECTOR_ZIPKIN_HTTP_PORT=9411
networks:
- monitoring
# ELK Stack for Logging
elasticsearch:
image: elasticsearch:7.17.0
environment:
- discovery.type=single-node
- "ES_JAVA_OPTS=-Xms2g -Xmx2g"
- xpack.security.enabled=false
volumes:
- elasticsearch_data:/usr/share/elasticsearch/data
networks:
- monitoring
logstash:
image: logstash:7.17.0
volumes:
- ./logstash/pipeline:/usr/share/logstash/pipeline
- ./logstash/config:/usr/share/logstash/config
networks:
- monitoring
depends_on:
- elasticsearch
kibana:
image: kibana:7.17.0
ports:
- "5601:5601"
environment:
- ELASTICSEARCH_HOSTS=http://elasticsearch:9200
networks:
- monitoring
depends_on:
- elasticsearch
networks:
monitoring:
external: true
volumes:
prometheus_data:
grafana_data:
alertmanager_data:
elasticsearch_data:
Project 2: CI/CD Pipeline with GitOps
Complete CI/CD Configuration
# .gitlab-ci.yml
stages:
- build
- test
- security
- package
- deploy-staging
- integration-tests
- deploy-production
variables:
DOCKER_DRIVER: overlay2
DOCKER_TLS_CERTDIR: "/certs"
REGISTRY: $CI_REGISTRY_IMAGE
COMPOSE_PROJECT_NAME: $CI_PROJECT_NAME-$CI_COMMIT_REF_SLUG
services:
- docker:20.10.16-dind
before_script:
- docker login -u $CI_REGISTRY_USER -p $CI_REGISTRY_PASSWORD $CI_REGISTRY
# Build Stage
build:
stage: build
script:
- |
# Build all services
docker-compose -f docker-compose.build.yml build
# Tag and push images
for service in frontend api-gateway user-service tenant-service billing-service analytics-service worker; do
docker tag ${COMPOSE_PROJECT_NAME}_${service}:latest $REGISTRY/$service:$CI_COMMIT_SHA
docker push $REGISTRY/$service:$CI_COMMIT_SHA
docker tag $REGISTRY/$service:$CI_COMMIT_SHA $REGISTRY/$service:latest
docker push $REGISTRY/$service:latest
done
# Test Stage
test:
stage: test
script:
- |
# Run unit tests
docker-compose -f docker-compose.test.yml up --build --abort-on-container-exit
# Run integration tests
docker-compose -f docker-compose.integration.yml up --build --abort-on-container-exit
artifacts:
reports:
junit: test-results.xml
coverage: coverage.xml
# Security Scanning
security-scan:
stage: security
script:
- |
# Scan images for vulnerabilities
for service in frontend api-gateway user-service tenant-service billing-service; do
docker run --rm -v /var/run/docker.sock:/var/run/docker.sock \
aquasec/trivy:latest image --exit-code 1 --severity HIGH,CRITICAL \
$REGISTRY/$service:$CI_COMMIT_SHA
done
# SAST scanning
docker run --rm -v $PWD:/code \
registry.gitlab.com/gitlab-org/security-products/sast:latest /analyzer run
# Package Stage
package:
stage: package
script:
- |
# Create deployment package
envsubst < docker-compose.prod.template.yml > docker-compose.prod.yml
tar czf deployment-$CI_COMMIT_SHA.tar.gz \
docker-compose.prod.yml \
docker-compose.monitoring.yml \
traefik/ \
prometheus/ \
grafana/ \
scripts/
artifacts:
paths:
- deployment-$CI_COMMIT_SHA.tar.gz
expire_in: 1 week
# Staging Deployment
deploy-staging:
stage: deploy-staging
script:
- |
# Deploy to staging environment
export VERSION=$CI_COMMIT_SHA
export DOMAIN=staging.example.com
export REGISTRY=$CI_REGISTRY_IMAGE
# Update staging environment
docker-compose -f docker-compose.staging.yml down
docker-compose -f docker-compose.staging.yml pull
docker-compose -f docker-compose.staging.yml up -d
# Wait for services to be healthy
./scripts/wait-for-health.sh staging
environment:
name: staging
url: https://staging.example.com
only:
- develop
# Integration Tests
integration-tests:
stage: integration-tests
script:
- |
# Run end-to-end tests against staging
docker run --rm \
-e BASE_URL=https://staging.example.com \
-v $PWD/e2e:/tests \
cypress/included:latest
artifacts:
when: always
paths:
- e2e/screenshots/
- e2e/videos/
only:
- develop
# Production Deployment
deploy-production:
stage: deploy-production
script:
- |
# Blue-Green Deployment
export VERSION=$CI_COMMIT_SHA
export DOMAIN=example.com
export REGISTRY=$CI_REGISTRY_IMAGE
# Determine current and target environments
CURRENT=$(curl -s https://api.example.com/deployment/current)
TARGET=$([ "$CURRENT" = "blue" ] && echo "green" || echo "blue")
echo "Deploying to $TARGET environment"
# Deploy to target environment
docker-compose -f docker-compose.$TARGET.yml down
docker-compose -f docker-compose.$TARGET.yml pull
docker-compose -f docker-compose.$TARGET.yml up -d
# Health check
./scripts/wait-for-health.sh $TARGET
# Switch traffic
./scripts/switch-traffic.sh $TARGET
# Cleanup old environment after successful switch
sleep 300 # Wait 5 minutes
OTHER=$([ "$TARGET" = "blue" ] && echo "green" || echo "blue")
docker-compose -f docker-compose.$OTHER.yml down
environment:
name: production
url: https://example.com
when: manual
only:
- main
Deployment Scripts
scripts/wait-for-health.sh:
#!/bin/bash
ENVIRONMENT=$1
MAX_ATTEMPTS=30
ATTEMPT=0
echo "Waiting for $ENVIRONMENT environment to be healthy..."
while [ $ATTEMPT -lt $MAX_ATTEMPTS ]; do
HEALTHY=true
# Check each service health
for service in frontend api-gateway user-service tenant-service billing-service; do
if ! curl -f -s "http://$service-$ENVIRONMENT:8000/health" > /dev/null; then
HEALTHY=false
break
fi
done
if [ "$HEALTHY" = true ]; then
echo "All services are healthy!"
exit 0
fi
echo "Attempt $((ATTEMPT + 1))/$MAX_ATTEMPTS - Services not ready yet..."
sleep 10
ATTEMPT=$((ATTEMPT + 1))
done
echo "Health check failed after $MAX_ATTEMPTS attempts"
exit 1
scripts/switch-traffic.sh:
#!/bin/bash
TARGET=$1
echo "Switching traffic to $TARGET environment..."
# Update load balancer configuration
cat > /etc/nginx/conf.d/upstream.conf << EOF
upstream backend {
server app-$TARGET:8000;
}
EOF
# Reload nginx
nginx -s reload
# Update deployment marker
echo "$TARGET" > /var/www/html/deployment/current
echo "Traffic switched to $TARGET environment"
Project 3: Disaster Recovery and Backup System
# docker-compose.backup.yml
version: '3.8'
services:
# Backup Orchestrator
backup-orchestrator:
build: ./backup
environment:
- BACKUP_SCHEDULE=0 2 * * *
- S3_BUCKET=${BACKUP_S3_BUCKET}
- AWS_ACCESS_KEY_ID=${AWS_ACCESS_KEY_ID}
- AWS_SECRET_ACCESS_KEY=${AWS_SECRET_ACCESS_KEY}
- ENCRYPTION_KEY_FILE=/run/secrets/backup_encryption_key
volumes:
- /var/run/docker.sock:/var/run/docker.sock
- backup_temp:/tmp/backup
secrets:
- backup_encryption_key
networks:
- backup
# Database Backup
postgres-backup:
image: postgres:14
environment:
- PGPASSWORD_FILE=/run/secrets/postgres_password
volumes:
- backup_temp:/backup
- ./scripts/postgres-backup.sh:/backup.sh
secrets:
- postgres_password
networks:
- backup
- database
profiles:
- backup
command: /backup.sh
# Volume Backup
volume-backup:
image: alpine
volumes:
- redis_data:/source/redis:ro
- clickhouse_data:/source/clickhouse:ro
- backup_temp:/backup
profiles:
- backup
command: |
sh -c "
tar czf /backup/volumes_$(date +%Y%m%d_%H%M%S).tar.gz -C /source .
echo 'Volume backup completed'
"
# Disaster Recovery Test
dr-test:
build: ./dr-test
environment:
- TEST_ENVIRONMENT=dr-test
- RESTORE_FROM_BACKUP=latest
volumes:
- /var/run/docker.sock:/var/run/docker.sock
- backup_temp:/backup:ro
profiles:
- disaster-recovery
command: |
sh -c "
echo 'Starting disaster recovery test...'
./restore-and-test.sh
"
networks:
backup:
driver: bridge
database:
external: true
volumes:
backup_temp:
redis_data:
external: true
clickhouse_data:
external: true
secrets:
backup_encryption_key:
external: true
postgres_password:
external: true
Summary
This comprehensive final section demonstrated:
Enterprise-Grade Implementation
- Multi-Tenant SaaS Platform: Complete production architecture with load balancing, service mesh, and multi-database setup
- Monitoring Stack: Full observability with Prometheus, Grafana, Jaeger, and ELK stack
- Security Integration: Secrets management, network isolation, and vulnerability scanning
DevOps Excellence
- CI/CD Pipeline: Complete GitLab CI pipeline with security scanning, testing, and blue-green deployment
- GitOps Workflow: Infrastructure as code with automated deployment and rollback capabilities
- Quality Gates: Comprehensive testing including unit, integration, and end-to-end tests
Operational Resilience
- Disaster Recovery: Automated backup systems with encryption and cloud storage
- High Availability: Database replication, service redundancy, and health monitoring
- Performance Optimization: Caching layers, connection pooling, and resource management
Key Achievements
Throughout this Docker Compose guide, you’ve mastered:
- Fundamental Concepts: Service orchestration, networking, and volume management
- Advanced Patterns: Service mesh integration, event-driven architecture, and CQRS
- Production Readiness: Security hardening, performance optimization, and monitoring
- Real-World Implementation: Complete enterprise systems with CI/CD and disaster recovery
Congratulations! You now have the expertise to design, implement, and operate production-grade Docker Compose applications. You can confidently tackle complex multi-service architectures, implement robust CI/CD pipelines, and ensure operational excellence in containerized environments.