You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.

224 lines
6.9 KiB

3 years ago
# 什么是灰度发布
灰度发布又名金丝雀发布,
> 是指在黑与白之间,能够平滑过渡的一种发布方式。 在其上可以进行A/B testing,即让一部分用户继续用产品特性A,一部分用户开始用产品特性B,如果用户对B没有什么反对意见,那么逐步扩大范围,把所有用户都迁移到B上面来。–维基百科
假定线上版本为A, 需要发布的版本为B,通常是新版本。
灰度发布可以让一定百分比的用户(比如10%)优先体验版本B,其余用户仍然使用版本A,并且慢慢扩大百分比,最终将所用用户迁移到版本B。
![](https://cdn.jsdelivr.net/gh/vinloong/imgchr@latest/notes/img/202201191023493.png)
# 为什么需要灰度发布
随着微服务架构的普及,服务数量激增,版本更新频繁,如果缺少灰度的能力,容易对现有的生产运行业务造成影响,并且新上线的系统和功能也需要灰度的能力来验证可行性和效果,简而言之,无论是对于系统运行稳定安全还是对于验证业务效果,灰度发布/验证的能力都是现代软件架构所必须的。
灰度发布有一个隐藏的前提条件,线上资源远大于生产团队的规模;
以至于生产团队没有足够的资源来应付使用新版本后带来的问题,包括用户不习惯和数据量所带来的不适应和线上bug等等。
而灰度发布可以通过控制发布面积,让使用新版本的用户控制在生产团队可以应付的范围内;将可能出现问题的用户圈定在“部分”用户,这个部分的范围由生产团队评估得出。
我们通过灰度发布,将一部分经过筛选后的用户纳入测试范围,由生产团队和用户共同完成对新版本的验收;主要的目的是检验了用户对于新版本的接受度,规避了因为产品决策冒失、冒进所带来的风险。
# 问题
## 用户标识
用于区分用户,辅助数据统计,并且保证灰度发布过程中用户体验的连贯性(不要在新老版本中跳来跳去)。
## 目标用户的选取策略
如何选取让哪些用户先行体验新版本,是让用户自己选择还是强制升级等。
## 数据
如何能够获取新版本的指标数据
## 回滚策略
新版本表现不佳,如何快速回滚到老版本。如果是app 回滚可能代价比较大。
# 灰度策略
## 按流量比例
![](https://cdn.jsdelivr.net/gh/vinloong/imgchr@latest/notes/img/202201191021433.png)
基于流量就是设置流量权重,实现上最简单,但是流量不稳定,会使用户使用有割裂感。
## 按请求内容
![[../Pasted image 20210604153710.png]]
这个分为两种:基于 cookie 和 请求 Header;
这种相对于前面一种就会相对复杂点,需要请求端设置 Header或cookie。这种用户体验会好很多,能够保证用户体验的连贯性。
> 注意:金丝雀规则具有以下优先级:
> `canary-by-header` - > `canary-by-cookie` - > `canary-weight`
# 灰度发布实践
我们商用环境k8s 管理是使用的 `KubeSphere` ,所以下面的实践都是利用 `KubeSphere` 来实现
简单自定义一个接口服务:
```js
const main = async function(ctx) {
ctx.body ="this is canary test";;
};
const about = ctx => {
ctx.body = "this is version 2";
// ctx.body = "this is version 1";
};
```
分别构建了两个镜像:
```
# Production 版本
repository.anxinyun.cn/base-images/demo:0.1
# Canary 版本
repository.anxinyun.cn/base-images/demo:0.3
```
## 基于 `ingress-nginx`
### 1. 我们先部署一个 `Production` 版本的应用
```yaml
apiVersion: apps/v1
kind: Deployment
metadata:
name: gated-demo
namespace: fs-gtest
spec:
replicas: 1
selector:
matchLabels:
app: gated-demo
template:
metadata:
labels:
app: gated-demo
spec:
containers:
- name: gated-demo
image: repository.anxinyun.cn/base-images/demo:0.1
ports:
- containerPort: 5000
name: http-port
---
apiVersion: v1
kind: Service
metadata:
name: gated-demo
namespace: fs-gtest
labels:
app: gated-demo
spec:
ports:
- port: 15001
targetPort: 5000
protocol: TCP
name: http-port
selector:
app: gated-demo
```
```shell
$ kubectl appy -f production.yaml
deployment.apps/production created
service/production created
```
### 2. 创建 `Production` 版本的应用路由 (Ingress)
```yaml
kind: Ingress
apiVersion: extensions/v1beta1
metadata:
name: gated-demo
namespace: fs-gtest
annotations:
kubernetes.io/ingress.class: nginx
kubesphere.io/creator: admin
spec:
rules:
- host: gated-demo.fs-gtest.10.8.30.157.nip.io
http:
paths:
- path: /
pathType: ImplementationSpecific
backend:
serviceName: gated-demo
servicePort: 15001
```
### 3. 访问`Production` 接口
![](https://cdn.jsdelivr.net/gh/vinloong/imgchr@latest/notes/img/202201191024380.png)
### 4. 下面部署 `Canary` 版本
yaml 文件 参考上面的版本,在 `gated-demo` 加上 `-canary`
### 5. 设置 Ingress-Nginx Annotation 规则
> 要开启灰度发布机制,需设置 `nginx.ingress.kubernetes.io/canary: "true"` 启用 Canary
#### 基于权重
```yaml
kind: Ingress
apiVersion: extensions/v1beta1
metadata:
name: gated-demo-canary
namespace: fs-gtest
annotations:
kubernetes.io/ingress.class: nginx
kubesphere.io/creator: admin
nginx.ingress.kubernetes.io/canary: 'true'
nginx.ingress.kubernetes.io/canary-weight: "30"
spec:
rules:
- host: gated-demo.fs-gtest.10.8.30.157.nip.io
http:
paths:
- path: /
pathType: ImplementationSpecific
backend:
serviceName: gated-demo-canary
servicePort: 15002
```
> 上面 Ingress 示例的 Canary 版本使用了**基于权重进行流量切分**的 annotation 规则,将分配 **30%** 的流量请求发送至 Canary 版本
#### Request Header
```yaml
kind: Ingress
apiVersion: extensions/v1beta1
metadata:
name: gated-demo-canary
namespace: fs-gtest
annotations:
kubernetes.io/ingress.class: nginx
kubesphere.io/creator: admin
nginx.ingress.kubernetes.io/canary: 'true'
nginx.ingress.kubernetes.io/canary-by-header: version
nginx.ingress.kubernetes.io/canary-by-header-value: '2'
spec:
rules:
- host: gated-demo.fs-gtest.10.8.30.157.nip.io
http:
paths:
- path: /
pathType: ImplementationSpecific
backend:
serviceName: gated-demo-canary
servicePort: 15002
```
![](https://cdn.jsdelivr.net/gh/vinloong/imgchr@latest/notes/img/202201191025017.png)
当 header 'version' 设置 为 '2' 时,所有请求被转到 Canary 版本
# 总结
上面是简单的灰度测试,实际商用还是考虑灰度策略问题如何与用户结合起来控制,可以指定哪些用户参与灰度测试。