找回密码
立即注册
搜索
热搜: Java Python Linux Go
发回帖 发新帖

1790

积分

0

好友

232

主题
发表于 昨天 08:04 | 查看: 2| 回复: 0

一、什么是蓝绿发布?

蓝绿发布(Blue-Green Deployment)是一种旨在实现零宕机的发布策略。其核心思想是同时维护两个完全相同的生产环境,然后通过切换流量来实现平滑升级。

简单来说:

  • 🟦 蓝色环境:当前正在对外服务的线上版本。
  • 🟩 绿色环境:包含新版本、等待上线的环境。
  • 🔁 流量切换:通过一个“开关”将用户流量从蓝色环境瞬时切换到绿色环境。
  • 瞬间完成:切换动作通常能在毫秒级内完成。
  • 🔙 秒级回滚:如果新版本出现问题,可以立即将流量切回蓝色环境。

Kubernetes 中实现蓝绿发布,其本质就是:

利用 Service 的 selector 标签选择器 作为一个高效的“流量开关”。

二、生产级架构设计

📌 典型生产拓扑

                ┌─────────────┐
                │   Ingress   │
                └──────┬──────┘
                       │
               ┌──────────────┐
               │  prod-svc    │  ← 只修改 selector
               └──────┬───────┘
                      │
        ┌──────────────┴──────────────┐
        │                             │
 ┌─────────────┐               ┌─────────────┐
 │ app-blue    │               │ app-green   │
 │ Deployment  │               │ Deployment  │
 └──────┬──────┘               └──────┬──────┘
        │                             │
     Pod x3                        Pod x3

在生产环境中,我们通常采用以下设计原则:

  • 为每个版本(蓝、绿)创建独立的 Deployment
  • 可以(可选地)为每个版本创建独立的 Service,用于内部调试。
  • 创建一个统一的、面向用户的 prod-svc(生产服务)。
  • 入口(Ingress)只指向这个统一的 prod-svc
  • 发布时,仅需修改 prod-svcselector,即可将流量导向目标版本。

三、完整生产级 YAML 示例

1️⃣ 蓝版本 Deployment

apiVersion: apps/v1
kind: Deployment
metadata:
  name: app-blue
  namespace: blue-green-demo
spec:
  replicas: 3
  selector:
    matchLabels:
      app: myapp
      version: blue
  template:
    metadata:
      labels:
        app: myapp
        version: blue
    spec:
      containers:
      - name: app
        image: yourusername/demo:v1
        ports:
        - containerPort: 80

        resources:
          requests:
            cpu: "100m"
            memory: "128Mi"
          limits:
            cpu: "300m"
            memory: "256Mi"

        readinessProbe:
          httpGet:
            path: /
            port: 80
          initialDelaySeconds: 5
          periodSeconds: 5

        livenessProbe:
          httpGet:
            path: /
            port: 80
          initialDelaySeconds: 10
          periodSeconds: 10

2️⃣ 绿版本 Deployment

创建绿版本 Deployment 时,核心修改只有两处:

version: green
image: yourusername/demo:v2

其他配置,如资源限制、探针等,应与蓝版本保持一致以确保环境一致性。

3️⃣ 统一生产 Service

这个服务是流量切换的关键。

apiVersion: v1
kind: Service
metadata:
  name: prod-svc
  namespace: blue-green-demo
spec:
  selector:
    app: myapp
    version: blue  # 初始指向蓝版本
  ports:
  - port: 80
    targetPort: 80
  type: ClusterIP

四、流量切换(核心步骤)

切换到绿版本

执行一条 kubectl patch 命令即可完成切换:

kubectl patch svc prod-svc -n blue-green-demo \
  -p '{"spec":{"selector":{"version":"green"}}}'
  • 切换时间:毫秒级。Kubernetes 会立即更新 Service 的端点(Endpoints)列表。
  • 🟢 无需重启:不会影响任何正在运行的 Pod。
  • 🟢 无需滚动更新:瞬间完成全量切换。

回滚到蓝版本

如果绿版本出现问题,回滚操作同样简单直接:

kubectl patch svc prod-svc -n blue-green-demo \
  -p '{"spec":{"selector":{"version":"blue"}}}'

这就是蓝绿发布的最大价值之一:

