k8s series 19: 灰度发布

1,151 阅读3分钟

这是我参与8月更文挑战的第15天,活动详情查看:8月更文挑战

简介

灰度发布往往先只升级部分服务,让一部分用户继续用老版本,一部分用户用新版本,经常一段时间观察,如果新版本没有问题,那么再逐步扩大升级范围,让所有用户用上新版本

image.png

特点

  • 保证整休系统稳定性,影响范围可控
  • 新功能逐步评估,出现问题,相对用户体验少
  • 用户无感知,平滑过渡

规则

按照一定的规则将部分流量接入新的版本,当新版本运行一段时间检测没有问题后,继续让新版本接入流量,直到全量新版本

要求

准备一个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为止

image.png

到此已经完成了基于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也是可以实现的