灰度发布策略(一):蓝绿部署

说到灰度发布,蓝绿部署是我最常用的策略之一。简单来说,它就像给系统准备了两套独立的环境——一套蓝色(当前运行的老版本),一套绿色(你要发布的新版本)。两套环境并存,但同一时刻只有一套在承接用户流量。

核心思想:一次切换,而非逐步放量。你完全可以在绿色环境上验证好,然后瞬间把流量从蓝色切到绿色。

蓝绿部署的原理

我个人习惯把蓝绿部署看作是「全量切换」的一种优雅实现。它的架构其实很清晰:

  • 蓝色环境(Blue):当前的生产环境,运行着旧版本。
  • 绿色环境(Green):预配好的新版本环境,与蓝色环境完全隔离。
  • 负载均衡器/路由层:流量切换的核心开关。

你可能会问,那这两套环境怎么共享数据?嗯,这里要注意,数据库和持久化存储通常是共享的。所以,新版本在数据库 schema 上的兼容性就变得非常关键。我在项目中遇到过,就是因为没处理好数据库迁移,导致切到绿色环境后发现数据对不上,不得不紧急回滚。

避坑指南:我曾经接手过一个项目,蓝绿环境各自连了独立的数据库,结果切换后发现数据断层了。记住,蓝绿环境通常共享数据层,应用层才是隔离的。

蓝绿部署架构示意图 用户流量入口 负载均衡器 / 路由 蓝色环境 (Blue) 运行:旧版本 (v1.2) 状态:● 在线 (流量承载) 副本数: 8 Pods 绿色环境 (Green) 运行:新版本 (v2.0) 状态:● 待机 (未接流量) 副本数: 8 Pods 共享数据层 (数据库 / 缓存) 通常,绿色环境用独立域名直接验证;确认无误后,路由层将流量从蓝色切换到绿色。

蓝绿部署的优点

说白了,蓝绿部署最大的好处就是「快」和「安全」。我罗列几个关键点:

  • 切换极快:全量切换只是路由层改个配置,几秒钟就完成了。
  • 回滚秒级:出问题了?把路由切回蓝色环境就行。本质上就是一次「反向切换」。
  • 两套环境独立验证:绿色环境可以提前部署好,QA 团队可以提前在上面跑完整的回归测试。
  • 零停机发布:切换瞬间用户几乎无感知。

蓝绿部署的缺点

当然,没有银弹。蓝绿部署也有明显的短板,我来分享一下我的真实体会:

  • 资源成本翻倍: 你要同时维护两套一模一样的环境,硬件或云资源开销几乎翻倍。我建议只在关键业务上使用,或者通过 K8s 弹性缩容来降低成本。
  • 数据库兼容性风险: 如果新版改了数据库 schema,切换时很难保证平滑。我曾经就踩过这个坑,回滚时发现老版本读不了新数据,不得不做数据回滚,整个过程非常痛苦。
  • 不适合逐步观察: 它不能像金丝雀发布那样,先放 1% 的流量观察一段时间。说白了,蓝绿是「全部切换」或「全部不切换」,没有中间状态。

适用场景

根据我的经验,蓝绿部署在下面这些场景特别有用:

适用场景 原因
前端静态资源 / Serverless 服务 切换快,回滚极简单,几乎没有有状态依赖。
无状态微服务 只要数据层兼容,随便切。
重大版本发布 需要做全量回归测试和预发布验证。
有严格合规要求的场景 需要完整的审计日志和可追溯的切换动作。

回滚实现:这是重点

蓝绿部署的回滚,在我看来也是它最出彩的地方。回滚其实就是「把流量切回蓝色环境」。你想想看,绿色环境出了问题,我们只要把路由器的目标地址指向蓝色环境就行。

具体来说,我一般这么做:

# 假设你用 Nginx 做负载均衡器
# 当前 flow 指向 green
upstream myapp {
    server green-cluster.example.com:8080;
}

# 回滚时,只需要把配置文件改回 blue
upstream myapp {
    server blue-cluster.example.com:8080;
}

# 然后重新加载 Nginx
nginx -s reload

注意:如果你在 CI/CD 里自动化回滚,我建议把回滚作为一个独立 Pipeline。比如,在 Pipeline 里加一个 Rollback 按钮。我曾经见过有人手动改配置,结果改错了把两个环境都搞崩了。

在 CI 工具(比如 Jenkins 或 GitLab CI)里,回滚 Pipeline 可以是这样的:

stages:
  - deploy_blue
  - deploy_green
  - switch_to_green
  - rollback_to_blue  # 独立的回滚阶段

rollback_to_blue:
  stage: rollback_to_blue
  script:
    - echo "开始回滚到蓝色环境..."
    - kubectl set image deployment/myapp-v1 -n production myapp=myapp:v1.2
    - kubectl patch service myapp -n production -p '{"spec":{"selector":{"version":"v1.2"}}}'
  when: manual  # 手动触发,避免误操作

CI 分层支持实战

在 CI 里支持蓝绿部署,我建议做到 3 层:

  1. 构建层: 每次代码合并 → 自动构建两套环境的镜像(蓝/绿)。绿色镜像打上 v2.0 标签,蓝色镜像保持 stable 标签。
  2. 部署层: 自动部署到绿色环境,并触发自动化冒烟测试。
  3. 切换层: 只有负责人手动确认后,Pipeline 才会执行流量切换。

个人经验:我一般会在切换层之前加一个「Post-deploy health check」步骤。比如,检查绿色环境的 /healthz 接口是否返回 200,并且响应时间在正常范围内。如果不达标,自动中止切换,并通知相关人员。

# 在 pipeline 中加一个简单的健康检查步骤
check_health:
  stage: verification
  script:
    - for i in 1 2 3 4 5; do
        STATUS=$(curl -s -o /dev/null -w "%{http_code}" http://green-cluster.example.com/healthz);
        if [ "$STATUS" -eq 200 ]; then
          echo "Green 环境健康检查通过";
          exit 0;
        fi;
        sleep 5;
      done;
    - echo "Green 环境健康检查失败,自动中止发布";
    - exit 1;

这样三层下来,每次发布都像走一条标准流程。出错?一键回滚到蓝色环境,蓝绿部署的这份安全感,真的很踏实。