K8S灰度发布与蓝绿部署实战指南-CSDN博客

Kubernetes灰度发布与蓝绿部署实战指南:从原理到生产落地

导读 :在生产环境中,应用升级发布是最常见的运维操作之一,也是最容易引发故障的环节。一次不当的发布可能导致线上服务大面积中断,甚至造成严重的业务损失。本文将深入讲解Kubernetes中两种最主流的发布策略------灰度发布(金丝雀发布)蓝绿部署,从设计思路、YAML编写、逐步实操到生产环境选型建议,带你从入门到精通。


一、为什么需要发布策略?

在企业级生产环境中,直接将旧版本"一刀切"替换为新版本是极其危险的做法。假设你的应用每天有100万次请求,新版本存在一个隐藏的Bug导致5%的请求失败,那么直接发布后瞬间就会有5万次失败请求------这对用户体验和业务声誉的打击是巨大的。

因此,业界发展出了多种渐进式发布策略,核心目标只有一个:

在不影响用户体验的前提下,安全、可控地将新版本推向全量。

1.1 三种主流发布策略对比

策略 原理 优点 缺点 适用场景
灰度发布(金丝雀) 新旧版本按比例共存,逐步调大新版本、缩小旧版本 风险可控,资源利用率高,回滚简单 流量分配粒度受副本数限制 常规功能迭代、Bug修复
蓝绿部署 同时运行两套完整环境,通过切换Service流量实现发布 切换瞬间完成,回滚即时 需要双倍资源,成本较高 重大版本升级、大促保障
A/B测试 基于用户特征精确路由到不同版本 精细化控制,可量化对比 实现复杂,需要额外的流量网关支持 功能实验、用户行为分析

二、灰度发布实战

2.1 设计思路

灰度发布(也叫金丝雀发布)的核心思想是:让新旧版本短期共存,通过逐步调整副本数,让新版本逐渐"蚕食"旧版本的流量。

复制代码
发布流程:
1. 旧版本 Deployment 部署 3 个副本(承载全部流量)
2. 新版本 Deployment 部署 0 个副本(待命)
3. Service 同时匹配新旧版本的 Pod(通过共享标签 apps=xiuxian)
4. 逐步调整:旧 3→2→1→0,新 0→1→2→3
5. 验证无误后,删除旧版本 Deployment

关键点 :Service 的 selector 使用的是新旧版本 共享的公共标签 (如 apps: xiuxian),而不是版本标签。这样才能让流量同时分配到新旧版本的 Pod。

2.2 环境准备

首先部署旧版本(v1):

yaml 复制代码
# 01-deploy-apps-v1.yaml
apiVersion: apps/v1
kind: Deployment
metadata:
  name: deploy-xiuxian-old
spec:
  replicas: 3
  selector:
    matchLabels:
      apps: xiuxian
      version: v1
  template:
    metadata:
      labels:
        apps: xiuxian
      spec:
        containers:
        - name: c1
          image: registry.cn-hangzhou.aliyuncs.com/eci_open/nginx:latest

创建 Service,注意 selector 只使用公共标签

yaml 复制代码
# 02-svc-xiuxian.yaml
apiVersion: v1
kind: Service
metadata:
  name: svc-xiuxian
spec:
  type: ClusterIP
  selector:
    apps: xiuxian       # 关键:只用公共标签,不区分版本
  ports:
  - port: 80

部署并验证:

bash 复制代码
# 部署旧版本
kubectl apply -f 01-deploy-apps-v1.yaml
kubectl apply -f 02-svc-xiuxian.yaml

# 确认Pod运行正常
kubectl get pods -o wide
NAME                                  READY   STATUS    RESTARTS   AGE   IP             NODE
deploy-xiuxian-old-568cf47956-fpx84   1/1     Running   0          4s    10.100.2.231   worker233
deploy-xiuxian-old-568cf47956-qlww5   1/1     Running   0          4s    10.100.2.230   worker233
deploy-xiuxian-old-568cf47956-tgqnx   1/1     Running   0          4s    10.100.1.145   worker232

