2. Docker Compose 编排进阶:多服务编排、依赖管理、健康检查、环境变量与配置管理
在微服务架构中,单一容器的管理远不能满足生产级需求。Docker Compose 作为多容器编排的核心工具,其进阶能力决定了服务集群的稳定性与可维护性。本章将深入剖析多服务编排、依赖管理、健康检查以及环境变量与配置管理四大核心模块,帮助你在压测与契约测试场景中构建高可用的服务拓扑。
2.1 多服务编排:从单体到拓扑
多服务编排的核心在于将多个相互依赖的容器定义为单一应用栈。通过 docker-compose.yml 文件,你可以声明式地定义服务、网络、卷与端口映射,实现一键启动与销毁。
关键原则: 每个服务应遵循单一职责,避免在同一个容器中运行多个进程。编排文件应作为基础设施即代码(IaC)的入口,纳入版本控制。
以下是一个典型的多服务编排示例,包含 API 网关、用户服务、订单服务与数据库:
version: '3.8'
services:
api-gateway:
image: myapp/gateway:1.0
ports:
- "8080:8080"
environment:
- USER_SERVICE_URL=http://user-service:3001
- ORDER_SERVICE_URL=http://order-service:3002
networks:
- frontend
- backend
user-service:
image: myapp/user-service:1.0
ports:
- "3001:3001"
environment:
- DB_HOST=postgres-db
- DB_PORT=5432
depends_on:
postgres-db:
condition: service_healthy
networks:
- backend
order-service:
image: myapp/order-service:1.0
ports:
- "3002:3002"
environment:
- DB_HOST=postgres-db
- DB_PORT=5432
depends_on:
postgres-db:
condition: service_healthy
networks:
- backend
postgres-db:
image: postgres:15
environment:
POSTGRES_USER: app_user
POSTGRES_PASSWORD: secure_pass
POSTGRES_DB: microservices_db
volumes:
- pgdata:/var/lib/postgresql/data
healthcheck:
test: ["CMD-SHELL", "pg_isready -U app_user -d microservices_db"]
interval: 10s
timeout: 5s
retries: 5
networks:
- backend
volumes:
pgdata:
networks:
frontend:
backend:
网络隔离策略: 将 API 网关置于
frontend 与 backend 双网络中,而内部服务仅连接 backend 网络,可有效减少攻击面并提升安全性。
2.2 依赖管理:启动顺序与条件控制
微服务之间存在明确的启动依赖关系。Docker Compose 通过 depends_on 指令控制服务启动顺序,但默认仅等待容器启动,不保证服务就绪。进阶用法需结合健康检查实现条件依赖。
| 依赖模式 | 配置方式 | 行为说明 | 适用场景 |
|---|---|---|---|
| 简单依赖 | depends_on: - db |
仅等待 db 容器启动(不保证就绪) | 快速开发环境 |
| 健康条件依赖 | depends_on: db: condition: service_healthy |
等待 db 容器通过健康检查后才启动 | 生产环境、压测场景 |
| 启动完成依赖 | depends_on: db: condition: service_started |
等待 db 容器启动完成(默认行为) | 无健康检查的遗留服务 |
常见陷阱: 仅使用
depends_on 而不配置健康检查,可能导致上游服务在数据库尚未完成初始化时即开始连接,引发连接拒绝或数据不一致。在契约测试中,这种时序问题会直接导致测试失败。
2.3 健康检查:服务就绪的黄金标准
健康检查是确保服务真实可用的关键机制。Docker Compose 支持在服务级别定义 healthcheck 指令,通过周期性执行自定义命令判断服务状态。
健康检查的完整参数包括:
- test:执行的检查命令,支持
CMD、CMD-SHELL或NONE(禁用)。 - interval:检查间隔,默认 30s。
- timeout:单次检查超时,默认 30s。
- retries:连续失败次数后标记为 unhealthy,默认 3。
- start_period:启动宽限期,在此期间失败不计入 retries。
以下为不同服务的健康检查配置示例:
# PostgreSQL 数据库
healthcheck:
test: ["CMD-SHELL", "pg_isready -U app_user -d microservices_db"]
interval: 10s
timeout: 5s
retries: 5
start_period: 30s
# Redis 缓存
healthcheck:
test: ["CMD", "redis-cli", "ping"]
interval: 5s
timeout: 3s
retries: 3
# Spring Boot 应用(通过 Actuator)
healthcheck:
test: ["CMD", "curl", "-f", "http://localhost:8080/actuator/health"]
interval: 15s
timeout: 5s
retries: 3
start_period: 60s
压测场景建议: 在压测启动前,应通过
docker compose ps --services --filter "status=running" 结合健康状态检查,确保所有服务均为 healthy 状态,避免压测流量进入未就绪的服务。
2.4 环境变量与配置管理
环境变量是解耦配置与代码的核心手段。Docker Compose 提供多层级的变量注入方式,适用于不同环境(开发、测试、生产)。
2.4.1 变量注入方式对比
| 注入方式 | 配置位置 | 优先级 | 典型用途 |
|---|---|---|---|
| 内联 environment | docker-compose.yml |
高 | 少量固定配置 |
| env_file | 外部 .env 文件 |
中 | 环境差异化配置 |
| shell 环境变量 | 宿主机 shell | 低 | CI/CD 动态注入 |
| Docker 秘密 | secrets 配置块 |
最高安全 | 密码、证书等敏感信息 |
2.4.2 环境文件最佳实践
推荐使用 .env 文件管理环境变量,并通过 env_file 指令引用。以下为典型的分环境配置结构:
# 项目目录结构
project/
├── docker-compose.yml
├── .env.dev # 开发环境
├── .env.test # 测试环境
├── .env.prod # 生产环境
└── secrets/
├── db_password.txt
└── api_key.txt
docker-compose.yml 中引用方式:
services:
user-service:
image: myapp/user-service:1.0
env_file:
- .env.dev
environment:
- SERVICE_NAME=user-service # 覆盖 env_file 中的同名变量
secrets:
- db_password
secrets:
db_password:
file: ./secrets/db_password.txt
安全提醒: 切勿将
.env.prod 或 secrets/ 目录提交到版本控制。应在 .gitignore 中明确排除这些文件,并通过 CI/CD 的安全变量或密钥管理服务注入。
2.5 配置管理进阶:Configs 与 Secrets
对于非敏感配置文件(如 Nginx 配置、Logback 配置),Docker Compose 提供 configs 机制;对于敏感数据,使用 secrets 机制。两者均支持文件挂载与运行时注入。
2.6 压测场景下的编排最佳实践
在契约测试与压测场景中,Docker Compose 编排需要额外关注以下要点:
- 资源限制:使用
deploy.resources.limits为每个服务设置 CPU 和内存上限,避免压测时单服务耗尽宿主机资源。 - 日志驱动:配置
logging驱动为json-file并设置max-size和max-file,防止压测产生海量日志撑爆磁盘。 - 端口冲突规避:压测环境建议使用动态端口映射(
ports: - "0:3001"),通过docker compose port获取实际端口。 - 网络延迟模拟:结合
tc命令或专用网络插件,在 Compose 网络中注入延迟与丢包,模拟真实生产网络条件。
压测编排检查清单:
- 所有依赖服务配置了
condition: service_healthy。 - 数据库等有状态服务配置了
start_period避免启动阶段误判。 - 环境变量通过
.env.test文件统一管理,不硬编码在 Compose 文件中。 - 敏感信息使用
secrets机制,不通过环境变量传递。 - 资源限制已设置,防止压测流量导致 OOM。