Docker: Phase 3综合实践
最后更新:2026-08-26
把 Phase 3 的知识串起来——编排一个完整的微服务电商后端。
1. 你将学到
- 多层 Compose 项目结构设计
- 服务发现与负载均衡
- 数据持久化策略
- 多环境配置管理
- 健康检查与自愈
2. 一个电商平台后端的故事
(1) 痛点:6 个服务手动启动
Charlie 需要为电商平台后端部署 6 个服务:React frontend、Nginx 反向代理、Go API、PostgreSQL、Redis cache、RabbitMQ 消息队列。手动用 docker run 需要记住 30+ parameter,启动顺序严格,出错率极高。
(2) Compose 一键编排的解法
Charlie 用一个 docker-compose.yml 全搞定。
BASH
docker compose up -d
(3) 收益:6 个服务一键启动
从手动 30 分钟降到 docker compose up -d 30 秒。新人入职 5 分钟跑起整个后端。
3. 微服务架构设计
(1) 架构总览
graph TB
USER["Browser"] --> NGX["Nginx<br/>:80 Reverse Proxy"]
NGX -->|"api/"| API1["Go API #1<br/>:8080"]
NGX -->|"api/"| API2["Go API #2<br/>:8080"]
NGX -->|"api/"| API3["Go API #3<br/>:8080"]
NGX -->|"/"| REACT["React SPA<br/>Static Files"]
API1 --> PG["PostgreSQL<br/>:5432"]
API2 --> PG
API3 --> PG
API1 --> REDIS["Redis<br/>:6379"]
API2 --> REDIS
API3 --> MQ["RabbitMQ<br/>:5672"]
(2) 服务清单
| 服务 | 镜像 | 端口 | 网络 | 依赖 |
|---|---|---|---|---|
| Nginx | nginx:1.25-alpine | 80→80 | frontend, backend | api (healthy) |
| React | 自建(多阶段) | - | frontend | - |
| Go API | 自建(多阶段) | 8080 | backend, db-net, cache-net | postgres (healthy), redis |
| PostgreSQL | postgres:15-alpine | 5432 | db-net | - |
| Redis | redis:7-alpine | 6379 | cache-net | - |
| RabbitMQ | rabbitmq:3-management | 5672, 15672 | backend | - |
4. Compose 文件编写
▶ 示例:编写完整 compose 文件(难度⭐⭐⭐)
YAML
# ============================================
# docker-compose.yml - E-commerce microservices
# ============================================
services:
# ---------- Frontend ----------
nginx:
image: nginx:1.25-alpine
ports:
- "80:80"
volumes:
- ./nginx.conf:/etc/nginx/conf.d/default.conf:ro
- react-build:/usr/share/nginx/html:ro
depends_on:
api:
condition: service_healthy
restart: unless-stopped
networks:
- frontend
- backend
healthcheck:
test: ["CMD", "nginx", "-t"]
interval: 30s
timeout: 5s
react:
build:
context: ./frontend
dockerfile: Dockerfile
volumes:
- react-build:/app/build
networks:
- frontend
# ---------- Backend ----------
api:
build:
context: ./api
dockerfile: Dockerfile
environment:
DATABASE_URL: postgresql://appuser:${DB_PASSWORD:-secret}@postgres:5432/${DB_NAME:-ecommerce}
REDIS_URL: redis://redis:6379
RABBITMQ_URL: amqp://guest:guest@rabbitmq:5672
depends_on:
postgres:
condition: service_healthy
redis:
condition: service_started
restart: unless-stopped
deploy:
replicas: 3
resources:
limits:
cpus: "1.0"
memory: 512M
networks:
- backend
- db-net
- cache-net
healthcheck:
test: ["CMD", "wget", "-qO-", "http://localhost:8080/health"]
interval: 15s
timeout: 5s
retries: 3
start_period: 10s
logging:
driver: json-file
options:
max-size: "10m"
max-file: "5"
# ---------- Data Stores ----------
postgres:
image: postgres:15-alpine
environment:
POSTGRES_USER: appuser
POSTGRES_PASSWORD: ${DB_PASSWORD:-secret}
POSTGRES_DB: ${DB_NAME:-ecommerce}
volumes:
- pg-data:/var/lib/postgresql/data
restart: unless-stopped
networks:
- db-net
healthcheck:
test: ["CMD-SHELL", "pg_isready -U appuser"]
interval: 5s
timeout: 5s
retries: 5
redis:
image: redis:7-alpine
command: redis-server --appendonly yes
volumes:
- redis-data:/data
restart: unless-stopped
networks:
- cache-net
healthcheck:
test: ["CMD", "redis-cli", "ping"]
interval: 10s
timeout: 5s
rabbitmq:
image: rabbitmq:3-management-alpine
ports:
- "15672:15672" # Management UI
environment:
RABBITMQ_DEFAULT_USER: guest
RABBITMQ_DEFAULT_PASS: guest
volumes:
- mq-data:/var/lib/rabbitmq
restart: unless-stopped
networks:
- backend
# ---------- Volumes ----------
volumes:
pg-data:
redis-data:
mq-data:
react-build:
# ---------- Networks ----------
networks:
frontend:
backend:
db-net:
internal: true # No external access
cache-net:
internal: true
(1) Nginx 配置(负载均衡)
TEXT
📖 仅展示
# nginx.conf
upstream api_backend {
server api:8080; # Docker DNS round-robin to 3 replicas
}
server {
listen 80;
server_name localhost;
# Static files (React SPA)
location / {
root /usr/share/nginx/html;
try_files $uri $uri/ /index.html;
}
# API proxy
location /api/ {
proxy_pass http://api_backend/;
proxy_set_header Host $host;
proxy_set_header X-Real-IP $remote_addr;
}
}
5. 多环境配置
▶ 示例:开发环境 override(难度⭐⭐)
YAML
# docker-compose.dev.yml
services:
api:
build:
context: ./api
dockerfile: Dockerfile.dev
volumes:
- ./api/src:/app/src # Hot-reload
environment:
GO_ENV: development
deploy:
replicas: 1 # Single replica for debugging
# Dev-only: database admin UI
adminer:
image: adminer
ports:
- "8081:8080"
profiles: ["dev"]
networks:
- db-net
6. 验证部署
(1) 验证清单
| 检查项 | 命令 | 预期结果 |
|---|---|---|
| 所有服务运行 | docker compose ps |
6+ 服务 Up |
| Nginx 健康 | curl http://localhost |
200 OK |
| API 健康 | curl http://localhost/api/health |
{"status":"ok"} |
| API 副本数 | docker compose ps api |
3 个容器 |
| Redis 连接 | docker compose exec redis redis-cli ping |
PONG |
| PostgreSQL 连接 | docker compose exec postgres pg_isready |
accepting connections |
| 数据库隔离 | 从 nginx 容器 ping postgres | 失败(internal 网络) |
7. 完整示例:一键部署电商平台
BASH
# ============================================
# Complete walkthrough: E-commerce microservices
# ============================================
# 1. Build and start all services
docker compose up -d --build
# 2. Verify all services are running
docker compose ps
# 3. Check health status
docker compose ps --format "table {{.Name}}\t{{.Status}}"
# 4. Test the API
curl -s http://localhost/api/health | python3 -m json.tool
# 5. Verify load balancing (multiple requests to different replicas)
for i in $(seq 1 6); do
curl -s http://localhost/api/health | jq -r '.hostname'
done
# 6. Check database connectivity from API
docker compose exec api wget -qO- http://localhost:8080/health
# 7. Access RabbitMQ management UI
# Open http://localhost:15672 (guest/guest)
# 8. View logs
docker compose logs -f api
# 9. Scale API to 5 replicas
docker compose up -d --scale api=5
# 10. Clean up
docker compose down
docker compose down -v # Also removes data volumes
❓ 常见问题
Q 服务间通信用网络别名还是 service 名?
A Compose 中推荐用 service 名(如
postgres、redis)。Compose 自动为每个服务注册 DNS 记录,service 名就是主机名。网络别名用于同一服务在不同网络中需要不同名字的场景。Q 依赖启动顺序怎么保证?
A
depends_on + condition: service_healthy。API 依赖 postgres 的健康检查通过后才启动。注意:depends_on: [db](默认 condition: service_started)只等容器启动,不等服务就绪。Q 多副本 API 如何做负载均衡?
A Docker 内置 DNS 轮询 + Nginx upstream。3 个 api 容器都注册 DNS 为
api,Nginx 的 upstream api_backend { server api:8080; } 会轮询分发。对于更复杂的负载均衡策略,可以用 HAProxy。Q 数据库主从复制怎么配置?
A 单机 Compose 可以用多个 PostgreSQL 容器 + 主从复制配置。但生产级主从建议用 managed database(AWS RDS / 云服务商)或专用工具(Patroni/Stolon)。本课的 PostgreSQL 是单节点。
Q 配置热加载怎么实现?
A 开发环境用 Volume 挂载源码(如
-v ./api/src:/app/src)+ 热重载工具(air for Go, nodemon for Node, flask --debug for Python)。生产环境不挂载源码,配置变更通过环境变量 + docker compose up -d 重启。📖 小节
- 微服务 Compose 架构:Frontend → Backend → Data Stores 三层网络隔离
internal: true网络防止数据库/缓存被外部直接访问- API 多副本 + Nginx upstream 实现负载均衡
depends_on: { condition: service_healthy }确保依赖真正就绪- 日志轮转
logging: { options: { max-size: "10m" } }防止磁盘撑满 - dev/prod override 文件管理环境差异
📝 作业
- 基础题(难度⭐):设计一个博客系统的多服务架构(Nginx + API + DB + Cache),编写 docker-compose.yml 并启动。
- 进阶题(难度⭐⭐):配置 API 多副本(replicas: 3)+ Nginx 负载均衡,验证请求分发到不同副本。
- 挑战题(难度⭐⭐⭐):添加 dev/prod 两套 override 文件(dev 加 Adminer + 热重载,prod 加资源限制 + 日志轮转),分别启动验证差异。