# 确认Service已关联
kubectl get svc svc-xiuxian -o wide
NAME          TYPE        CLUSTER-IP     EXTERNAL-IP   PORT(S)   AGE   SELECTOR
svc-xiuxian   ClusterIP   10.200.64.17   <none>        80/TCP    4m34s   apps=xiuxian

此时访问 Service IP,所有请求都由 v1 版本处理。

2.3 开始灰度:部署新版本

yaml 复制代码
# 03-deploy-apps-v2.yaml
apiVersion: apps/v1
kind: Deployment
metadata:
  name: deploy-xiuxian-new
spec:
  replicas: 1          # 先只启动1个新版本Pod
  selector:
    matchLabels:
      apps: xiuxian
      version: v2
  template:
    metadata:
      labels:
        apps: xiuxian
      spec:
        containers:
        - name: c1
          image: registry.cn-hangzhou.aliyuncs.com/acs/nginx:1.21
bash 复制代码
kubectl apply -f 03-deploy-apps-v2.yaml

此时集群中有 3个旧版本Pod + 1个新版本Pod,Service 会将流量轮询分配到这4个Pod,新版本自然承担了约25%的流量

2.4 逐步灰度:调整副本比例

这就是灰度发布最核心的操作------通过 kubectl scale 命令逐步调整新旧版本的副本数

bash 复制代码
# 第一步:旧3→2,新1→2(各50%流量)
kubectl scale deployment deploy-xiuxian-old --replicas=2
kubectl scale deployment deploy-xiuxian-new --replicas=2

# 验证Pod状态
kubectl get pods -o wide
NAME                                  READY   STATUS    RESTARTS   AGE     IP
deploy-xiuxian-new-845ffc675b-4zf2z   1/1     Running   0          2s      10.100.1.146
deploy-xiuxian-new-845ffc675b-9jt5c   1/1     Running   0          80s     10.100.2.232
deploy-xiuxian-old-568cf47956-fpx84   1/1     Running   0          8m14s   10.100.2.231
deploy-xiuxian-old-568cf47956-tgqnx   1/1     Running   0          8m14s   10.100.1.145

# 第二步:旧2→1,新2→3(新版本占75%流量)
kubectl scale deployment deploy-xiuxian-new --replicas=3
kubectl scale deployment deploy-xiuxian-old --replicas=1

# 验证Pod状态
kubectl get pods -o wide
NAME                                  READY   STATUS    RESTARTS   AGE     IP
deploy-xiuxian-new-845ffc675b-4zf2z   1/1     Running   0          63s     10.100.1.146
deploy-xiuxian-new-845ffc675b-9jt5c   1/1     Running   0          2m21s   10.100.2.232
deploy-xiuxian-new-845ffc675b-fsnwv   1/1     Running   0          14s     10.100.2.233
deploy-xiuxian-old-568cf47956-fpx84   1/1     Running   0          9m15s   10.100.2.231

# 第三步:旧1→0,完成全量切换
kubectl scale deployment deploy-xiuxian-old --replicas=0

# 确认只剩新版本
kubectl get pods -o wide
NAME                                  READY   STATUS    RESTARTS   AGE     IP
deploy-xiuxian-new-845ffc675b-4zf2z   1/1     Running   0          89s     10.100.1.146
deploy-xiuxian-new-845ffc675b-9jt5c   1/1     Running   0          2m47s   10.100.2.232
deploy-xiuxian-new-845ffc675b-fsnwv   1/1     Running   0          40s     10.100.2.233

提示 :在整个灰度过程中,可以使用 while true; do curl <Service-IP>; sleep 0.1; done 持续观察响应内容,确认新版本是否正常工作。

2.5 灰度发布流程图解

复制代码
时间轴 →

阶段1 [全量v1]          阶段2 [灰度25%]         阶段3 [灰度50%]         阶段4 [灰度75%]         阶段5 [全量v2]
━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━

旧版本Pod:  [●][●][●]          [●][●][●]              [●][●]                 [●]                   (已清除)
                                [●] new               [●][●] new             [●][●][●] new
新版本Pod:  (未创建)            ↑ 25%                  ↑↑ 50%                ↑↑↑ 75%               ↑↑↑ 100%

