Docker: Compose高级编排
最后更新:2026-08-26
开发、测试、生产——三套环境一个 Compose 文件搞定。
1. 你将学到
- Profiles 多环境配置
- 配置复用与继承(extends / override)
- 水平扩展(scaling)
- 资源限制声明
- 健康检查依赖控制
2. 一个技术负责人的真实故事
(1) 痛点:三套环境三套配置文件
Charlie 需要为开发/测试/生产三套环境维护不同的 Compose config:开发要热重载和调试工具,测试要完整的服务栈,生产要资源限制和多副本。三个独立的 YAML 文件有大量重复代码,改一处要改三处。
(2) Profiles + Override 的解法
Charlie 用 profiles 和 override 文件,实现了"一个基础配置 + 环境差异覆盖"的方案。
BASH
# Development: activate dev profile + dev overrides
docker compose --profile dev -f docker-compose.yml -f docker-compose.dev.yml up -d
# Production: prod overrides only
docker compose -f docker-compose.yml -f docker-compose.prod.yml up -d
(3) 收益:3 个文件→1+2 个文件
从 3 个完全独立的文件变成 1 个基础文件 + 2 个差异覆盖文件。公共配置只需维护一份。
3. Profiles 多环境配置
(1) Profile 机制
graph TB
BASE["docker-compose.yml<br/>Base services"] --> DEV["--profile dev<br/>+ dev tools (hot-reload, adminer)"]
BASE --> TEST["--profile test<br/>+ test runners (selenium)"]
BASE --> PROD["--profile prod<br/>+ monitoring (prometheus, grafana)"]
▶ 示例:--profile dev 激活(难度⭐⭐)
YAML
# docker-compose.yml with profiles
services:
api:
build: .
ports:
- "5000:5000"
environment:
- FLASK_ENV=development
db:
image: postgres:15-alpine
volumes:
- pg-data:/var/lib/postgresql/data
# Dev-only: database management UI
adminer:
image: adminer
ports:
- "8081:8080"
profiles: ["dev"]
depends_on: [db]
# Dev-only: hot-reload with flask debug
api-dev:
build:
context: .
dockerfile: Dockerfile.dev
volumes:
- ./src:/app
ports:
- "5000:5000"
- "5678:5678" # Debug port
environment:
- FLASK_DEBUG=1
profiles: ["dev"]
# Prod-only: Prometheus monitoring
prometheus:
image: prom/prometheus
volumes:
- ./prometheus.yml:/etc/prometheus/prometheus.yml
ports:
- "9090:9090"
profiles: ["prod"]
volumes:
pg-data:
BASH
# Development: base services + dev profile
docker compose --profile dev up -d
# Production: base services + prod profile
docker compose --profile prod up -d
# Only base services (no profile)
docker compose up -d
(1) Profiles vs Override 对比
| 维度 | Profiles | Override Files |
|---|---|---|
| 文件数 | 1 个文件 | 2-3 个文件 |
| 激活方式 | --profile xxx |
-f base.yml -f override.yml |
| 适合场景 | 增减少量服务 | 大量配置差异 |
| 可组合性 | 多个 profile 可组合 | 按顺序覆盖 |
4. Override 文件合并
▶ 示例:override 文件覆盖配置(难度⭐⭐⭐)
YAML
# docker-compose.yml (base configuration)
services:
api:
build: .
environment:
FLASK_ENV: production
restart: unless-stopped
db:
image: postgres:15-alpine
volumes:
- pg-data:/var/lib/postgresql/data
restart: unless-stopped
volumes:
pg-data:
YAML
# docker-compose.dev.yml (dev overrides)
services:
api:
environment:
FLASK_ENV: development
FLASK_DEBUG: "1"
volumes:
- ./src:/app # Hot-reload: mount source code
ports:
- "5678:5678" # Debug port
# Dev-only service
adminer:
image: adminer
ports:
- "8081:8080"
YAML
# docker-compose.prod.yml (prod overrides)
services:
api:
deploy:
replicas: 3
resources:
limits:
cpus: "1.0"
memory: 512M
healthcheck:
test: ["CMD", "curl", "-f", "http://localhost:5000/health"]
interval: 30s
timeout: 5s
retries: 3
# Prod-only: Nginx reverse proxy
nginx:
image: nginx:1.25-alpine
ports:
- "80:80"
volumes:
- ./nginx.prod.conf:/etc/nginx/conf.d/default.conf
depends_on:
- api
BASH
# Development
docker compose -f docker-compose.yml -f docker-compose.dev.yml up -d
# Production
docker compose -f docker-compose.yml -f docker-compose.prod.yml up -d
# Preview merged config (dry-run)
docker compose -f docker-compose.yml -f docker-compose.prod.yml config
5. 水平扩展(Scaling)
▶ 示例:--scale 扩展(难度⭐⭐)
BASH
# Scale the API service to 3 replicas
docker compose up -d --scale api=3
# Scale dynamically on a running stack
docker compose up -d --scale api=5
(1) Scaling 注意事项
| 问题 | 原因 | 解决方案 |
|---|---|---|
| 端口冲突 | 多副本映射同一主机端口 | 只暴露 1 个入口(Nginx),API 不映射主机端口 |
| 数据一致性 | 多副本写同一存储 | 无状态服务才适合扩展,共享数据库 |
| 负载均衡 | 请求如何分发到多副本 | Nginx upstream 或 Docker 内置 DNS 轮询 |
▶ 示例:deploy.replicas 声明式扩展(难度⭐⭐)
YAML
services:
api:
build: .
deploy:
replicas: 3
resources:
limits:
cpus: "0.5"
memory: 256M
reservations:
cpus: "0.25"
memory: 128M
# Do NOT map ports for scaled services
# ports: ["5000:5000"] ← This breaks with replicas > 1
nginx:
image: nginx:alpine
ports:
- "80:80"
# Nginx upstream uses DNS round-robin to api:5000
6. 资源限制
(1) deploy.resources 配置
YAML
services:
api:
deploy:
resources:
limits: # Hard limits (kill if exceeded)
cpus: "1.0"
memory: 512M
reservations: # Soft guarantees (minimum)
cpus: "0.5"
memory: 256M
| 字段 | 作用 | 效果 |
|---|---|---|
limits.cpus |
CPU 上限 | 超过被限流 |
limits.memory |
内存上限 | 超过被 OOM Kill |
reservations.cpus |
CPU 最低保证 | 调度保证 |
reservations.memory |
内存最低保证 | 调度保证 |
7. 完整示例:三环境 Compose 项目
YAML
# ============================================
# docker-compose.yml - Base configuration
# ============================================
services:
api:
build:
context: .
dockerfile: Dockerfile
environment:
DATABASE_URL: postgresql://postgres:${DB_PASSWORD:-secret}@db:5432/${DB_NAME:-myapp}
depends_on:
db:
condition: service_healthy
restart: unless-stopped
networks:
- backend
db:
image: postgres:15-alpine
environment:
POSTGRES_PASSWORD: ${DB_PASSWORD:-secret}
POSTGRES_DB: ${DB_NAME:-myapp}
volumes:
- pg-data:/var/lib/postgresql/data
healthcheck:
test: ["CMD-SHELL", "pg_isready -U postgres"]
interval: 5s
timeout: 5s
retries: 5
restart: unless-stopped
networks:
- backend
# Dev-only: Adminer DB UI
adminer:
image: adminer
ports:
- "8081:8080"
profiles: ["dev"]
networks:
- backend
volumes:
pg-data:
networks:
backend:
YAML
# ============================================
# docker-compose.prod.yml - Production overrides
# ============================================
services:
api:
deploy:
replicas: 3
resources:
limits:
cpus: "1.0"
memory: 512M
healthcheck:
test: ["CMD", "curl", "-f", "http://localhost:5000/health"]
interval: 30s
timeout: 5s
retries: 3
nginx:
image: nginx:1.25-alpine
ports:
- "80:80"
volumes:
- ./nginx.prod.conf:/etc/nginx/conf.d/default.conf
depends_on:
api:
condition: service_healthy
restart: unless-stopped
networks:
- backend
BASH
# Development
docker compose --profile dev up -d
# Production (3 replicas + Nginx + resource limits)
docker compose -f docker-compose.yml -f docker-compose.prod.yml up -d
# Verify scaling
docker compose -f docker-compose.yml -f docker-compose.prod.yml ps
❓ 常见问题
Q profiles 和 override 文件能混用吗?
A 能。
docker compose --profile dev -f docker-compose.yml -f docker-compose.dev.yml up -d 同时使用 profiles 和 override。profiles 管理增减服务,override 管理配置差异,两者互补。Q --scale 和 deploy.replicas 哪个生效?
A
--scale 命令行参数优先于 deploy.replicas YAML 声明。如果两者都设置,--scale 的值覆盖 YAML 中的值。生产环境推荐用 YAML 声明(可版本控制),调试时用 --scale 快速调整。Q 如何控制服务启动顺序?
A
depends_on + condition。三种条件:① service_started(默认,只等启动);② service_healthy(等健康检查通过);③ service_completed_successfully(等初始化任务完成)。生产环境一律用 service_healthy。Q Compose 文件里的变量怎么在不同环境间切换?
A
${VAR:-default} + .env 文件。每个环境放不同的 .env 文件:.env.dev / .env.prod。启动时用 --env-file 指定:docker compose --env-file .env.prod up -d。Q 多副本时端口怎么处理?
A 被扩展的服务不能映射主机端口(多副本会冲突)。只让 Nginx/HAProxy 映射端口,API 服务在内部网络通信。Nginx 的 upstream 使用 Docker DNS 轮询自动分发到多副本。
📖 小节
- Profiles:同一文件按环境增减服务,
--profile dev激活 - Override 文件:
-f base.yml -f override.yml合并配置,适合大量差异 - Scaling:
--scale api=3或deploy.replicas: 3水平扩展无状态服务 - 被扩展的服务不能映射主机端口——用 Nginx 入口 + 内部 DNS 轮询
deploy.resources声明 CPU/内存限制和预留depends_on: { condition: service_healthy }确保依赖真正就绪
📝 作业
- 基础题(难度⭐):为第 12 课的应用编写 dev/prod 两套 override 文件,dev 加热重载,prod 加资源限制。
- 进阶题(难度⭐⭐):用
--scale api=3扩展 API 服务到 3 副本,用docker compose ps验证。 - 挑战题(难度⭐⭐⭐):配置 Nginx 反向代理到 3 副本 API,验证请求被分发到不同副本(查看不同容器的日志)。