Docker Compose 编排
实际项目通常包含多个服务:API 服务、数据库、缓存、消息队列等。Docker Compose 用一个 docker-compose.yml 定义所有服务及其依赖关系,一条命令启动全套环境。
本页涵盖 compose 文件编写、多环境配置、profiles、override、健康检查和日志管理。Docker 单容器知识见 Docker 容器化,数据库与中间件的深入内容见 数据库与中间件。
多容器编排架构
Section titled “多容器编排架构”一个典型的 AI 推理平台由 API、数据库、缓存和可选的消息队列组成,各容器通过 Compose 内部网络互联:
docker-compose.yml 示例
Section titled “docker-compose.yml 示例”以下是一个包含 FastAPI 推理服务 + PostgreSQL 数据库 + Redis 缓存的完整编排:
version: "3.9"
services: # ===== AI 推理 API 服务 ===== api: build: context: . dockerfile: Dockerfile container_name: inference-api ports: - "8000:8000" environment: - DATABASE_URL=postgresql://aiflow:secret@db:5432/aiflow - REDIS_URL=redis://redis:6379/0 - MODEL_PATH=/models/latest volumes: - ./models:/models # 挂载模型文件(避免打包进镜像) - ./logs:/app/logs # 日志持久化 depends_on: db: condition: service_healthy redis: condition: service_started deploy: resources: reservations: devices: - driver: nvidia # 申请 GPU count: 1 capabilities: [gpu] restart: unless-stopped
# ===== PostgreSQL 数据库 ===== db: image: postgres:16-alpine container_name: inference-db environment: POSTGRES_USER: aiflow POSTGRES_PASSWORD: secret POSTGRES_DB: aiflow ports: - "5432:5432" volumes: - pgdata:/var/lib/postgresql/data # 数据持久化到命名卷 healthcheck: test: ["CMD-SHELL", "pg_isready -U aiflow"] interval: 10s timeout: 5s retries: 5
# ===== Redis 缓存 ===== redis: image: redis:7-alpine container_name: inference-redis ports: - "6379:6379" volumes: - redisdata:/data command: redis-server --maxmemory 256mb --maxmemory-policy allkeys-lru
# ===== 命名卷(数据持久化)=====volumes: pgdata: redisdata:# 启动所有服务(-d 后台运行)docker compose up -d
# 查看服务状态docker compose ps
# 查看 API 日志(-f 实时跟踪)docker compose logs -f api
# 停止并删除容器(-v 同时删除卷)docker compose down -v
# 重新构建并启动docker compose up -d --build
# 只启动部分服务docker compose up -d api redis
# 在运行中的服务里执行命令docker compose exec api python -m pytestdocker compose run --rm api python migrate.py💡
depends_on的condition: service_healthy确保 API 等数据库健康检查通过后才启动,避免启动时数据库未就绪的竞态问题。
多环境配置(override)
Section titled “多环境配置(override)”Docker Compose 默认会合并 docker-compose.yml 和 docker-compose.override.yml。利用这一机制可以实现多环境配置。
project/├── docker-compose.yml # 基础配置(所有环境共享)├── docker-compose.override.yml # 开发覆盖(默认自动加载)├── docker-compose.prod.yml # 生产覆盖├── docker-compose.staging.yml # 预发布覆盖└── .env # 环境变量# docker-compose.yml(所有环境通用)services: api: build: . environment: - MODEL_PATH=/models/latest volumes: - ./models:/models restart: unless-stopped
db: image: postgres:16-alpine volumes: - pgdata:/var/lib/postgresql/data# docker-compose.override.yml(开发环境,自动加载)services: api: volumes: - ./src:/app/src # 源码挂载,支持热重载 - ./models:/models environment: - DEBUG=true - LOG_LEVEL=DEBUG command: python -m uvicorn src.server:app --reload --host 0.0.0.0 ports: - "8000:8000" - "5678:5678" # debugpy 端口services: api: environment: - DEBUG=false - LOG_LEVEL=WARNING command: python -m src.server --workers 4 deploy: resources: limits: memory: 16G reservations: devices: - driver: nvidia count: all capabilities: [gpu] ports: - "127.0.0.1:8000:8000" # 只绑定内网,前面有 Nginx
db: environment: POSTGRES_PASSWORD: ${DB_PASSWORD} # 从 .env 读取 volumes: - /data/pgdata:/var/lib/postgresql/data # 绑定到宿主机高性能磁盘# 开发环境(默认合并 override)docker compose up -d
# 生产环境(显式指定,不加载 override)docker compose -f docker-compose.yml -f docker-compose.prod.yml up -dCompose Profiles
Section titled “Compose Profiles”profiles 让你按需启动不同的服务组合。例如区分推理服务、训练任务、监控栈。
services: # ===== 始终启动 ===== api: image: my-inference:latest ports: - "8000:8000"
db: image: postgres:16-alpine
# ===== 只在训练时启动 ===== trainer: image: my-trainer:latest profiles: ["training"] volumes: - /data:/data deploy: resources: reservations: devices: - driver: nvidia count: all capabilities: [gpu]
jupyter: image: jupyter/tensorflow-notebook:latest profiles: ["dev"] ports: - "8888:8888"
# ===== 监控栈 ===== prometheus: image: prom/prometheus:latest profiles: ["monitoring"] ports: - "9090:9090"
grafana: image: grafana/grafana:latest profiles: ["monitoring"] ports: - "3000:3000"# 默认只启动无 profile 的服务(api、db)docker compose up -d
# 启动训练相关服务docker compose --profile training up -d
# 启动监控栈docker compose --profile monitoring up -d
# 同时启动多个 profiledocker compose --profile training --profile monitoring up -d健康检查策略
Section titled “健康检查策略”健康检查(healthcheck)决定 Docker 如何判断一个容器是否正常工作,影响 depends_on 的启动顺序和自动重启策略。
services: api: # ... 其他配置 ... healthcheck: test: ["CMD", "curl", "-f", "http://localhost:8000/health"] interval: 30s # 检查间隔 timeout: 10s # 超时时间 retries: 3 # 连续失败次数后才标记为 unhealthy start_period: 40s # 启动后宽限期,期间失败不计入 retries
db: image: postgres:16-alpine healthcheck: test: ["CMD-SHELL", "pg_isready -U postgres"] interval: 10s timeout: 5s retries: 5
redis: image: redis:7-alpine healthcheck: test: ["CMD", "redis-cli", "ping"] interval: 10s retries: 3常用健康检查命令
Section titled “常用健康检查命令”| 服务 | 健康检查命令 |
|---|---|
| HTTP API | curl -f http://localhost:8000/health |
| PostgreSQL | pg_isready -U postgres |
| Redis | redis-cli ping |
| MySQL | mysqladmin ping -h localhost |
| MongoDB | mongosh --eval "db.adminCommand('ping')" |
# 查看容器健康状态docker inspect --format='{{.State.Health.Status}}' inference-api# healthy / unhealthy / starting / none
# 查看健康检查历史docker inspect --format='{{json .State.Health.Log}}' inference-api | jq💡
start_period很重要:模型加载、预热可能需要 30-60 秒,没有宽限期的话容器会被误判为 unhealthy 并反复重启。
容器日志默认存储在宿主机的 JSON 日志文件中,长时间运行的服务会积累大量日志,最终撑满磁盘。
日志驱动与轮转
Section titled “日志驱动与轮转”# docker-compose.yml 中配置日志驱动services: api: logging: driver: json-file options: max-size: "10m" # 单个日志文件最大 10MB max-file: "3" # 保留 3 个轮转文件全局日志配置
Section titled “全局日志配置”// /etc/docker/daemon.json(宿主机全局配置,重启 docker 生效){ "log-driver": "json-file", "log-opts": { "max-size": "10m", "max-file": "3" }}生产环境推荐用集中式日志方案,而非容器本地文件:
services: api: logging: driver: fluentd options: fluentd-address: localhost:24224 tag: inference.api环境变量与 .env 文件
Section titled “环境变量与 .env 文件”# docker-compose.yml 中引用环境变量services: api: image: my-inference:${IMAGE_TAG:-latest} environment: - DATABASE_URL=postgresql://${DB_USER}:${DB_PASSWORD}@db:5432/${DB_NAME} - API_KEY=${API_KEY}# .env 文件(与 docker-compose.yml 同目录,自动加载)DB_USER=aiflowDB_PASSWORD=secretDB_NAME=aiflowIMAGE_TAG=v1.2.0API_KEY=sk-xxxxxxxxxxxxx
# .env 不要提交到 Git(加入 .gitignore)# 提交 .env.example 作为模板⚠️
.env文件中的密钥会以明文形式存在于宿主机文件系统中。生产环境推荐用 Docker secrets 或外部密钥管理服务(Vault、AWS Secrets Manager)。
- 不要依赖
version字段:Docker Compose V2(docker compose子命令)已废弃对version的校验,新版可省略。 - 用
condition: service_healthy控制启动顺序,而不是裸depends_on(只保证启动顺序,不保证就绪)。 - 生产环境设日志轮转,否则容器日志会无限增长撑满磁盘。
- 用 profiles 区分环境,避免开发时启动不需要的重型服务。
- GPU 在 compose 中用
deploy.resources声明,而不是runtime: nvidia(已废弃)。
| 术语 | 英文 | 解释 |
|---|---|---|
| 编排 | orchestration | 管理多个容器的启动、网络、依赖关系 |
| 覆盖文件 | override file | 在基础 compose 配置上叠加环境差异配置 |
| 配置集 | profiles | 按需启动不同服务组合的机制 |
| 健康检查 | healthcheck | 容器内定期执行的检查命令,判断服务是否正常 |
| 启动宽限期 | start_period | 容器启动后不计入健康检查失败的重试宽限期 |
| 日志轮转 | log rotation | 自动分割和限制日志文件大小的机制 |
- 站内关联
- Docker 容器化 —— 单容器的基础知识
- 数据库与中间件 —— Compose 编排的数据库与缓存的深入实践
- 工程基础概览 —— 本分类的入口页
- 推荐资源