回滚不需要重新部署旧版本应用。旧版本一直以完整的副本数在运行,随时待命。

五、数据库升级的真正难点(90% 团队踩坑)

蓝绿发布最大的风险往往不在于应用本身,而在于数据库的结构变更

试想一下,如果绿版本的应用代码依赖一个修改过的数据库 Schema(例如删除了某个字段),而你将流量切到绿版本后发现了问题。当你试图切回蓝版本时,蓝版本的应用会因为找不到那个已被删除的字段而崩溃,导致回滚失效

常见的破坏性变更包括:

  • 删除字段
  • 修改字段类型或约束
  • 更改索引
  • 重命名表

✅ 正确做法:Expand → Migrate → Contract 模式

  1. Expand(扩展阶段)

    • 在发布新版本之前,先对数据库进行“扩展”操作。
    • 只新增字段或表,绝对不删除、不修改现有的字段。
    • 绿版本和蓝版本的代码此时都能兼容新旧两套 Schema。
  2. Migrate(迁移阶段)

    • 部署绿版本应用,此时它开始写入新字段,但可能仍能读取旧字段。
    • 运行数据迁移脚本,将旧数据填充到新结构中(异步进行)。
    • 切换流量到绿版本。由于 Schema 是兼容的,即使此时回滚,蓝版本也能正常运行。
  3. Contract(收缩阶段)

    • 确认绿版本稳定运行足够长的时间(例如一周)。
    • 在下一个发布周期中,安全地删除那些不再被任何版本使用的旧字段或表。

六、真实生产事故案例

🚨 事故一:未配置 ReadinessProbe

现象

  • 绿版本 Deployment 刚刚创建,Pod 处于 ContainerCreatingRunning 但应用未完成初始化。
  • 运维人员执行了流量切换。
  • Service 将请求转发到了尚未就绪的绿版本 Pod。
  • 结果:全站出现大量 502 Bad Gateway503 Service Unavailable 错误。

原因
Kubernetes 默认只检查 Pod 是否 Running,而不会判断 Pod 内的应用是否已经准备好接收流量。如果没有 readinessProbe,Service 会立即将新 Pod 纳入负载均衡池。

解决
如前面 YAML 所示,必须为你的应用配置有效的 readinessProbe。只有当探针通过后,Pod 才会被标记为就绪,Service 才会向其转发流量。

🚨 事故二:Session 存储在本地内存

现象

  • 流量从蓝版本切换到绿版本后。
  • 用户会话(Session)全部丢失,所有用户需要重新登录。
  • 部分正在进行中的操作因会话失效而报错。

原因
许多应用的默认 Session 存储在本地进程内存中。当流量从一个环境的 Pod 切换到另一个环境的 Pod 时,新的 Pod 无法访问旧 Pod 内存中的 Session 数据。

解决
使用外部集中式存储来管理 Session,例如 Redis 或数据库。确保蓝绿两个环境的应用都能访问同一份 Session 存储,这样切换时用户状态不会丢失。

🚨 事故三:定时任务重复执行

现象

  • 蓝绿两个环境的 Deployment 同时运行。
  • 两个环境内的应用实例都激活了各自的定时任务(如每天凌晨的数据报表生成)。
  • 导致任务被重复执行两次,造成数据错乱或重复计算。

解决方案

  • 使用分布式锁:在任务执行前,尝试从一个共享存储(如 Redis、ZooKeeper)获取全局锁,确保同一时间只有一个实例能执行任务。
  • 环境区分:在定时任务逻辑中判断当前 Pod 的标签(如 version),只允许当前流量所指版本(即 prod-svc 选中的版本)执行任务。非活动版本的任务自动跳过。

七、与滚动更新对比

维度 滚动更新 蓝绿发布
是否双环境 ❌ 同一套 Deployment 逐渐替换 ✅ 两套独立的 Deployment
是否可秒级回滚 ❌ 回滚需重新滚动部署旧镜像 ✅ 只需切换 Service selector
是否支持完整预验证 ❌ 无法用真实流量测试完整新版本 ✅ 可在隔离环境中完整测试新版本
资源消耗 低(副本数小幅波动) 高(长期双倍资源)
适合场景 普通服务、无状态应用、迭代迅速 核心系统、关键业务、追求高可用