Service:    selector:           selector:              selector:              selector:              selector:
            apps:xiuxian        apps:xiuxian          apps:xiuxian          apps:xiuxian          apps:xiuxian

关键操作:   初始状态             部署new(1副本)         scale old→2 new→2      scale old→1 new→3      scale old→0

2.6 灰度发布回滚

如果在灰度过程中发现新版本有问题,回滚非常简单:

bash 复制代码
# 一键回滚:直接把新版本副本缩为0,旧版本恢复到3
kubectl scale deployment deploy-xiuxian-new --replicas=0
kubectl scale deployment deploy-xiuxian-old --replicas=3

# 确认回滚成功
kubectl get pods -o wide

这就是灰度发布最大的优势:回滚成本极低,秒级恢复。


三、蓝绿部署实战

3.1 设计思路

蓝绿部署与灰度发布的关键区别在于:两套环境始终各自运行完整的副本数 ,通过修改 Service 的 selector 来决定流量指向哪套环境。

复制代码
发布流程:
1. 旧版本(蓝环境)Deployment 部署 3 个副本
2. 新版本(绿环境)Deployment 部署 3 个副本
3. Service selector 指向旧版本标签(version: v1)
4. 验证新版本Pod正常运行后,修改 Service selector 指向新版本标签(version: v2)
5. 流量瞬间全部切换到新版本

3.2 同时部署两套环境

蓝环境(旧版本 v1)

yaml 复制代码
# 01-deploy-apps-v1-blue.yaml
apiVersion: apps/v1
kind: Deployment
metadata:
  name: deploy-xiuxian-blue
spec:
  replicas: 3
  selector:
    matchLabels:
      apps: xiuxian
      version: v1
  template:
    metadata:
      labels:
        apps: xiuxian
        version: v1
    spec:
      containers:
      - name: c1
        image: registry.cn-hangzhou.aliyuncs.com/eci_open/nginx:latest

绿环境(新版本 v2)

yaml 复制代码
# 02-deploy-apps-v2-green.yaml
apiVersion: apps/v1
kind: Deployment
metadata:
  name: deploy-xiuxian-green
spec:
  replicas: 3
  selector:
    matchLabels:
      apps: xiuxian
      version: v2
  template:
    metadata:
      labels:
        apps: xiuxian
        version: v2
    spec:
      containers:
      - name: c1
        image: registry.cn-hangzhou.aliyuncs.com/acs/nginx:1.21

部署两套环境:

bash 复制代码
kubectl apply -f 01-deploy-apps-v1-blue.yaml -f 02-deploy-apps-v2-green.yaml

# 确认两套环境都正常运行
kubectl get pods -o wide
NAME                                    READY   STATUS    RESTARTS   AGE   IP
deploy-xiuxian-blue-568cf47956-fff9l    1/1     Running   0          5s    10.100.2.238   worker233
deploy-xiuxian-blue-568cf47956-ptvxm    1/1     Running   0          5s    10.100.2.237   worker233
deploy-xiuxian-blue-568cf47956-x7nwn    1/1     Running   0          5s    10.100.1.148   worker232
deploy-xiuxian-green-845ffc675b-jmq78   1/1     Running   0          5s    10.100.1.149   worker232
deploy-xiuxian-green-845ffc675b-nh2js   1/1     Running   0          5s    10.100.2.239   worker233
deploy-xiuxian-green-845ffc675b-zdbsq   1/1     Running   0          5s    10.100.2.236   worker233

# 查看标签确认版本区分
kubectl get pods --show-labels
NAME                                    READY   LABELS
deploy-xiuxian-blue-568cf47956-fff9l    1/1     apps=xiuxian,pod-template-hash=568cf47956,version=v1
deploy-xiuxian-blue-568cf47956-ptvxm    1/1     apps=xiuxian,pod-template-hash=568cf47956,version=v1
deploy-xiuxian-blue-568cf47956-x7nwn    1/1     apps=xiuxian,pod-template-hash=568cf47956,version=v1
deploy-xiuxian-green-845ffc675b-jmq78   1/1     apps=xiuxian,pod-template-hash=845ffc675b,version=v2
deploy-xiuxian-green-845ffc675b-nh2js   1/1     apps=xiuxian,pod-template-hash=845ffc675b,version=v2
deploy-xiuxian-green-845ffc675b-zdbsq   1/1     apps=xiuxian,pod-template-hash=845ffc675b,version=v2

