一、何为金丝雀(灰度)发布
金丝雀发布(Canary Release)是一种软件部署策略,它允许在生产环境中以可控的方式逐步引入新的软件版本,从而降低新版本发布带来的风险。
1.1、起源与概念
- 起源:该术语源于17世纪英国煤矿工人的做法,他们会携带金丝雀下井。由于金丝雀对瓦斯等有毒气体非常敏感,当井下有毒气体浓度升高时,金丝雀会先出现不适甚至死亡,从而为矿工提供危险预警。在软件发布中,金丝雀发布的原理类似,先向一小部分用户发布新版本,以此作为 “金丝雀” 来提前发现潜在问题。
- 概念:在金丝雀发布过程中,新版本软件首先会在一小部分用户或服务器上进行部署和测试。通过监控这部分用户的反馈和相关指标(如性能、错误率等),评估新版本的稳定性和兼容性。如果一切正常,再逐步扩大新版本的使用范围,直到完全替换旧版本;若出现问题,则可以及时回滚,避免影响大部分用户。
- 图示:如下图所示,某服务当前版本为v1,现在新版本v2要上线。为确保流量在服务升级过程中平稳无损,采用金丝雀发布方案,逐步将流量从老版本迁移至新版本。
1.2、实现步骤
- 环境准备:确保生产环境稳定运行,同时准备好新版本的软件。可以使用容器编排工具(如 Kubernetes)来管理不同版本的部署。
- 选择金丝雀组:确定一小部分用户或服务器作为金丝雀组。可以根据用户特征(如地理位置、用户类型等)或服务器标识进行划分。
- 部署新版本:将新版本软件部署到金丝雀组中。在这个阶段,旧版本仍然为大部分用户提供服务。
- 监控与评估:密切监控金丝雀组的各项指标,如响应时间、吞吐量、错误率等。收集用户反馈,及时发现新版本可能存在的问题。
- 决策与扩展:根据监控结果和评估数据,决定是否继续扩大新版本的使用范围。如果新版本表现良好,则逐步增加使用新版本的用户或服务器数量;如果出现严重问题,则立即回滚到旧版本。
1.3、优点
- 降低风险:通过先在小范围内测试新版本,可以提前发现并解决潜在的问题,避免对大量用户造成影响。
- 快速反馈:能够快速收集到真实用户对新版本的反馈,有助于及时调整和优化软件。
- 灵活控制:可以根据实际情况灵活调整新版本的推广速度和范围,确保发布过程可控。
1.4、缺点
- 管理复杂:需要对不同版本的软件进行管理和监控,增加了运维的复杂性。有时候应用,它不仅仅只有镜像,还包括它所依赖的中间件环境,倘若新旧版本依赖的环境配置不同,采用金丝雀发布,无疑增加了管理的复杂度。
- 资源消耗:在发布过程中,需要同时维护旧版本和新版本的环境,会消耗更多的资源。
二、镜像准备
假设有如下三个节点的 K8S 集群:
k8s31master 是控制节点
k8s31node1、k8s31node2 是工作节点
容器运行时是 containerd
使用 springboot 打包两个镜像 hellok8s-1.0.jar.gz 和 hellok8s-2.0.jar.gz。
hellok8s:1.0
@RestController
public class HelloController {@GetMapping("/sayHello")@ResponseBodypublic String sayHello() {# 蓝return "Hello,I am Blue";}
}
hellok8s:2.0
@RestController
public class HelloController {@GetMapping("/sayHello")@ResponseBodypublic String sayHello() {# 绿return "Hello,I am Green";}
}
它们的区别仅在输出的问候信息不同,一个 Blue、一个 Green.
- 导入镜像
# node1 执行
[root@k8s31node1 ~]# ctr -n=k8s.io images import hellok8s-1.0.jar.gz
[root@k8s31node1 ~]# ctr -n=k8s.io images import hellok8s-2.0.jar.gz
# node2 执行
[root@k8s31node2 ~]# ctr -n=k8s.io images import hellok8s-1.0.jar.gz
[root@k8s31node2 ~]# ctr -n=k8s.io images import hellok8s-2.0.jar.gz
三、Deployment 实现
- deploy-blue.yaml
apiVersion: apps/v1
kind: Deployment
metadata:name: deploy-blue
spec:replicas: 3selector:matchLabels:app: hellok8sversion: "1.0"template:metadata:labels:app: hellok8sversion: "1.0"spec:containers:- name: hellok8simage: hellok8s:1.0imagePullPolicy: IfNotPresentports:- containerPort: 8080startupProbe:httpGet:path: /port: 8080initialDelaySeconds: 5periodSeconds: 10readinessProbe:httpGet:path: /port: 8080initialDelaySeconds: 5periodSeconds: 10livenessProbe:httpGet:path: /port: 8080initialDelaySeconds: 5periodSeconds: 10
镜像版本现在是 1.0。
- 运行并查看
kubectl apply -f deploy-blue.yaml
kubectl get pod -owide
- 在另一个终端开启监控
kubectl get pod -owide -w
- 执行更新并暂停
kubectl set image deploy deploy-blue hellok8s=hellok8s:2.0 && kubectl rollout pause deploy deploy-blue
- set image 命令用来给工作负载更新镜像。命令格式为:
kubectl set image deploy deploy-name container-name=image-name:image-tag
- && 表示上一条命令执行成功之后才执行下一条命令
- rollout pause 命令用来暂停滚动更新过程。命令格式为:
kubectl rollout pause deploy deploy-name
- 查看监控
- 一个新的pod会被创建,与此同时所有旧的pod还在运行。
- 一旦新的pod成功运行,服务的一部分请求将被切换到新的pod。这样相当于运行了一个金丝雀版本。金丝雀发布是一种可以将应用程序的出错版本和其影响到的用户的风险化为最小的技术。与其直接向每个用户发布新版本,不如用新版本替换一个或一小部分的pod。通过这种方式,在升级的初期只有少数用户会访问新版本。验证新版本是否正常工作之后,可以将剩余的pod继续升级或者回滚到上一个的版本。
- 查看 部署详情
会发现 paused 被系统设置为 true
kubectl get deploy deploy-blue -ojson
- 执行回滚
倘若这个时候,我们发现版本有问题,想回滚怎么办?
kubectl rollout undo deploy deploy-blue
它会提示你,要先恢复(resume)rollout 过程,然后才能执行回滚命令。
- 恢复 Rollout
kubectl rollout resume deployment/deploy-blue
- 查看监控
可以看到,所有的 pod,都已被更新成新版。
- 执行回滚
现在就可以正常回滚了。
kubectl rollout undo deploy deploy-blue
四、总结
Deployment pause 的金丝雀发布是一种伪金丝雀发布。它有一下几个问题:
- 在滚动升级过程中,想要在⼀个确切的位置暂停滚动升级无法做到。
- 无法实现流量的按比例分配。
- 需要恢复更新才能执行回滚。相当于将有问题的版本全部更新完才能回滚,将影响面扩大化了。
在现代云原生环境中,有许多其他工具和技术可以帮助实现金丝雀发布,
如Kubernetes的服务网格Istio、负载均衡器配置等。这些工具允许细粒度控制流量分配,使得从A/B测试到完整的金丝雀发布变得更为容易实现。