八、进阶:结合 Service Mesh

如果你在集群中已经部署了 Service Mesh(如 Istio 或 Linkerd),蓝绿发布可以变得更加智能和强大,轻松升级为金丝雀发布

  • 精细化流量控制:可以实现 10% -> 30% -> 50% -> 100% 的渐进式流量切换,而非“一刀切”。
  • 基于指标的自动决策:监控新版本(绿版本)的请求错误率、延迟等指标。如果指标超出阈值,Mesh 可以自动执行回滚,将流量切回蓝版本。
  • 多维条件路由:可以根据请求头(如 内部用户)、用户标识等条件,将特定流量导向新版本进行测试。

九、CI/CD 自动化切流脚本

将切换操作脚本化并集成到你的 DevOps 流水线中是生产级实践的关键。下面是一个简单的 Bash 脚本示例:

#!/bin/bash

NAMESPACE=blue-green-demo
SERVICE=prod-svc
TARGET=$1

if [[ "$TARGET" != "blue" && "$TARGET" != "green" ]]; then
  echo "Usage: ./switch.sh [blue|green]"
  exit 1
fi

kubectl patch svc $SERVICE -n $NAMESPACE \
  -p "{\"spec\":{\"selector\":{\"version\":\"$TARGET\"}}}"

echo "Switched to $TARGET"

你可以将这个脚本轻松集成到:

  • Jenkins Pipeline
  • GitLab CI/CD
  • GitHub Actions
  • ArgoCD 的钩子(Hook)中

十、生产级最佳实践 Checklist

上线前,请逐一核对以下清单:

  • 必须配置 readinessProbe:确保流量只被导向已就绪的 Pod。
  • 必须设置资源限制(requests/limits:防止单个版本异常消耗所有集群资源。
  • 数据库 Schema 向前兼容:严格遵守 Expand → Migrate → Contract 模式。
  • Session 外部化:使用 Redis 等外部存储,避免会话丢失。
  • 定时任务加分布式锁:或设计为仅活动版本执行。
  • 保留旧版本至少 24-48 小时:为彻底的回滚和问题排查留出足够时间。
  • 自动化切流:将切换命令封装为脚本或流水线步骤,禁止在生产环境使用 kubectl edit 手工修改。

十一、蓝绿发布的成本

采用蓝绿发布策略,最直观的成本增加在于资源

  • 在发布和观察期间,你需要同时运行两套完整的应用实例,这意味着临时的资源使用量接近翻倍
  • 会对集群的 CPU、内存配额产生额外压力。

然而,这笔成本换来的是:

零宕机时间、秒级回滚能力、以及对发布风险极强的控制力。

对于电商交易、支付网关、核心后台管理等关键业务系统而言,这种用资源换取稳定性和可控性的权衡,通常是绝对值得的。

十二、总结

蓝绿发布在 Kubernetes 中的实现,其核心难点并不在于编写 YAML 文件,而在于背后的系统性设计规范

它考验的是团队的以下能力:

  • 流量控制能力:能否精确、瞬时地操纵流量指向。
  • 数据兼容设计:能否处理好最棘手的数据库变更问题。
  • 快速回滚能力:预案是否完善,流程是否顺畅。
  • 自动化与流程化能力:发布是脚本化的标准操作,还是依赖人工的“骚操作”。

正如很多在 云栈社区 交流的一线工程师所共识的:真正的生产级蓝绿发布,

技术实现只占 30%,而规范、流程与团队协作占了剩下的 70%。

希望这份从架构到踩坑指南的完整梳理,能帮助你不仅仅“跑通 Demo”,更能有信心将蓝绿发布应用于真实的生产环境之中。




上一篇:设计师进阶难?基础薄弱成30岁+瓶颈,三大提升方法解析
下一篇:一名被裁程序员的心里话:技术之外的焦虑与职场“青春饭”
您需要登录后才可以回帖 登录 | 立即注册

手机版|小黑屋|网站地图|云栈社区 ( 苏ICP备2022046150号-2 )

GMT+8, 2026-3-1 00:44 , Processed in 0.386912 second(s), 42 queries , Gzip On.

Powered by Discuz! X3.5

© 2025-2026 云栈社区.

快速回复 返回顶部 返回列表