在 CI 中自动根据模板生成 docker-compose 并部署
解读
国内一线互联网与金融公司普遍采用 GitLab-CI / Jenkins + Harbor + 自建 K8s 的混合云架构。面试官想确认你是否能把「模板化」与「自动化」落地到整条流水线:
- 模板如何与 多环境(dev/test/stage/prod) 解耦;
- 如何 零停机滚动升级 并保证 回滚秒级可用;
- 如何 审计 & 合规(等保 2.0、国密、内网安全扫描)。
回答必须体现「模板即代码」与「不可变基础设施」思想,否则会被认为只能写“静态 YAML”。
知识点
- Jinja2 / Helm / Kustomize 变量语法差异与选型理由
- docker-compose --compatibility 与 Swarm overlay 网络限制
- ARG/ENV 差异 与 多阶段构建缓存复用
- CI_COMMIT_SHORT_SHA、CI_MERGE_REQUEST_ID 等 GitLab 预定义变量
- docker stack deploy --prune 与 rollback-order 参数
- 健康检查(healthcheck) 与 depends_on 条件化启动
- Secrets 管理:Docker Config vs Swarm Secret vs 外部 Vault
- 镜像加速:阿里云 ACR 镜像缓存 + 个人版 VPC 免公网
- 合规扫描:trivy / Clair / 阿里云云安全中心镜像扫描
- 蓝绿 / 金丝雀:Traefik 权重标签 或 Nginx Ingress canary-by-header
答案
-
目录规范(被多家大厂作为 强制代码规约 检查项)
├── templates │ ├── docker-compose.yml.j2 │ └── nginx.conf.j2 ├── environments │ ├── dev.env │ ├── test.env │ └── prod.env ├── scripts │ └── render_compose.py └── .gitlab-ci.yml -
模板示例(docker-compose.yml.j2)
version: "3.9" services: app: image: {{ REGISTRY }}/{{ PROJECT }}:{{ CI_COMMIT_SHORT_SHA }} deploy: replicas: {{ REPLICAS }} update_config: parallelism: 1 delay: 10s failure_action: rollback restart_policy: condition: on-failure max_attempts: 3 secrets: - source: db_pass target: /run/secrets/db_pass healthcheck: test: ["CMD", "wget", "-q", "--spider", "http://localhost:8080/health"] interval: 15s retries: 4 secrets: db_pass: external: true -
render_compose.py(Python3 官方镜像 50MB,内网秒拉)
#!/usr/bin/env python3 import os, sys, jinja2 env = jinja2.Environment(loader=jinja2.FileSystemLoader('templates')) template = env.get_template('docker-compose.yml.j2') with open('environments/%s.env' % os.getenv('CI_ENVIRONMENT_NAME'), 'r') as f: ctx = dict(line.strip().split('=',1) for line in f if '=' in line) ctx.update(os.environ) # 让 CI 预定义变量覆盖文件变量 with open('docker-compose.yml', 'w') as f: f.write(template.render(ctx)) -
.gitlab-ci.yml(关键阶段必须设置 timeout 与 retry,防止构建队列堆积)
stages: - build - render - deploy variables: REGISTRY: "registry.cn-hangzhou.aliyuncs.com/yourproj" PROJECT: "demo" build: stage: build image: docker:24 services: - docker:24-dind before_script: - echo $ALIYUN_CR_PWD | docker login -u $ALIYUN_CR_USER --password-stdin $REGISTRY script: - docker build -t $REGISTRY/$PROJECT:$CI_COMMIT_SHORT_SHA . - docker push $REGISTRY/$PROJECT:$CI_COMMIT_SHORT_SHA - trivy image --exit-code 1 --severity HIGH,CRITICAL $REGISTRY/$PROJECT:$CI_COMMIT_SHORT_SHA render: stage: render image: python:3.11-alpine script: - pip install jinja2 - python scripts/render_compose.py artifacts: paths: - docker-compose.yml expire_in: 1 week deploy: stage: deploy image: alpine:3.18 before_script: - apk add --no-cache docker-cli-compose script: - docker context create remote --docker "host=ssh://$SWARM_MANAGER" - docker --context remote stack deploy -c docker-compose.yml $STACK_NAME --with-registry-auth --prune environment: name: $CI_ENVIRONMENT_NAME url: http://$DOMAIN only: - master - /^release\/.*$/ -
回滚策略
在 GitLab 界面点击 “回滚” 按钮,CI 会重新跑 上一成功 pipeline 的 CI_COMMIT_SHORT_SHA,确保 镜像与配置双维度可回滚;同时 Swarm 自带docker stack rollback可在 30s 内完成。 -
合规加固
- 基础镜像统一来自 阿里云 ACR 基础镜像仓库,已做 CentOS 官方源替换为华为开源镜像站;
- 非 root 用户启动:Dockerfile 末尾
USER 1001; - Secrets 不落盘,通过 Swarm Secret 注入,符合等保 2.0 对敏感数据存储要求;
- 镜像扫描阈值:HIGH 及以上漏洞必须清零 才允许 deploy 阶段运行。
拓展思考
- 如果公司全面切到 Kubernetes,可将 Jinja2 模板改为 Helm Chart,利用
helm upgrade --atomic --timeout 10m实现同样效果;Compose 模板沉淀为 v1 版本,降低迁移成本。 - 对于 边缘机房网络不稳定 场景,可预置 docker-compose 离线包 + 私有 registry 镜像缓存,CI 只下发 manifest 文件,通过 Ansible pull 模式 在边缘节点本地渲染,减少公网依赖。
- 当业务需要 多区域灰度 时,可在模板里引入 Traefik 权重标签 实现 金丝雀 5%→30%→100% 的 自动梯度切换,结合 Prometheus 指标 做 自动回滚决策,形成 无人值守发布。