40 Docker Compose for Microservice
services:
# AI Service 1 - Python FastAPI
ai-service-1:
build:
context: ./ai-service-1
dockerfile: Dockerfile
container_name: acme-ai-service-1
ports:
- "8001:8001"
volumes:
# Mount source code for hot reload
- ./ai-service-1:/app
# Exclude virtual environment from mount (use container's packages)
- /app/.venv
# Exclude Python cache
- /app/__pycache__
environment:
- PYTHONUNBUFFERED=1
networks:
- acme-network
restart: unless-stopped
# API Gateway - .NET ASP.NET Core
api-gateway:
build:
context: ./AcmeApi/ApiGateway
dockerfile: Dockerfile
container_name: acme-api-gateway
ports:
- "5124:5124"
volumes:
# Mount source code for hot reload
- ./AcmeApi/ApiGateway:/app
# Exclude bin and obj directories (use container's build artifacts)
- /app/bin
- /app/obj
environment:
# Override service discovery to use Docker container name
- ASPNETCORE_ENVIRONMENT=Development
- DownstreamServices__AiService1__BaseUrl=http://ai-service-1:8001
- ASPNETCORE_URLS=http://+:5124
# Disable HTTPS redirect in Docker
- ASPNETCORE_HTTPS_PORT=
networks:
- acme-network
depends_on:
- ai-service-1
restart: unless-stopped
networks:
acme-network:
driver: bridgeGreat! Let’s dive into Docker Compose for microservices. I’ll explain your configuration and the concepts behind it.
40.1 Architecture Overview
First, let me visualize what this Docker Compose setup creates:
┌─────────────────────────────────────────────────────────┐
│ Host Machine │
│ (Your Mac M3 Pro) │
│ │
│ ┌────────────────────────────────────────────────────┐ │
│ │ Docker Network: acme-network │ │
│ │ (bridge driver) │ │
│ │ │ │
│ │ ┌─────────────────┐ ┌──────────────────┐ │ │
│ │ │ ai-service-1 │ │ api-gateway │ │ │
│ │ │ (Python/FastAPI)│◄─────┤ (.NET/ASP.NET) │ │ │
│ │ │ │ │ │ │ │
│ │ │ Port: 8001 │ │ Port: 5124 │ │ │
│ │ └─────────────────┘ └──────────────────┘ │ │
│ │ ▲ ▲ │ │
│ └─────────┼─────────────────────────┼────────────────┘ │
│ │ │ │
│ localhost:8001 localhost:5124 │
└────────────┼─────────────────────────┼──────────────────┘
│ │
Your Code Your Code
(./ai-service-1) (./AcmeApi/ApiGateway)
40.2 Key Docker Compose Concepts
40.2.1 1. Services Definition
Each service represents a containerized microservice. Your setup has two services:
ai-service-1: Python FastAPI backend (AI processing)api-gateway: .NET API Gateway (entry point, routes requests)
40.2.2 2. Build Context
build:
context: ./ai-service-1
dockerfile: Dockerfile- context: Directory containing source code and Dockerfile
- dockerfile: Instructions to build the container image
- Docker builds the image from scratch when you run
docker-compose up --build
40.2.3 3. Port Mapping
ports:
- "8001:8001" # HOST:CONTAINERFormat: "host_port:container_port"
Your Mac Docker Container
┌───┐ ┌───┐
│ │─── 8001 ────►│ │ Port 8001
└───┘ └───┘
You access the service via http://localhost:8001 from your Mac.
40.2.4 4. Volumes (Critical for Development)
volumes:
- ./ai-service-1:/app # Source code mount
- /app/.venv # Anonymous volume
- /app/__pycache__ # Anonymous volumeVolume Types Explained:
┌─────────────────────────────────────────────────┐
│ Host Machine │
│ │
│ ./ai-service-1/ │
│ ├── main.py ─────┐ │
│ ├── requirements.txt │ │
│ └── .venv/ │ (excluded) │
│ └── (packages) │ │
└────────────────────────────┼────────────────────┘
│ Bind Mount
┌────────────────────────────┼────────────────────┐
│ Container │ │
│ ▼ │
│ /app/ │
│ ├── main.py (from host) │
│ ├── requirements.txt (from host) │
│ └── .venv/ (from container only!) │
│ └── (packages) │
└─────────────────────────────────────────────────┘
Why exclude .venv and __pycache__?
.venv: Container has its own Python environment (possibly different OS/architecture)__pycache__: Avoid conflicts between host and container bytecode- Your M3 Mac is ARM64, but container might be different architecture
This enables hot reload - edit code on your Mac, changes reflect immediately in container!
40.2.5 5. Environment Variables
environment:
- ASPNETCORE_ENVIRONMENT=Development
- DownstreamServices__AiService1__BaseUrl=http://ai-service-1:8001Key insight: http://ai-service-1:8001
Inside the Docker network, services communicate using container names as hostnames:
api-gateway container can call:
http://ai-service-1:8001/predict
NOT localhost:8001 (that would be api-gateway itself!)
40.2.6 6. Networks
networks:
acme-network:
driver: bridgeBridge Network: Creates a private network where containers can discover each other by name.
┌──────────────────────────────────────────┐
│ acme-network (172.18.0.0/16) │
│ │
│ ai-service-1 │
│ IP: 172.18.0.2 │
│ Hostname: ai-service-1 │
│ │
│ api-gateway │
│ IP: 172.18.0.3 │
│ Hostname: api-gateway │
│ │
│ (Docker DNS resolves names to IPs) │
└──────────────────────────────────────────┘
40.2.7 7. Dependencies
depends_on:
- ai-service-1- Docker Compose starts
ai-service-1beforeapi-gateway - Note: Doesn’t wait for service to be “ready”, just “started”
- For production, you might need health checks
40.2.8 8. Restart Policy
restart: unless-stoppedContainer restarts automatically if it crashes, unless you explicitly stop it.
40.3 Request Flow Example
Let’s trace a request through your architecture:
1. External Client
│
│ HTTP GET http://localhost:5124/ai/predict
│
▼
2. Host Machine (Port 5124)
│
│ Port mapping
│
▼
3. api-gateway Container (Port 5124)
│
│ Internal routing logic
│ Uses: DownstreamServices__AiService1__BaseUrl
│
▼
4. Docker Network (acme-network)
│
│ DNS resolution: ai-service-1 → 172.18.0.2
│
▼
5. ai-service-1 Container (Port 8001)
│
│ Process request with FastAPI
│
▼
6. Response flows back through same path
40.4 Common Docker Compose Commands
# Start all services
docker-compose up
# Start in background (detached)
docker-compose up -d
# Rebuild images and start
docker-compose up --build
# Stop all services
docker-compose down
# View logs
docker-compose logs -f
# View logs for specific service
docker-compose logs -f ai-service-1
# Execute command in running container
docker-compose exec ai-service-1 bash
# List running services
docker-compose ps40.5 Advantages of This Setup
1. Isolation: Each service runs independently with its own dependencies
2. Reproducibility: Same environment everywhere (Mac, Linux, CI/CD)
3. Development Speed: Hot reload - no need to rebuild containers for code changes
4. Service Discovery: Services find each other by name automatically
5. Easy Scaling: Can add more services easily