Featured image of post 用于生产的 Docker Compose:部署最佳实践Featured image of post 用于生产的 Docker Compose:部署最佳实践

用于生产的 Docker Compose:部署最佳实践

生产 Docker Compose 最佳实践:组合文件版本控制、服务依赖项、运行状况检查、日志记录驱动程序、资源限制、机密和滚动更新。

介绍

Docker Compose 通常被归为本地开发,但它越来越多地用于中小型应用程序的单主机生产部署。 “Compose 不适用于生产”的常见批评忽略了一个关键点:对于许多工作负载,单个虚拟机上配置良好的 Compose 堆栈可以提供简单性和可靠性之间的适当平衡。

本指南涵盖了生产级 Compose 实践 - 通过适当的版本控制、CI/CD 集成和特定于生产的强化,将您的 compose 文件视为基础设施即代码。


1. 组合文件结构和版本控制

使用 Compose 规范(格式 3.8+)并采用多文件策略来分离关注点:

compose.yml          # Base configuration (shared across environments)
compose.override.yml # Local development overrides (not used in production)
compose.prod.yml     # Production-specific overrides

利用 YAML 锚点减少服务之间的重复:

x-logging: &logging
  driver: "json-file"
  options:
    max-size: "10m"
    max-file: "3"

services:
  app:
    image: myapp:latest
    logging: *logging
    restart: unless-stopped

使用 --env-file 注入特定于环境的变量并避免硬编码秘密。优先使用 docker compose (v2),而不是已弃用的 docker-compose (v1)。


2. 服务依赖和健康检查

仅依靠 depends_on 不足以进行生产。使用 condition: service_healthy 确保服务在启动之前等待依赖项通过运行状况检查。

services:
  postgres:
    image: postgres:16
    healthcheck:
      test: ["CMD-SHELL", "pg_isready -U $$POSTGRES_USER"]
      interval: 5s
      timeout: 5s
      retries: 5
      start_period: 30s

  app:
    depends_on:
      postgres:
        condition: service_healthy
    healthcheck:
      test: ["CMD", "curl", "-f", "http://localhost:3000/healthz"]
      interval: 10s
      timeout: 3s
      retries: 3

这种级联健康检查模式 - Nginx → App → Redis → PostgreSQL - 确保每个服务仅在其依赖项真正准备就绪时启动。


3. 组网配置

使用带有 driver: bridge 的自定义网络进行服务隔离。避免使用默认的 bridge 网络,该网络缺乏通过 DNS 的服务发现。

networks:
  frontend:
    driver: bridge
  backend:
    driver: bridge
    internal: true
  monitoring:
    driver: bridge

services:
  app:
    networks:
      frontend:
      backend:
      monitoring:

三网络拓扑提供了干净的分离:frontend 用于反向代理和应用程序,backend(内部)用于应用程序和数据库,monitoring 用于可观察性工具。使用网络别名在重新启动后实现稳定的 DNS 解析。


4. 资源约束和限制

生产容器必须有资源边界,以防止单个服务导致主机资源匮乏。

services:
  app:
    deploy:
      resources:
        limits:
          cpus: '0.5'
          memory: 256M
          pids: 100
        reservations:
          cpus: '0.25'
          memory: 128M
指令目的
占位符_0最大 CPU 核心数(例如 '0.5' = 半个核心)
占位符_0OOM 终止前的最大内存
占位符_0保证最低资源
占位符_0文件描述符和进程限制(例如 nofile: 65536

对于 Node.js 应用程序,请将 --max-old-space-size 与内存限制对齐,以避免垃圾收集抖动。


5. 日志记录和可观察性

集中日志记录对于调试生产问题至关重要。配置 json-file 驱动程序进行轮换以防止磁盘耗尽:

x-logging: &logging
  driver: "json-file"
  options:
    max-size: "10m"
    max-file: "5"

集中聚合的替代驱动因素:

司机目的地使用案例
占位符_0Fluentd → Elasticsearch全文搜索和分析
占位符_0格雷洛格结构化日志管理
占位符_0亚马逊CloudWatchAWS 原生部署

从应用程序输出结构化 JSON,以便 Docker 可以有效地转发它。使用 docker compose logs --tail 100 --follow 进行实时调试。


6. 秘密与环境管理

切勿在撰写文件中对机密进行硬编码。对于 Swarm 模式,使用静态加密并作为文件挂载的 Docker Secret:

secrets:
  db_password:
    file: ./secrets/db_password.txt

services:
  app:
    secrets:
      - db_password

对于非 Swarm Compose,请使用 .env 文件(在 .gitignore 中列出),并使用 sopsage 进行加密。通过 $ 语法引用变量:

services:
  app:
    environment:
      - DATABASE_URL=postgres://user:${DB_PASSWORD}@postgres:5432/myapp

定期轮换机密并使用 SERVICE_NAME_SECRET 等命名约定以保持清晰。


7. 滚动更新和零停机部署

使用 deploy.update_config 通过运行状况检查门控来编排滚动更新:

services:
  app:
    deploy:
      replicas: 3
      update_config:
        parallelism: 1
        delay: 10s
        order: start-first
        failure_action: rollback
      rollback_config:
        parallelism: 1
        order: stop-first
参数描述
占位符_0一次更新的容器数量
占位符_0更新组之间暂停
占位符_0start-first(蓝绿色)或 stop-first
占位符_0pausecontinuerollback

运行 docker compose up --detach --wait 进行精心策划的更新,等待运行状况检查通过,然后再考虑部署完成。


8. 反向代理集成

Traefik 是推荐用于 Compose 部署的反向代理。它通过 Docker 标签动态发现服务,并使用 Let’s Encrypt 自动执行 SSL 证书管理。

services:
  traefik:
    image: traefik:v3
    command:
      - "--providers.docker=true"
      - "--entrypoints.websecure.address=:443"
      - "--certificatesresolvers.le.acme.tlschallenge=true"
    ports:
      - "443:443"
    volumes:
      - "/var/run/docker.sock:/var/run/docker.sock"

  app:
    labels:
      - "traefik.http.routers.app.rule=Host(`example.com`)"
      - "traefik.http.services.app.loadbalancer.server.port=3000"

替代方案:Nginx 需要手动上游定义和 SSL 终止配置。 Caddy 提供类似于 Traefik 的自动 HTTPS,但动态重新配置较少。


9. 监控与备份

为可观察性堆栈(cAdvisor + Prometheus + Grafana)定义一个单独的 monitoring.yml 撰写文件。这使得关注点分离——监控可以独立于应用程序进行更新。

对于数据库备份,通过 cron 安排 docker exec 转储:

0 3 * * * docker exec postgres pg_dump -U user mydb > /backups/db_$(date +\%Y\%m\%d).sql

使用 restart: unless-stopped 进行生产服务。与 restart: always 不同,这可以防止容器在手动 docker stop 之后重新启动。


结论

Docker Compose 对于适当规模的部署来说是可行的。将撰写文件视为代码、设计级联运行状况检查、设置资源限制、集中日志、正确管理机密并实施滚动更新。这些实践将 Compose 从一种方便的开发工具转变为一种强大的部署工具。

当扩展需求超出单个主机时,相同的 compose 文件提供了到 Docker Swarm 或 Kubernetes 的平滑迁移路径,使 Compose 成为容器编排的务实起点。