docker-compose 进阶:profiles 多环境、override 文件、扩缩容与健康联动
深入讲解 docker-compose 的进阶用法:profiles 实现开发/测试/生产环境按需启动服务、compose override 文件分层覆盖配置、docker compose scale 水平扩容配合 Nginx 负载均衡、extend 复用服务定义、watch 模式实现代码热更新,以及 compose 项目的目录组织最佳实践。
上一篇讲了 docker-compose 的基础用法,本文深入进阶特性:如何用一套 compose 文件适配多个环境、如何在不改主配置的情况下叠加覆盖、如何快速水平扩容——这些是生产中最常见的实际需求。
一、Profiles — 按需启动服务
Profiles 解决的问题:开发时需要监控面板和调试工具,生产时只需要核心服务。
# compose.yml
services:
# 核心服务(无 profiles,总是启动)
api:
build: .
ports:
- "8080:8080"
networks:
- app-net
db:
image: mysql:8.0
networks:
- app-net
redis:
image: redis:7.2
networks:
- app-net
# 开发工具(只在 dev profile 启动)
adminer:
image: adminer
profiles: ["dev", "debug"]
ports:
- "8081:8080"
networks:
- app-net
redis-insight:
image: redislabs/redisinsight:latest
profiles: ["dev"]
ports:
- "8001:8001"
networks:
- app-net
# 监控(只在 monitoring profile 启动)
prometheus:
image: prom/prometheus
profiles: ["monitoring"]
ports:
- "9090:9090"
networks:
- app-net
grafana:
image: grafana/grafana
profiles: ["monitoring"]
ports:
- "3000:3000"
networks:
- app-net
networks:
app-net:
# 只启动核心服务
docker compose up -d
# 启动:api, db, redis(adminer/grafana 等不启动)
# 启动开发模式(核心 + dev profile)
docker compose --profile dev up -d
# 启动多个 profile
docker compose --profile dev --profile monitoring up -d
# 单独启动某个 profile 的服务
docker compose --profile monitoring up -d prometheus grafana
# 环境变量方式(更方便)
COMPOSE_PROFILES=dev,monitoring docker compose up -d
二、Override 文件 — 分层配置
Override 文件让你在不修改主 compose.yml 的情况下覆盖配置,非常适合多环境管理。
文件加载顺序(自动合并):
compose.yml
+ docker-compose.override.yml ← 开发时自动加载(如存在)
手动指定多个文件:
docker compose -f compose.yml -f compose.prod.yml up -d
# compose.yml — 基础配置(通用)
services:
api:
image: myapp:${APP_VERSION:-latest}
environment:
- LOG_LEVEL=info
networks:
- app-net
db:
image: mysql:8.0
networks:
- app-net
networks:
app-net:
# docker-compose.override.yml — 开发环境自动叠加
# (docker compose up 自动加载,不需要 -f 指定)
services:
api:
build: . # 覆盖:用本地 Dockerfile 构建
volumes:
- .:/app # 挂载代码(热更新)
environment:
- LOG_LEVEL=debug # 覆盖:调试日志
- DEBUG=true
ports:
- "8080:8080"
- "5678:5678" # 调试端口
db:
ports:
- "3306:3306" # 开发时暴露数据库端口
volumes:
- ./dev-seed.sql:/docker-entrypoint-initdb.d/seed.sql
# compose.prod.yml — 生产环境配置
services:
api:
image: registry.company.com/myapp:${APP_VERSION} # 用固定版本镜像
restart: unless-stopped
deploy:
resources:
limits:
cpus: '2'
memory: 1G
logging:
driver: json-file
options:
max-size: "100m"
max-file: "5"
db:
restart: unless-stopped
volumes:
- mysql_data:/var/lib/mysql
volumes:
mysql_data:
# 开发环境(自动加载 override.yml)
docker compose up -d
# 生产环境(手动指定,不加载 override.yml)
docker compose -f compose.yml -f compose.prod.yml up -d
# 查看合并后的最终配置
docker compose -f compose.yml -f compose.prod.yml config
三、扩缩容与负载均衡
# 水平扩展(启动多个实例)
docker compose up -d --scale api=3
# 查看
docker compose ps
# NAME IMAGE COMMAND SERVICE CREATED STATUS PORTS
# project-api-1 myapp ... api ... Up 8080/tcp
# project-api-2 myapp ... api ... Up 8080/tcp
# project-api-3 myapp ... api ... Up 8080/tcp
# 注意:使用 scale 时,不能设置 container_name(名称冲突)
# 也不能固定宿主机端口(端口冲突)
# api 服务的端口只写容器端口,让 Nginx 来反向代理
# compose.yml — 支持 scale 的配置
services:
api:
build: .
expose:
- "8080" # expose 不映射到宿主机,只在 Docker 网络内可达
# 不要写 ports: - "8080:8080"(多实例会冲突)
networks:
- app-net
healthcheck:
test: ["CMD", "curl", "-f", "http://localhost:8080/health"]
interval: 10s
retries: 3
nginx:
image: nginx:1.25-alpine
ports:
- "80:80"
volumes:
- ./nginx/nginx.conf:/etc/nginx/nginx.conf:ro
networks:
- app-net
depends_on:
api:
condition: service_healthy
networks:
app-net:
# nginx/nginx.conf
events { worker_connections 1024; }
http {
upstream api_backend {
# 使用服务名,Docker DNS 自动解析所有实例并轮询
server api:8080;
}
server {
listen 80;
location / {
proxy_pass http://api_backend;
proxy_set_header Host $host;
proxy_set_header X-Real-IP $remote_addr;
proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for;
}
}
}
# 启动(1个实例)
docker compose up -d
# 扩容到 5 个实例(Nginx 自动感知新实例)
docker compose up -d --scale api=5
# 缩容
docker compose up -d --scale api=2
# 查看负载情况(每个实例的请求数)
for i in 1 2 3 4 5; do
docker compose exec api cat /tmp/request_count 2>/dev/null || echo "instance $i"
done
四、Extend — 服务定义复用
# base.yml — 公共基础定义
services:
base-service:
restart: unless-stopped
logging:
driver: json-file
options:
max-size: "50m"
max-file: "3"
healthcheck:
interval: 30s
timeout: 5s
retries: 3
# compose.yml — 复用基础定义
services:
api:
extends:
file: base.yml
service: base-service
image: myapp:latest
ports:
- "8080:8080"
healthcheck:
test: ["CMD", "curl", "-f", "http://localhost:8080/health"]
# 继承了 interval/timeout/retries,只覆盖 test
worker:
extends:
file: base.yml
service: base-service
image: myapp:latest
command: ["python3", "worker.py"]
healthcheck:
test: ["CMD", "python3", "-c", "import sys; sys.exit(0)"]
五、Watch 模式 — 代码热更新
Docker Compose Watch(Compose v2.22+)监听文件变化自动同步到容器,不需要重启。
# compose.yml
services:
api:
build: .
ports:
- "5000:5000"
develop:
watch:
# 同步代码(文件变化立即同步,不重启容器)
- action: sync
path: ./src
target: /app/src
ignore:
- __pycache__/
- "*.pyc"
# 重新构建(依赖文件变化时)
- action: rebuild
path: requirements.txt
# 同步并重启(配置文件变化时)
- action: sync+restart
path: ./config
target: /app/config
# 启动 watch 模式
docker compose watch
# 或启动时自动开启 watch
docker compose up --watch
# 效果:
# 修改 src/ 下的代码 → 立即同步到容器,Flask/FastAPI 热重载生效
# 修改 requirements.txt → 自动重新 docker build
# 修改 config/ → 同步后重启服务
六、项目目录组织最佳实践
my-project/
├── compose.yml # 通用基础配置
├── docker-compose.override.yml # 开发覆盖(自动加载)
├── compose.staging.yml # 测试环境
├── compose.prod.yml # 生产环境
├── .env # 默认环境变量
├── .env.staging # 测试环境变量
├── .env.prod # 生产环境变量(不提交 git)
├── .gitignore # 忽略 .env.prod、.env.local 等
├── nginx/
│ ├── nginx.conf
│ └── ssl/
├── scripts/
│ ├── deploy.sh # 生产部署脚本
│ └── backup.sh # 数据备份脚本
└── src/
└── ... 应用代码
# deploy.sh — 生产部署脚本
#!/bin/bash
set -e
APP_VERSION=${1:-$(git describe --tags)}
echo "部署版本: $APP_VERSION"
export APP_VERSION
# 拉取最新镜像
docker compose -f compose.yml -f compose.prod.yml pull
# 滚动更新(先启动新容器,再停旧容器)
docker compose -f compose.yml -f compose.prod.yml \
--env-file .env.prod \
up -d --no-deps api
# 检查健康状态
sleep 10
HEALTH=$(docker compose ps --format json | jq -r '.[] | select(.Service=="api") | .Health')
if [ "$HEALTH" != "healthy" ]; then
echo "❌ 部署失败,回滚..."
docker compose -f compose.yml -f compose.prod.yml \
--env-file .env.prod \
up -d --no-deps api
exit 1
fi
echo "✅ 部署成功"
七、常见问题与技巧
# 问题1:服务重启但配置没更新
# 原因:compose 检测到镜像/配置没变化,跳过重建
# 解决:强制重新创建
docker compose up -d --force-recreate api
# 问题2:修改 compose.yml 后想只更新某个服务
docker compose up -d --no-deps api
# --no-deps 不重启依赖的服务
# 问题3:查看某个服务使用的环境变量
docker compose run --rm api env | sort
# 问题4:清理项目所有资源
docker compose down -v --rmi local
# -v:删除 volumes
# --rmi local:删除本地构建的镜像
# 问题5:并行构建多个服务
docker compose build --parallel
# 查看 compose 项目的所有资源
docker compose ls # 列出所有 compose 项目
小结
docker-compose 进阶三个核心模式:
多环境:用 profiles 控制哪些服务在当前场景启动,用 override 文件叠加环境差异,主 compose.yml 保持通用。
扩缩容:--scale api=N 水平扩展 + Nginx upstream 服务名自动轮询,一条命令完成水平扩容(不需要修改 Nginx 配置)。
开发体验:watch 模式监听文件变化自动同步,告别“改了代码重启容器”的低效循环。
