Skip to content

Docker Compose 编排

实际项目通常包含多个服务:API 服务、数据库、缓存、消息队列等。Docker Compose 用一个 docker-compose.yml 定义所有服务及其依赖关系,一条命令启动全套环境。

本页涵盖 compose 文件编写、多环境配置、profiles、override、健康检查和日志管理。Docker 单容器知识见 Docker 容器化,数据库与中间件的深入内容见 数据库与中间件。

一个典型的 AI 推理平台由 API、数据库、缓存和可选的消息队列组成,各容器通过 Compose 内部网络互联:

以下是一个包含 FastAPI 推理服务 + PostgreSQL 数据库 + Redis 缓存的完整编排:

docker-compose.yml
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:
Terminal window
# 启动所有服务(-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 pytest
docker compose run --rm api python migrate.py

💡 depends_on 的 condition: service_healthy 确保 API 等数据库健康检查通过后才启动,避免启动时数据库未就绪的竞态问题。

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 端口
docker-compose.prod.yml
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 # 绑定到宿主机高性能磁盘
Terminal window
# 开发环境(默认合并 override)
docker compose up -d
# 生产环境(显式指定,不加载 override)
docker compose -f docker-compose.yml -f docker-compose.prod.yml up -d

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"
Terminal window
# 默认只启动无 profile 的服务(api、db)
docker compose up -d
# 启动训练相关服务
docker compose --profile training up -d
# 启动监控栈
docker compose --profile monitoring up -d
# 同时启动多个 profile
docker compose --profile training --profile monitoring up -d

健康检查(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
服务健康检查命令
HTTP APIcurl -f http://localhost:8000/health
PostgreSQLpg_isready -U postgres
Redisredis-cli ping
MySQLmysqladmin ping -h localhost
MongoDBmongosh --eval "db.adminCommand('ping')"
Terminal window
# 查看容器健康状态
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 日志文件中,长时间运行的服务会积累大量日志,最终撑满磁盘。

# docker-compose.yml 中配置日志驱动
services:
api:
logging:
driver: json-file
options:
max-size: "10m" # 单个日志文件最大 10MB
max-file: "3" # 保留 3 个轮转文件
// /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
# 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}
Terminal window
# .env 文件(与 docker-compose.yml 同目录,自动加载)
DB_USER=aiflow
DB_PASSWORD=secret
DB_NAME=aiflow
IMAGE_TAG=v1.2.0
API_KEY=sk-xxxxxxxxxxxxx
# .env 不要提交到 Git(加入 .gitignore)
# 提交 .env.example 作为模板

⚠️ .env 文件中的密钥会以明文形式存在于宿主机文件系统中。生产环境推荐用 Docker secrets 或外部密钥管理服务(Vault、AWS Secrets Manager)。

  1. 不要依赖 version 字段:Docker Compose V2(docker compose 子命令)已废弃对 version 的校验,新版可省略。
  2. 用 condition: service_healthy 控制启动顺序,而不是裸 depends_on(只保证启动顺序,不保证就绪)。
  3. 生产环境设日志轮转,否则容器日志会无限增长撑满磁盘。
  4. 用 profiles 区分环境,避免开发时启动不需要的重型服务。
  5. GPU 在 compose 中用 deploy.resources 声明,而不是 runtime: nvidia(已废弃)。
术语英文解释
编排orchestration管理多个容器的启动、网络、依赖关系
覆盖文件override file在基础 compose 配置上叠加环境差异配置
配置集profiles按需启动不同服务组合的机制
健康检查healthcheck容器内定期执行的检查命令,判断服务是否正常
启动宽限期start_period容器启动后不计入健康检查失败的重试宽限期
日志轮转log rotation自动分割和限制日志文件大小的机制