3.3 创建 Service 并指向蓝环境

注意:蓝绿部署中 Service 的 selector 使用的是 version 标签来区分版本! 这与灰度发布使用公共标签的方式完全不同。

yaml 复制代码
# 03-svc-xiuxian.yaml (初始指向蓝环境)
apiVersion: v1
kind: Service
metadata:
  name: svc-xiuxian
spec:
  type: ClusterIP
  selector:
    version: v1          # 指向蓝环境(旧版本)
  ports:
  - port: 80
bash 复制代码
kubectl apply -f 03-svc-xiuxian.yaml

kubectl get svc svc-xiuxian -o wide
NAME          TYPE        CLUSTER-IP      EXTERNAL-IP   PORT(S)   AGE   SELECTOR
svc-xiuxian   ClusterIP   10.200.88.148   <none>        80/TCP    7s    version=v1

此时所有流量都指向蓝环境(v1),绿环境(v2)虽然运行着3个Pod,但不接收任何流量------这正是蓝绿部署"空跑"的含义。

3.4 切换流量:一键发布

确认绿环境Pod运行正常后,只需修改 Service 的 selector:

yaml 复制代码
# 03-svc-xiuxian.yaml (修改后指向绿环境)
apiVersion: v1
kind: Service
metadata:
  name: svc-xiuxian
spec:
  type: ClusterIP
  selector:
    version: v2          # 切换到绿环境(新版本)
  ports:
  - port: 80
bash 复制代码
kubectl apply -f 03-svc-xiuxian.yaml

kubectl get svc svc-xiuxian -o wide
NAME          TYPE        CLUSTER-IP      EXTERNAL-IP   PORT(S)   AGE   SELECTOR
svc-xiuxian   ClusterIP   10.200.88.148   <none>        80/TCP    72s   version=v2

流量切换瞬间完成! 从这一刻起,所有请求都由绿环境(v2)处理,蓝环境变为空跑状态。

3.5 蓝绿部署回滚

如果发现问题,回滚同样简单:

bash 复制代码
# 把selector改回v1即可
# 修改 03-svc-xiuxian.yaml 中 selector.version 为 v1
kubectl apply -f 03-svc-xiuxian.yaml

一键切换,秒级回滚。 这就是蓝绿部署的核心优势。

3.6 蓝绿部署流程图解

复制代码
时间轴 →

阶段1 [蓝环境上线]     阶段2 [绿环境就绪]     阶段3 [流量切换]      阶段4 [清理蓝环境]
━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━

蓝环境(v1):   [●][●][●]           [●][●][●]            [●][●][●]           (删除)
               ↑ 承载流量            ↑ 承载流量           (空跑)
绿环境(v2):   (未创建)              [●][●][●]            [●][●][●]           [●][●][●]
                                     (空跑)               ↑ 承载流量           ↑ 承载流量

Service:      selector:             selector:             selector:            selector:
              version:v1            version:v1           version:v2           version:v2

关键操作:     部署蓝环境            部署绿环境            修改selector         删除蓝环境

四、灰度发布 vs 蓝绿部署:核心区别

通过前面的实战,我们来对比两种策略的关键差异:

4.1 Service Selector 使用方式对比

这是两种策略最本质的技术差异

