Docker Compose生产环境部署完全指南:多容器应用、健康检查与零停机更新

Docker Compose将多容器应用的定义、配置和启动整合到一个YAML文件中,是小型团队和个人开发者最常用的容器编排方案。本文聚焦生产环境实践,涵盖健康检查、密钥管理、日志限制与零停机更新等关键配置。

一、生产级Compose文件结构

<code">version: '3.8'

# 定义网络(服务间通信走内部网络,不暴露到宿主机)
networks:
  backend:
    driver: bridge
    internal: false   # 需要访问外网(如下载依赖)
  database:
    driver: bridge
    internal: true    # 数据库网络不需要访问外网

# 持久化存储卷
volumes:
  mysql_data:
    driver: local
  redis_data:
    driver: local
  app_uploads:
    driver: local

services:
  # ============ 应用服务 ============
  app:
    image: your-registry/your-app:${APP_VERSION:-latest}
    restart: unless-stopped
    networks:
      - backend
      - database
    environment:
      - NODE_ENV=production
      - DB_HOST=mysql
      - REDIS_HOST=redis
    env_file:
      - .env.production    # 敏感配置从文件读取,不硬编码
    volumes:
      - app_uploads:/app/uploads
    depends_on:
      mysql:
        condition: service_healthy    # 等待MySQL健康才启动
      redis:
        condition: service_healthy
    healthcheck:
      test: ["CMD", "curl", "-f", "http://localhost:3000/health"]
      interval: 30s
      timeout: 10s
      retries: 3
      start_period: 40s    # 启动后等待40秒再开始健康检查
    deploy:
      resources:
        limits:
          cpus: '1.0'
          memory: 512M
        reservations:
          memory: 256M
    logging:
      driver: "json-file"
      options:
        max-size: "50m"
        max-file: "5"

  # ============ MySQL数据库 ============
  mysql:
    image: mysql:8.0
    restart: unless-stopped
    networks:
      - database
    environment:
      MYSQL_ROOT_PASSWORD_FILE: /run/secrets/mysql_root_password
      MYSQL_DATABASE: appdb
      MYSQL_USER: appuser
      MYSQL_PASSWORD_FILE: /run/secrets/mysql_password
    secrets:
      - mysql_root_password
      - mysql_password
    volumes:
      - mysql_data:/var/lib/mysql
      - ./mysql/init.sql:/docker-entrypoint-initdb.d/init.sql:ro
    command: >
      --character-set-server=utf8mb4
      --collation-server=utf8mb4_unicode_ci
      --innodb-buffer-pool-size=256M
      --slow-query-log=1
      --slow-query-log-file=/var/lib/mysql/slow.log
      --long-query-time=2
    healthcheck:
      test: ["CMD", "mysqladmin", "ping", "-h", "localhost", "-u", "root",
             "--password=$$(cat /run/secrets/mysql_root_password)"]
      interval: 30s
      timeout: 10s
      retries: 5
      start_period: 60s
    logging:
      driver: "json-file"
      options:
        max-size: "20m"
        max-file: "3"

  # ============ Redis缓存 ============
  redis:
    image: redis:7-alpine
    restart: unless-stopped
    networks:
      - database
    command: >
      redis-server
      --requirepass $${REDIS_PASSWORD}
      --maxmemory 256mb
      --maxmemory-policy allkeys-lru
      --appendonly yes
      --save 900 1
    environment:
      - REDIS_PASSWORD_FILE=/run/secrets/redis_password
    secrets:
      - redis_password
    volumes:
      - redis_data:/data
    healthcheck:
      test: ["CMD", "redis-cli", "--no-auth-warning", "-a",
             "$$(cat /run/secrets/redis_password)", "ping"]
      interval: 15s
      timeout: 5s
      retries: 3
    logging:
      driver: "json-file"
      options:
        max-size: "10m"
        max-file: "3"

  # ============ Nginx反向代理 ============
  nginx:
    image: nginx:alpine
    restart: unless-stopped
    networks:
      - backend
    ports:
      - "80:80"
      - "443:443"
    volumes:
      - ./nginx/nginx.conf:/etc/nginx/nginx.conf:ro
      - ./nginx/conf.d:/etc/nginx/conf.d:ro
      - /etc/letsencrypt:/etc/letsencrypt:ro
      - app_uploads:/var/www/uploads:ro
    depends_on:
      app:
        condition: service_healthy
    healthcheck:
      test: ["CMD", "nginx", "-t"]
      interval: 60s
      timeout: 10s
      retries: 3
    logging:
      driver: "json-file"
      options:
        max-size: "50m"
        max-file: "10"

