Multi-Service Architecture
๐ฅ Vibe Prompt
"Extend compose to 4 services: API Gateway, Auth, Worker, and Frontend. Use network isolation."
services:
gateway:
image: nginx:alpine
ports: ["80:80"]
networks: ["frontend", "backend"]
volumes: ["./nginx.conf:/etc/nginx/conf.d/default.conf"]
frontend:
build: ./frontend
networks: ["frontend"]
auth:
build: ./auth
networks: ["backend"]
depends_on: [db, redis]
environment:
JWT_SECRET: ${JWT_SECRET}
worker:
build: ./worker
networks: ["backend"]
depends_on: [redis, db]
deploy:
replicas: 3
networks:
frontend:
backend:
internal: true # No external access
Network Isolation
Internet โ Gateway (nginx)
โ
Frontend Network
โ
Backend Network (internal!)
โ โ โ
Auth Worker DB
Scaling with Compose
services:
worker:
deploy:
replicas: 5
resources:
limits:
cpus: "0.5"
memory: "256M"
Production Tips
- Use
.envfor secrets (never commit) - Pin image versions (not
:latest) - Add
restart: alwaysto critical services - Use read-only volumes where possible
Chapter Summary
- Understand core concepts and principles
- Master implementation methods and techniques
- Familiar with common issues and solutions
- Able to apply in real projects
Further Reading
- Official documentation and API references
- Open source examples on GitHub
- Technical books and online courses
- Community discussions and tech blogs
Implementation Example
Basic Example
# This section provides a complete implementation example
Steps
- Setup: Configure development environment
- Data: Prepare required data
- Implementation: Build core functionality
- Testing: Verify correctness
- Optimization: Improve performance
Common Errors
| Error Type | Cause | Solution | |------------|-------|----------| | Compilation | Syntax | Check code syntax | | Runtime | Environment | Verify dependencies installed | | Logic | Algorithm | Step-by-step debugging | | Performance | Efficiency | Use profilers |
Code Example
import sys
def main():
print("Hello, World!")
if __name__ == "__main__":
main()
References
- Official documentation
- API reference
- Open source examples
- Community discussions
Service Dependency Management
depends_on with Health Checks
services:
app:
depends_on:
db:
condition: service_healthy # Waits for health check to pass
redis:
condition: service_started # Waits for container start only
db:
image: postgres:16-alpine
healthcheck:
test: ["CMD-SHELL", "pg_isready -U myapp"]
interval: 5s
timeout: 5s
retries: 10
start_period: 30s
redis:
image: redis:7-alpine
# No health check โ app only needs redis to start
Sharing Data Between Services
Named Volumes
services:
api:
volumes:
- uploads:/app/uploads
worker:
volumes:
- uploads:/app/uploads # Same volume shared between services
volumes:
uploads:
Bind Mount for Development
services:
app:
volumes:
- .:/app # Mount source code for hot-reload
- /app/node_modules # Exclude node_modules (from image)
Networking Between Services
services:
app:
networks:
- frontend
- backend
api:
networks:
- backend
- database
db:
networks:
- database
networks:
frontend:
backend:
database:
This isolates services:
- App โ API (via backend network)
- API โ DB (via database network)
- App cannot reach DB directly (security)
Complete Multi-Service Example
version: "3.9"
services:
nginx:
image: nginx:alpine
ports:
- "80:80"
volumes:
- ./nginx.conf:/etc/nginx/nginx.conf:ro
- ./static:/usr/share/nginx/html:ro
networks:
- frontend
depends_on:
- app
app:
build:
context: ./app
dockerfile: Dockerfile
expose:
- "3000"
environment:
- DB_HOST=db
- DB_USER=${DB_USER}
- DB_PASSWORD=${DB_PASSWORD}
- REDIS_HOST=redis
networks:
- frontend
- backend
depends_on:
db:
condition: service_healthy
redis:
condition: service_started
worker:
build:
context: ./worker
dockerfile: Dockerfile
environment:
- DB_HOST=db
- DB_USER=${DB_USER}
- DB_PASSWORD=${DB_PASSWORD}
networks:
- backend
depends_on:
db:
condition: service_healthy
db:
image: postgres:16-alpine
volumes:
- pgdata:/var/lib/postgresql/data
networks:
- backend
healthcheck:
test: ["CMD-SHELL", "pg_isready -U ${DB_USER}"]
interval: 5s
timeout: 5s
retries: 10
start_period: 30s
redis:
image: redis:7-alpine
volumes:
- redis_data:/data
networks:
- backend
healthcheck:
test: ["CMD", "redis-cli", "ping"]
interval: 5s
timeout: 3s
retries: 5
volumes:
pgdata:
redis_data:
networks:
frontend:
backend:
Managing Multiple Compose Files
# Development: override with dev-specific config
docker compose -f docker-compose.yml -f docker-compose.dev.yml up -d
# Production: override with production config
docker compose -f docker-compose.yml -f docker-compose.prod.yml up -d
# Run specific services only
docker compose up -d db redis # Start only database and cache
Best Practices for Multi-Service
| Practice | Reason | |----------|--------| | Use expose (not ports) for internal services | Internal services should not be accessible from the host | | Isolate networks by security level | Frontend, backend, database โ each with different access | | Add health checks to all stateful services | Depends_on waits for real readiness, not just start | | Use named volumes for persistent data | Data survives container restarts | | Use .env file for shared variables | One source of truth for environment config | | Separate compose files per environment | Base + dev + prod overrides | | One service = one responsibility | Don't bundle multiple concerns into one container | | Set restart: always for critical services | Self-healing after crashes | | Configure log rotation | Prevent log files from filling the disk |
Summary
Multi-service Docker Compose setups coordinate web servers, APIs, databases, caches, and workers. Use depends_on with health checks for startup ordering, named volumes for data sharing, and network isolation for security. Multiple compose files handle environment differences.
Key takeaways:
- depends_on with condition: service_healthy waits for real readiness
- Named volumes share data between services (e.g., uploads between API and worker)
- Network isolation improves security (frontend cannot reach database)
- Use expose instead of ports for internal services
- Use .env files for shared environment configuration
- Multiple compose files (base + dev + prod) handle environment differences
- Health checks prevent the app from connecting to an unready database
What's Next: Dev vs. Prod Configurations
The next chapter covers development vs. production Docker Compose configurations โ hot-reload, debug tools, security hardening, and performance optimization.