KubeSphere灰度发布实战(上)
  T5Bv8I9TIFQW 2023年11月13日 17 0

前言

在如今的业务环境中,越来越多的应用采用了微服务架构,微服务的特性就是功能迭代版本较快,管理更加复杂,发布更加频繁。那么在每次有版本更新迭代的需求,如果直接将新版本发布给用户,那么在上线期间遭遇线上事故(或者突发Bug),那么这种情况对于用户来说是影响极大,解决问题周期较长,甚至不得不回滚至前一个版本来应对该问题,那么即使解决了问题那么也严重影响了用户体验。为了保证整体系统的稳定,将风险点位降到最低,我们可以采用灰度发布或者蓝绿发布等不同的发布方式。在技术架构体系中,灰度发布的方式有很多,那么在Kubernetes架构中,它的灰度是如何做的呢?接下来将会结合一些实际案例来说明。

金丝雀发布概念剖析

金丝雀发布,又称灰度发布,是指通过让小部分用户流量引入新版本进行测试,如果一切顺利用户反馈无误之后,则可以逐渐增加流量百分比,逐步替换旧版本。如果在替换过程中出现任何问题,则可以终止并快速的回滚旧版本。我们可以针对不同的属性进行灰度发布,我们可以基于下面三种方式进行分,下面将结合实际案例说明

创建一个实例版本v1

#vim demov1.yaml
apiVersion: apps/v1
kind: Deployment
metadata:
  namespace: demo-project
  name: demov1
  labels:
    app: demov1
spec:
  replicas: 1
  selector:
    matchLabels:
      app: demov1
  template:
    metadata:
      labels:
        app: demov1
    spec:
      containers:
      - name: demov1
        imagePullPolicy: Always
        image: registry.cn-beijing.aliyuncs.com/devops-op/nginx-damo:v1
        ports:
        - containerPort: 80
---
apiVersion: v1
kind: Service
metadata:
  namespace: demo-project
  name: demo-svc
spec:
  type: ClusterIP
  selector:
    app: demov1
  ports:
    - port: 80
      targetPort: 80
#kubectl apply -f demov1.yml

部署最新实例版本v2

#vim demov2.yaml
apiVersion: apps/v1
kind: Deployment
metadata:
  namespace: demo-project
  name: demov2
  labels:
    app: demov2
spec:
  replicas: 1
  selector:
    matchLabels:
      app: demov2
  template:
    metadata:
      labels:
        app: demov2
    spec:
      containers:
      - name: demov2
        imagePullPolicy: Always
        image: registry.cn-beijing.aliyuncs.com/devops-op/nginx-damo:v2
        ports:
        - containerPort: 80
---
apiVersion: v1
kind: Service
metadata:
  name: demo-v2-svc
  namespace: demo-project
spec:
  type: ClusterIP
  selector:
    app: demov2
  ports:
    - port: 80
      targetPort: 80
#kubectl apply -f demov2.yml

KubeSphere灰度发布实战(上)_Ingress灰度发布

KubeSphere灰度发布实战(上)_Kubernetes_02

创建常规的ingress实例

在这里我们先创建一个demo v1版本的ingress

#vim demo-ingress.yaml
apiVersion: networking.k8s.io/v1
kind: Ingress
metadata:
  namespace: demo-project
  name: demo
spec:
  rules:
  - host: demo.kubesphere.com
    http:
      paths:
      - path: /
        pathType: Prefix
        backend:
          service:
            name: demo-svc 
            port:
              number: 80
  ingressClassName: nginx

KubeSphere灰度发布实战(上)_Kubernetes_03

模拟真实用户请求,

访问一下测试域名,出现以下内容表示v1版本部署成功!

KubeSphere灰度发布实战(上)_Kubernetes_04

基于服务权重的流量切分

应用场景

假设上述案例v1版本是线上一套demo应用,此时研发已修复了一些问题,需要上线新版本demo应用,但是又不想直接替换成新版本demo应用,而是希望先将小部分用户流量,切换到新版本,待运行一段时间稳定之后,就可将所有流量从老版本demo应用切换到新版本demo应用中。随后再平滑的将老版本demo下线;

权重策略应用

KubeSphere灰度发布实战(上)_Ingress灰度发布_05

KubeSphere灰度发布实战(上)_Ingress灰度发布_06

