Skip to content

Docker Swarm 部署多环境集群实践

Posted on:2023-11-05 at 15:30

Docker Swarm 部署多环境集群时,服务配置很多都是共用的,如果把每个环境的配置都分别保存未免有些啰嗦,而且一旦有变更就需要修改多个文件,这时就可以对配置文件进行拆分。

一个常见的多环境部署方案是 local staging production 三环境部署。local 是开发人员在本地开发和测试使用的,staging 是系统预览环境,用来在系统上线前测试并发现问题,production 环境则是线上生产环境。

这三个环境很可能只有部分参数不同,例如 replicas 数量、数据库的用户名密码、开放端口等。而不太重要的一些参数(比如滚动更新配置、labels等)很有可能是共用的,如果把每个环境的配置都分别保存为一个 yaml 文件未免有些啰嗦,一旦有变更还要修改多个文件。

这时就可以拆分 compose 文件,像下面这样

# base.yaml 文件
version: "3.8"

services:
  # wordpress 服务的公共配置
  wordpress:
    ports:
      - 8080:80
    networks:
      - overlay
    deploy:
      restart_policy:
        condition: any
        delay: 5s
        max_attempts: 3
        window: 120s
      rollback_config:
        parallelism: 1
        delay: 0s
        monitor: 10s
        order: stop-first
      update_config:
        parallelism: 1
        delay: 10s
        monitor: 10s
        order: start-first

networks:
  overlay:
# staging.yaml 文件
version: "3.8"

services:
  wordpress:
    image: wordpress # staging 环境使用的镜像版本
    environment:
      WORDPRESS_DB_HOST: db:3306 # staging 环境的连接配置
    deploy:
      mode: replicated
      replicas: 1 # staging 环境不需要多个实例
# prod.yaml 文件
version: "3.8"

services:
  wordpress:
    image: wordpress # production 环境使用的镜像版本
    environment:
      WORDPRESS_DB_HOST: online-db:3306 # production 环境的连接配置
    deploy:
      mode: replicated
      replicas: 3 # production 环境的实例数量

执行 docker stack deploy -c base.yaml -c staging.yaml 命令就是用 staging 环境的配置去部署,它会将 base.yamlstaging.yaml 的内容进行合并。将 staging.yaml 替换为 prod.yaml 就可以用 production 的配置进行部署了。

另外一个技巧是,如果一个 compose 文件定义了多个 service,那不同的 service 也可能有相同的重启策略、回滚策略等,这时可以用 yaml 的锚点技巧优化 compose 文件定义,例如

# docker-compose.yaml
version: "3.8"

# 在 docker compose 文件中,以 x- 开头的字段会被识别为变量
x-deploy-defaults: &deploy-defaults
  restart_policy:
    condition: any
    delay: 5s
    max_attempts: 3
    window: 120s
  rollback_config:
    parallelism: 1
    delay: 0s
    monitor: 10s
    order: stop-first
  update_config:
    parallelism: 1
    delay: 10s
    monitor: 10s
    order: start-first

x-healthcheck-defaults: &healthcheck-defaults
  interval: 30s
  timeout: 5s
  retries: 3
  start_period: 10s

services:
  # 第一个服务
  wordpress:
    image: wordpress
    deploy:
      <<: *deploy-defaults # 插入前面定义的 deploy-defaults 变量
    healthcheck:
      <<: *healthcheck-defaults # 插入前面定义的 healthcheck-defaults 变量
      test: ["CMD", "curl", "-f", "http://localhost"]

  # 第二个服务
  wordpress-2:
    image: wordpress
    deploy:
      <<: *deploy-defaults # 插入前面定义的 deploy-defaults 变量
    healthcheck:
      <<: *healthcheck-defaults # 插入前面定义的 healthcheck-defaults 变量
      test: ["CMD", "curl", "-f", "http://localhost"]