# Docker Secrets(比环境变量更安全)
secrets:
  mysql_root_password:
    file: ./secrets/mysql_root_password.txt
  mysql_password:
    file: ./secrets/mysql_password.txt
  redis_password:
    file: ./secrets/redis_password.txt

二、密钥安全管理

<code"># 创建密钥目录(加入.gitignore)
mkdir -p secrets
echo "密码至少32位随机字符" > secrets/mysql_root_password.txt
echo "数据库用户密码" > secrets/mysql_password.txt
echo "Redis密码" > secrets/redis_password.txt

# 设置严格文件权限
chmod 600 secrets/*.txt

# .gitignore中添加
echo "secrets/" >> .gitignore
echo ".env.production" >> .gitignore
<code"># .env.production 示例(敏感信息,不提交Git)
APP_VERSION=1.2.3
NODE_ENV=production
REDIS_PASSWORD=你的Redis密码
SMTP_HOST=smtp.yourdomain.com
SMTP_USER=noreply@yourdomain.com
SMTP_PASS=邮件密码

三、零停机更新策略

<code">#!/bin/bash
# /usr/local/bin/deploy-update.sh
# 新版本镜像推送后,执行此脚本零停机更新应用

set -e
APP_VERSION="${1:-latest}"
COMPOSE_FILE="/srv/myapp/docker-compose.yml"

echo "=== 开始部署版本:$APP_VERSION ==="

cd /srv/myapp

# 1. 拉取新镜像
APP_VERSION="$APP_VERSION" docker compose pull app

# 2. 滚动更新(新容器启动健康后,旧容器才下线)
APP_VERSION="$APP_VERSION" docker compose up -d \
    --no-deps \
    --build \
    app

# 3. 等待健康检查通过
echo "等待新容器健康检查..."
timeout 120 bash -c 'until [ "$(docker compose ps app --format json | python3 -c "import sys,json; d=json.load(sys.stdin); print(d[\"Health\"])" 2>/dev/null)" = "healthy" ]; do sleep 5; done'

echo "✅ 部署成功:版本 $APP_VERSION"

# 4. 清理旧镜像(保留最近3个版本)
docker image prune -f

四、日志管理与查看

<code"># 查看所有服务日志
docker compose logs -f

# 查看特定服务日志(最近100行)
docker compose logs --tail=100 app

# 查看特定时间段的日志
docker compose logs --since="2026-01-02T10:00:00" --until="2026-01-02T11:00:00" app

# 统计错误日志频率
docker compose logs app 2>&1 | grep -i "error" | \
    awk '{print $1, $2}' | sort | uniq -c | sort -rn | head -20

# 导出日志到文件
docker compose logs --no-color app > /tmp/app-logs-$(date +%Y%m%d).log

五、监控容器资源使用

<code"># 实时查看所有容器的CPU/内存使用
docker stats

# 查看特定容器详细信息
docker inspect 容器名称 | jq '.[0].State, .[0].HostConfig.Memory'

# 查看容器网络统计
docker stats --no-stream --format "table {{.Name}}\t{{.CPUPerc}}\t{{.MemUsage}}\t{{.NetIO}}"

六、常用运维命令速查

<code"># 启动所有服务
docker compose up -d

# 停止所有服务(保留数据)
docker compose stop

# 停止并删除容器(保留数据卷)
docker compose down

# 停止并删除所有内容(包括数据卷,危险!)
docker compose down -v

# 重启单个服务(不影响其他服务)
docker compose restart app

# 进入容器内部调试
docker compose exec app /bin/sh

# 在容器内执行命令
docker compose exec mysql mysql -u root -p

# 查看服务状态和健康
docker compose ps

# 强制重建镜像并更新
docker compose up -d --force-recreate --build app

七、总结

生产级Docker Compose配置的核心要素:健康检查(确保依赖服务就绪)+ 密钥管理(Secrets替代环境变量)+ 日志限制(防止磁盘写满)+ 资源限制(防止单容器耗尽宿主机资源)。IDC.Net的香港VPS全系KVM架构,完整支持Docker的所有功能,是部署容器化应用的可靠基础平台。

THE END