当补丁导致容器启动失败时的回滚策略

解读

国内互联网节奏快、灰度窗口短,补丁一旦引入启动失败,必须在分钟级完成回滚,否则直接影响 SLA 与资损。面试官想确认:

  1. 你是否具备**“可回滚”设计前置意识**(镜像版本化、不可变基础设施);
  2. 能否在Swarm/K8s 双栈环境下,用 Docker 原生能力快速止血;
  3. 是否熟悉国内云厂商镜像仓库的限速与配额,保证回滚镜像秒级拉取;
  4. 能否把回滚动作沉淀为CI/CD 模板,下次无人值守。

知识点

  • 镜像不可变原则:tag 永不复用,生产只用 digest 或 v1.2.3-<git-sha> 级 tag。
  • Docker Compose v3.7+ rollbackdocker stack deploy --rollback-order stop-first --rollback-parallelism 1 可单批串行回滚,避免雪崩。
  • Swarm 任务历史docker service ps --no-trunc 查看失败原因,docker service rollback 一键回到上一版本,默认 5 分钟内完成
  • 健康检查与重启策略HEALTHCHECK --interval=5s --retries=3 配合 restart-policy: on-failure:3连续失败即触发回滚
  • 镜像预热:在阿里云 ACR 个人版限速 1 MB/s 场景下,提前 docker pull <旧镜像> 到所有节点,回滚时直接本地起容器,零网络等待
  • Secrets 版本对齐:回滚时若旧镜像依赖旧版证书,需同时回滚 Docker Secrets,避免“镜像旧、配置新”导致二次失败。
  • CI/CD 卡点:GitLab CI 在 .gitlab-ci.yml 中设置 only: variables: $ROLLBACK == "true"一键创建回滚流水线,人工只需点“retry”。
  • 审计与告警:在钉钉群机器人接入 docker events --filter event=service_rollback回滚动作 10 秒内推送,方便运营复盘。

答案

线上出现补丁镜像 app:v1.2.4 启动失败,按以下 6 步回滚

  1. 立即止血
    docker service update --rollback --detach=false myapp
    Swarm 自动回到上一稳定版本 app:v1.2.3串行替换,确保数据库连接池不瞬间打满
  2. 定位根因
    docker service ps myapp --no-trunc | grep Failed 拿到容器 ID,
    docker logs --tail 200 <ID> 结合 dmesg | grep OOM 判断是补丁引入的新依赖缺库还是内存泄漏
  3. 镜像预热
    若集群跨可用区,提前在各节点执行
    docker pull registry.cn-hangzhou.aliyuncs.com/xxx/app:v1.2.3
    利用阿里云 ACR 预热 API回滚时无需等待限速
  4. 配置同步
    v1.2.4 改动了 /run/secrets/api-key,回滚前执行
    echo "old-key" | docker secret create api-key-v1.2.3 -
    并在 Compose 文件里指定 secret: api-key-v1.2.3保证密钥版本与镜像一致
  5. CI/CD 模板固化
    在 GitLab CI 新增 rollback-job
    rollback:
      stage: deploy
      script:
        - docker stack deploy -c docker-compose.yml myapp
      only:
        variables:
          - $ROLLBACK == "true"
    
    下次回滚只需在 Web 端点击“retry”无需运维半夜登录堡垒机
  6. 复盘与防重
    将失败镜像 v1.2.4blocklist 标签,禁止 CI 再次推送同名 tag
    云效流水线增加“启动探测”阶段,健康检查失败即自动回滚并阻塞后续阶段把故障消灭在灰度 10% 阶段

拓展思考

  • 双镜像仓库策略:核心支付服务同步到金融云 ACR 与自建 Harbor,当公网 ACR 被运营商 QoS 限速时,秒级切换内网 Harbor 完成回滚
  • 蓝绿回滚与数据库兼容:若补丁包含不可逆 SQL,需先在 CI 中跑 flyway migrate -target=1.2.3向下迁移脚本,否则回滚后容器启动成功但业务逻辑报错
  • Serverless 场景:在阿里云 ECI 弹性容器实例中,没有 Swarm,需提前用虚拟节点 + Deployment 的 revisionHistoryLimit=10,通过 kubectl rollout undo 回滚,Docker 选手也要懂 K8s 逃生通道