技术博客

docker-compose 进阶:profiles 多环境、override 文件、扩缩容与健康联动

深入讲解 docker-compose 的进阶用法:profiles 实现开发/测试/生产环境按需启动服务、compose override 文件分层覆盖配置、docker compose scale 水平扩容配合 Nginx 负载均衡、extend 复用服务定义、watch 模式实现代码热更新,以及 compose 项目的目录组织最佳实践。

Dockerdocker-composeprofilesoverride扩缩容进阶热更新

上一篇讲了 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 模式监听文件变化自动同步,告别“改了代码重启容器”的低效循环。