这是我参与8月更文挑战的第15天,活动详情查看:8月更文挑战
简介
灰度发布往往先只升级部分服务,让一部分用户继续用老版本,一部分用户用新版本,经常一段时间观察,如果新版本没有问题,那么再逐步扩大升级范围,让所有用户用上新版本
特点
- 保证整休系统稳定性,影响范围可控
- 新功能逐步评估,出现问题,相对用户体验少
- 用户无感知,平滑过渡
规则
按照一定的规则将部分流量接入新的版本,当新版本运行一段时间检测没有问题后,继续让新版本接入流量,直到全量新版本
要求
准备一个kubernetes集群,以及在集群中安装nginx-ingress对象 ,如没有安装,请按照博主文章: juejin.cn/post/697757…
实操
准备2个Deployment应用,一个为v1,一个为v2,同时为它们创建service文件和ingress文件
v1相关配置如下
一份Deployment配置和一份Ingress配置,中间用---分隔
apiVersion: v1
kind: Service
metadata:
name: my-app-v1
labels:
app: my-app
spec:
ports:
- name: http
port: 80
targetPort: 80
selector:
app: my-app
version: v1.0.0
---
apiVersion: apps/v1
kind: Deployment
metadata:
name: my-app-v1
labels:
app: my-app
spec:
replicas: 1
selector:
matchLabels:
app: my-app
version: v1.0.0
template:
metadata:
labels:
app: my-app
version: v1.0.0
spec:
containers:
- name: my-app
image: nginx
ports:
- containerPort: 80
env:
- name: VERSION
value: v1.0.0
Ingress配置,其中v1.libaigo.com需要自行做域名解析或做hosts绑定,这是必须的,因为Ingress是以域名的方式进行访问
apiVersion: extensions/v1beta1
kind: Ingress
metadata:
name: my-app
labels:
app: my-app
spec:
rules:
- host: v1.libaigo.com
http:
paths:
- backend:
serviceName: my-app-v1
servicePort: 80
path: /
v2相关配置如下
v2的Deployment和Service其中除了name和labels需要改成v2之外,其它都是一样的,使用的同一个镜像容器,运行在相同的namespace下,都是default
apiVersion: v1
kind: Service
metadata:
name: my-app-v2
labels:
app: my-app
spec:
ports:
- name: http
port: 80
targetPort: 80
selector:
app: my-app
version: v2.0.0
---
apiVersion: apps/v1
kind: Deployment
metadata:
name: my-app-v2
labels:
app: my-app
spec:
replicas: 1
selector:
matchLabels:
app: my-app
version: v2.0.0
template:
metadata:
labels:
app: my-app
version: v2.0.0
spec:
containers:
- name: my-app
image: nginx
ports:
- containerPort: 80
env:
- name: VERSION
value: v2.0.0
Ingress的配置大部分和v1相同,但是加了2个配置项
- canary 是否开启灰度
- canary-weight 灰度的权重值
更多配置项请查看nginx-ingress官网: kubernetes.github.io/ingress-ngi…
apiVersion: extensions/v1beta1
kind: Ingress
metadata:
name: my-app-canary
labels:
app: my-app
annotations:
nginx.ingress.kubernetes.io/canary: "true"
nginx.ingress.kubernetes.io/canary-weight: "10"
spec:
rules:
- host: v1.libaigo.com
http:
paths:
- backend:
serviceName: my-app-v2
servicePort: 80
path: /
测试
将上述配置文件apply 之后,接下来测试一下结果
#每1秒使用curl命令请求一次v1.libaigo.com域名,结束请按Ctrl+c
while sleep 1;do curl v1.libaigo.com; done
因为我们的权重设置的是10,也就是说10次有一次会请求到v2的版本上,可以看下图,结果在预期之,然后可以调整v2的Ingress配置,逐步提高灰度权重值,直接100为止
到此已经完成了基于nginx-ingress的灰度发布流程
请求头灰度
当然还有一种场景,就是新版本发布之后,每次访问都是新版本,而不必跑十来次才请求到一次。。
这种场景nginx-ingress也提供了配置项,为请求头设置一对k/v,在请求时带上既可
nginx.ingress.kubernetes.io/canary: "true"
nginx.ingress.kubernetes.io/canary-by-header: "x-app-canary"
nginx.ingress.kubernetes.io/canary-by-header-value: "true"
用以上配置,然后在访问时指定请求头,每次请求都会访问新的版本
curl v1.libaigo.com -H "x-app-canary: true"
总结
kubernetes中的灰度发布,本次使用了nginx-ingress自带的能力和配置就实现了 按流量逐步更新的功能。如果没有ingress,那么如何实现了,其实使用Service+labeles也是可以实现的