#vim demo-new.yaml
apiVersion: networking.k8s.io/v1
kind: Ingress
metadata:
  name: demo-v2-new
  annotations:
    #开启Canary策略,启用了Canary部署模式
    nginx.ingress.kubernetes.io/canary: "true"
    #请求头来进行Canary流量的路由。这意味着使用该请求头的值来确定请求应该转发到哪个版本。
		nginx.ingress.kubernetes.io/canary-by-header: "X-Forwarded-For"
    #将20%的流量转发到新版本(v2应用),即将部分流量导流到Canary版本,而将剩余的80%流量保持在原版本。
    nginx.ingress.kubernetes.io/canary-weight: "20"
    
spec:
  rules:
  - host: demo.kubesre.com
    http:
      paths:
      - path: /
        pathType: Prefix
        backend:
          service:
            name: demo-new-svc #指定v2版本svc
            port:
              number: 80
  ingressClassName: nginx

验证测试

编写curl 循环请求脚本

#vim test.sh
#!/bin/bash
while true
do
    curl http://demo.kubesphere.com;echo
    sleep 2
done

下图所示,我们可以看到只有小部分流量(20%)流量请求由v2响应,大部分流量还是通过v1版本响应

KubeSphere灰度发布实战(上)_Kubernetes_07

随后我们将流量权重比改成1:1,也就是将50%的流量请求转入新版本

nginx.ingress.kubernetes.io/canary-weight: "50"

可以看到,已有50%的流量由v2版本响应,50%流量由老版本demo应用响应,符合服务器流量权重的标准

KubeSphere灰度发布实战(上)_Kubernetes_08

基于客户端来源IP流量切分

应用场景

仍然以上述原始实例为案例,假设线上已运行一套现有的demo应用,此时开发了新功能,需要上线新版本demo应用,但是呢又不想直接替换成新版本demo应用,而是希望公司内部人员能访问新版本demo应用,进行测试验证新版本,非公司人员也就是对外的用户请求仍然访问老版本应用,等公司内部人员测试验证通过并稳定后,可将所有流量从老版本demo应用切换到新版本中,再平滑的将老版本应用后下线

KubeSphere灰度发布实战(上)_Kubernetes_09

源IP策略应用

apiVersion: networking.k8s.io/v1
kind: Ingress
metadata:
  namespace: demo-project
  name: demo-new-header
  annotations:
    nginx.ingress.kubernetes.io/canary: "true"
    nginx.ingress.kubernetes.io/canary-by-header: "X-Forwarded-For"
    # 假设客户端来源IP为10.10.203.160
    nginx.ingress.kubernetes.io/canary-by-header-value: "10.10.203.160"
    
spec:
  rules:
  - host: demo.kubesphere.com
    http:
      paths:
      - path: /
        pathType: Prefix
        backend:
          service:
            name: demo-new-sv
            port:
              number: 80
  ingressClassName: nginx

验证测试

通过请求头模拟来源IP地址,比如这里我这是的是10.10.203.160这个IP请求由新版本v2响应,其它均由旧应用响应1

KubeSphere灰度发布实战(上)_Kubernetes_10

基于客户端请求头流量切分

应用场景

仍然以上述实例为准,线上已运行一套对外提供的demon应用,此时开发了一些新功能,需要上线新demo版本应用,但是呢又不想直接替换新版本,研发而是希望将请求头包含user-kubesphere的客户端请求转发到新版本demo应用中,进行验证测试新版本demo应用,等测试通过并稳定后,我们再将所有流量从老版本demo应用切换到新版本demo应用中,再平滑的将老版本demo应用下线。通过基于请求头的值来控制流量路由,从而逐步引入新版本并观察其性能和稳定性

KubeSphere灰度发布实战(上)_Ingress灰度发布_11

请求头策略应用

apiVersion: networking.k8s.io/v1
kind: Ingress
metadata:
  namespace: demo-project
  name: demo-new-header
  annotations:
    nginx.ingress.kubernetes.io/canary: "true"
    #使用请求头中的“user”字段来进行Canary 流量留有,使用该请求的值来确定请求应该转发到哪个版本
    nginx.ingress.kubernetes.io/canary-by-header: "user"
    #当请求头中"user"字段值等于"kubesphere"时,才会将请求转发到新版本的服务
    nginx.ingress.kubernetes.io/canary-by-header-value: "kubesphere"
    