对比项 灰度发布 蓝绿部署
Service selector 使用公共标签 (如 apps: xiuxian 使用版本标签 (如 version: v1/v2
流量分配方式 按Pod数量比例自动分配 Service只指向一套环境,100%流量
新旧版本关系 新旧版本共存于同一个Service 新旧版本各自独立,Service只选其一
资源消耗 渐进式,峰值约2倍 始终2倍资源
切换方式 调整副本数(kubectl scale 修改selector标签(kubectl apply

4.2 适用场景决策

复制代码
你的发布需求是什么?
│
├── 需要精确控制流量比例(如先放5%试试)
│   └── ✅ 选择灰度发布
│       (通过副本数比例控制流量分配)
│
├── 需要瞬间完成切换,不能有过渡期
│   └── ✅ 选择蓝绿部署
│       (修改selector即可,切换即时生效)
│
├── 集群资源紧张,不能双倍部署
│   └── ✅ 选择灰度发布
│       (总副本数保持不变,逐步替换)
│
├── 发布风险极高,需要随时秒级回滚
│   └── ✅ 选择蓝绿部署
│       (新旧环境都在运行,回滚就是改回selector)
│
└── 常规迭代,风险可控
    └── ✅ 选择灰度发布(更省资源,更常用)

五、生产环境进阶实践

5.1 结合 ReadinessProbe 确保安全发布

无论是灰度还是蓝绿,都应该为新版本Pod配置就绪探针,确保只有真正就绪的Pod才会被Service纳入后端:

yaml 复制代码
spec:
  containers:
  - name: c1
    image: registry.cn-hangzhou.aliyuncs.com/acs/nginx:1.21
    readinessProbe:
      httpGet:
        path: /
        port: 80
      initialDelaySeconds: 5
      periodSeconds: 3
      failureThreshold: 3

为什么这很重要? 如果新版本Pod启动后虽然处于Running状态,但应用内部尚未完成初始化(比如加载缓存、连接数据库等),没有ReadinessProbe的话Service会立即将流量发给它,导致大量请求失败。

5.2 使用 kubectl rollout 管理发布版本

Kubernetes 的 Deployment 控制器本身就内置了发布管理能力:

bash 复制代码
# 查看发布历史
kubectl rollout history deployment deploy-xiuxian-new

# 查看某个版本的详细信息
kubectl rollout history deployment deploy-xiuxian-new --revision=2

# 回滚到上一版本
kubectl rollout undo deployment deploy-xiuxian-new

# 回滚到指定版本
kubectl rollout undo deployment deploy-xiuxian-new --to-revision=1

# 查看发布状态
kubectl rollout status deployment deploy-xiuxian-new

5.3 灰度发布的比例控制优化

在基础灰度方案中,流量比例受限于副本总数(如3个副本只能实现0%/33%/67%/100%的比例)。在生产环境中,可以结合以下方式实现更精细的控制:

方案一:增加副本总数

将总副本数从3增加到10,就可以实现10%为步进的精细化灰度:

bash 复制代码
# 10%灰度:v1=9, v2=1
kubectl scale deployment deploy-old --replicas=9
kubectl scale deployment deploy-new --replicas=1

# 30%灰度:v1=7, v2=3
kubectl scale deployment deploy-old --replicas=7
kubectl scale deployment deploy-new --replicas=3

# 50%灰度:v1=5, v2=5
kubectl scale deployment deploy-old --replicas=5
kubectl scale deployment deploy-new --replicas=5

方案二:使用 Ingress 控制器实现权重路由

更高级的做法是借助 Nginx Ingress、Traefik 等网关,通过注解实现基于权重的流量分配:

yaml 复制代码
# Nginx Ingress Canary 方式(需安装 nginx-ingress-controller)
apiVersion: networking.k8s.io/v1
kind: Ingress
metadata:
  name: xiuxian-canary
  annotations:
    nginx.ingress.kubernetes.io/canary: "true"
    nginx.ingress.kubernetes.io/canary-weight: "30"   # 30%流量到新版本
spec:
  rules:
  - http:
      paths:
      - path: /
        pathType: Prefix
        backend:
          service:
            name: svc-xiuxian-new
            port:
              number: 80

5.4 蓝绿部署的资源优化

蓝绿部署最大的痛点是资源占用翻倍。在生产环境中可以采用以下策略优化:

  1. 降配空跑环境:将空跑环境的副本数降低到最小可用数(如1个),而非与线上保持一致
  2. 使用 HorizontalPodAutoscaler:让非活跃环境自动缩容到最低副本数
  3. 结合 PodDisruptionBudget:确保切换过程中始终有足够的Pod可用
bash 复制代码
# 蓝绿切换后,将旧环境缩到1个副本备用
kubectl scale deployment deploy-xiuxian-blue --replicas=1

# 观察24小时无问题后,彻底删除
kubectl delete deployment deploy-xiuxian-blue

5.5 自动化发布流水线

将发布策略集成到CI/CD流水线中,可以实现自动化的灰度或蓝绿发布:

groovy 复制代码
// Jenkinsfile - 灰度发布示例
pipeline {
    agent any
    parameters {
        string(name: 'IMAGE_TAG', defaultValue: 'v2', description: '镜像版本')
    }
    stages {
        stage('灰度部署 - 10%') {
            steps {
                sh 'kubectl scale deployment deploy-old --replicas=9'
                sh 'kubectl scale deployment deploy-new --replicas=1'
                sh 'sleep 60'  // 观察60秒
            }
        }
        stage('灰度部署 - 50%') {
            steps {
                sh 'kubectl scale deployment deploy-old --replicas=5'
                sh 'kubectl scale deployment deploy-new --replicas=5'
                sh 'sleep 120' // 观察120秒
            }
        }
        stage('全量发布') {
            steps {
                sh 'kubectl scale deployment deploy-new --replicas=10'
                sh 'kubectl scale deployment deploy-old --replicas=0'
            }
        }
    }
}

六、发布策略速查表

操作场景 灰度发布命令 蓝绿部署命令
部署新版本 kubectl apply -f deploy-v2.yaml kubectl apply -f deploy-v2.yaml
开始灰度/发布 kubectl scale deploy-new --replicas=1 kubectl apply -f svc-v2.yaml
扩大新版本比例 kubectl scale deploy-new --replicas=N N/A(蓝绿是瞬间切换)
回滚 kubectl scale deploy-new --replicas=0 && kubectl scale deploy-old --replicas=3 修改 svc selector: version: v1kubectl apply
查看流量分布 kubectl get pods --show-labels kubectl get svc -o wide
清理旧版本 kubectl delete deployment deploy-old kubectl delete deployment deploy-blue

七、总结

本文通过完整的实战操作,深入讲解了Kubernetes中两种最主流的发布策略:

  1. 灰度发布:通过共享标签 + 逐步调整副本数实现渐进式发布,资源利用率高,是最常用的发布策略。核心是 Service selector 使用公共标签,让K8S自动按Pod数量比例分配流量。

  2. 蓝绿部署:通过版本标签 + 切换 Service selector 实现瞬间切换,适合高风险发布场景。核心是两套完整环境同时运行,切换只是改一个标签值。

实践建议:在实际工作中,推荐以灰度发布为主、蓝绿部署为辅的组合策略。日常迭代使用灰度发布节省资源,重大版本升级时使用蓝绿部署确保安全。同时务必配合 ReadinessProbe 和健康检查机制,让发布更加安全可控。


环境信息

  • Kubernetes: v1.23.17
  • 部署方式: kubeadm
  • 容器运行时: Docker
  • CNI: Flannel
相关推荐
承渊政道1 小时前
极空间NAS部署Photopea:私有在线修图工作站,手机平板随时编辑
安全·docker·容器·ip·访问者模式·photoshop·持续部署
南境十里·墨染春水1 小时前
linux学习进展 libevent
linux·运维·学习
kanyun1231 小时前
在Docker容器中运行Docker:Docker-in-Docker(DinD)全面指南
运维·docker·容器
Agent产品评测局1 小时前
国产vs海外AI Agent方案,制造业场景适配性横评:2026年企业级自动化选型全景观察
运维·人工智能·ai·chatgpt·自动化
落日流年1 小时前
欧拉操作系统部署OceanBase集群
运维·oceanbase
开开心心就好1 小时前
直接减少蓝光辐射的专业护眼工具
linux·运维·服务器·智能手机·excel·java-rabbitmq·sdkman
唔661 小时前
Android在局域网中搭建 MQTT服务器 协议V3.1.1
android·运维·服务器
Shadow(⊙o⊙)1 小时前
进程分析—从操作系统到Linux内核深入
linux·运维·服务器·开发语言·网络·c++·后端
Championship.23.241 小时前
AI驱动的DevOps革命:智能运维系统实战指南
运维·人工智能·devops