spec:
  rules:
  - host: demo.kubesphere.com
    http:
      paths:
      - path: /
        pathType: Prefix
        backend:
          service:
            name: demo-new-sv
            port:
              number: 80
  ingressClassName: nginx

验证测试

[root@k8s-master01 ~]# curl -H "user:kubesphere" http://demo.kubesphere.com
宇轩辞白v2博客https://blog.51cto.com/u_11880730
[root@k8s-master01 ~]# curl -H "user:kubesphere" http://demo.kubesphere.com
宇轩辞白v2博客https://blog.51cto.com/u_11880730
[root@k8s-master01 ~]# curl -H "user:kubesphere" http://demo.kubesphere.com
宇轩辞白v2博客https://blog.51cto.com/u_11880730
[root@k8s-master01 ~]# curl -H "user:kubesphere" http://demo.kubesphere.com
宇轩辞白v2博客https://blog.51cto.com/u_11880730
[root@k8s-master01 ~]# curl http://demo.kubesphere.com
宇轩辞白V1
[root@k8s-master01 ~]# curl http://demo.kubesphere.com
宇轩辞白V1
[root@k8s-master01 ~]# curl http://demo.kubesphere.com
宇轩辞白V1
[root@k8s-master01 ~]# curl http://demo.kubesphere.com
宇轩辞白V1

KubeSphere灰度发布实战(上)_Ingress灰度发布_12

关于Nginx-ingress知识点

Nginx-ingress支持通过配置注视(Annotations)来实现不同场景下的发布和测试,可以满足灰度发布、蓝绿发布、A/B测试等业务场景,具体实现过程如下:

为服务创建两个Ingress,一个常规Ingress,另外一个为带有nginx.ingress.kubernetes.io/canary: "true"注解的Ingress,称为Canary Ingress;为Canary Ingress配置流量切分策略Annotation,两个ingress互相配合,即可实现多种应用场景的发布和测试,Nginx Ingress的Annotation支持以下几种规则:

  • nginx.ingress.kubernetes.io/canary-by-header基于Header的流量切分,适用于灰度发布。如果请求头中包含指定的header名称,并且值为“always”,就将该请求转发给Canary Ingress定义的对应后端服务。如果值为“never”则不转发,可用于回滚到旧版本。如果为其他值则忽略该annotation,并通过优先级将请求流量分配到其他规则。
  • nginx.ingress.kubernetes.io/canary-by-header-value必须与canary-by-header一起使用,可自定义请求头的取值,包含但不限于“always”或“never”。当请求头的值命中指定的自定义值时,请求将会转发给Canary Ingress定义的对应后端服务,如果是其他值则忽略该annotation,并通过优先级将请求流量分配到其他规则。
  • nginx.ingress.kubernetes.io/canary-by-header-pattern与canary-by-header-value类似,唯一区别是该annotation用正则表达式匹配请求头的值,而不是某一个固定值。如果该annotation与canary-by-header-value同时存在,该annotation将被忽略。
  • nginx.ingress.kubernetes.io/canary-by-cookie基于Cookie的流量切分,适用于灰度发布。与canary-by-header类似,该annotation用于cookie,仅支持“always”和“never”,无法自定义取值。
  • nginx.ingress.kubernetes.io/canary-weight基于服务权重的流量切分,适用于蓝绿部署。表示Canary Ingress所分配流量的百分比,取值范围[0-100]。例如,设置为100,表示所有流量都将转发给Canary Ingress对应的后端服务

END!

上述就是我们分享基于Ingress Canary策略来实现的灰度发布案例,下一篇文章将会带大家学习如何在kubesphere平台以可视化的方式实现我们的灰度发布、蓝绿发布案例

【版权声明】本文内容来自摩杜云社区用户原创、第三方投稿、转载,内容版权归原作者所有。本网站的目的在于传递更多信息,不拥有版权,亦不承担相应法律责任。如果您发现本社区中有涉嫌抄袭的内容,欢迎发送邮件进行举报,并提供相关证据,一经查实,本社区将立刻删除涉嫌侵权内容,举报邮箱: cloudbbs@moduyun.com

  1. 分享:
最后一次编辑于 2023年11月13日 0

暂无评论

推荐阅读
  O704k6GYsxMM   2023年11月13日   19   0   0 rkeDockerkubernetes
T5Bv8I9TIFQW