如何在 Kubernetes 中借助Ingress 实现灰度发布和蓝绿发布

前言

部署在 Kubernetes 集群中的应用,在升级发布时可能会存在的问题:

1,由于 Kuberneter 底层 Pod 容器生命周期与网络组件生命周期是异步管理的,在升级时如果没有处理好应用优雅退出的问题,就很容易导致 http 访问请求 5xx

2,原生 Deployment 应用的滚动发布功能是一把梭的全量发布模式,没有灰度和分批控制发布的概念,一旦出现问题,故障影响范围就会迅速扩大

这也是为什么需要灰度发布,蓝绿发布,彩虹发布,金丝雀发布、A/B Test等多样化形式发布的重要原因,核心目标只有一个,就是为了确保服务的稳定性,减少或避免因变更带来的不稳定因素

今天我们主要来聊下,如何在不引入第三方插件的情况下,来实现简单的灰度发布和蓝绿发布功能

通过 Ingress 实现灰度发布和蓝绿发布

在 Kubernetes 里面 Pod 的网络通信都是借助 Service 实现的,Service 的底层是依赖 Iptables 或者 eBPF 加上 dns 技术实现的,具体细节感兴趣可自行探索,Ingress 负责 k8s 集群内外的流量通信,本身属于七层负载的工作范围,所以可以将流量反向代理到四层负载的 Service 中,在七层负载中支持 Http 协议,所以可以实现的功能更加强大

工作原理

Kubernetes 自带的 Ingress Controller 组件的底层是 Nginx ,所以基于七层负载的能力,我们就可以做更多与流量分配相关的功能,目前基于 Nginx 的 Ingress 支持通过 Header,Cookie 和 Weight 三种流量切分的策略,这三种策略,又可以实现以下两种发布场景:

按请求级别的灰度用户流量

通过 header 和 cookie 路由流量进行灰度

按比例级别的灰度用户流量

通过 weight 权重设置

支持的Nginx Annotation介绍
  1. nginx.ingress.kubernetes.io/canary-by-header

基于Header的流量切分。如果请求头中包含指定的 header,并且值为“always”,就将该请求转发给Canary Ingress定义的对应后端服务。如果值为“never”则不转发,可用于回滚到旧版本。如果为其他值则忽略该annotation,并通过优先级将请求流量分配到其他规则。

  1. nginx.ingress.kubernetes.io/canary-by-header-value

必须与canary-by-header一起使用,可自定义请求头的取值,包含但不限于“always”或“never”。当请求头的值命中指定的自定义值时,请求将会转发给Canary Ingress定义的对应后端服务,如果是其他值则忽略该annotation,并通过优先级将请求流量分配到其他规则。

  1. nginx.ingress.kubernetes.io/canary-by-header-pattern

与canary-by-header-value类似,唯一区别是该annotation用正则表达式匹配请求头的值,而不是某一个固定值。如果该annotation与canary-by-header-value同时存在,该annotation将被忽略。

  1. nginx.ingress.kubernetes.io/canary-by-cookie

基于Cookie的流量切分。与canary-by-header类似,该annotation用于cookie,仅支持“always”和“never”,无法自定义取值。

  1. nginx.ingress.kubernetes.io/canary-weight

基于服务权重的流量切分,适用于蓝绿部署。表示Canary Ingress所分配流量的百分比,取值范围[0-100]。例如,设置为100,表示所有流量都将转发给Canary Ingress对应的后端服务。

注解规则会按优先级进行评估,优先级为:canary-by-header -> canary-by-cookie -> canary-weight。

灰度发布

依赖资源:2 个 Ingress 对象,2 个 Service 对象,两个 Deployment 对象

操作流程:为服务创建两个 Ingress,一个为常规 Ingress,另一个为带有 nginx.ingress.kubernetes.io/canary: "true"注解的 Ingress,称为 Canary Ingress,在 Canary Ingress 上配置切分策略。

两个 Deployment 对象,分别对应升级过程中的两个版本 v1,v2

apiVersion: apps/v1
kind: Deployment
metadata:
  name: py-hello-blue
spec:
  selector:
    matchLabels:
      app: hello
      color: blue
  replicas: 1
  template:
    metadata:
      labels:
        app: hello
        color: blue
    spec:
      terminationGracePeriodSeconds: 30
      containers:
      - name: hello
        imagePullPolicy: Always
        image: localhost:5001/py-http:1
        ports:
        - containerPort: 8888
        resources:
          requests:
            memory: "50Mi"
          limits:
            memory: "200Mi"
        lifecycle:
          preStop:
            exec:                                                                      
              command: ["sleep", "5"]
        # command: ["/usr/bin/tini", "--", "bash", "-c"]
        command: ["sh", "-c"]
        args:
        - |
          python app.py
apiVersion: apps/v1
kind: Deployment
metadata:
  name: py-hello-green
spec:
  selector:
    matchLabels:
      app: hello
      color: green
  replicas: 1
  template:
    metadata:
      labels:
        app: hello
        color: green
    spec:
      terminationGracePeriodSeconds: 30
      containers:
      - name: hello
        imagePullPolicy: Always
        image: localhost:5001/py-http:2
        ports:
        - containerPort: 8888
        resources:
          requests:
            memory: "50Mi"
          limits:
            memory: "200Mi"
        lifecycle:
          preStop:
            exec:                                                                      
              command: ["sleep", "5"]
        # command: ["/usr/bin/tini", "--", "bash", "-c"]
        command: ["sh", "-c"]
        args:
        - |
          python app.py

两个 Service 对象,分别对应 v1,v2 的Deployment

apiVersion: v1
metadata:
  name: py-hello-blue-service
kind: Service
spec:
  selector:
    app: hello
    #color: green
    color: blue
  ports:
    - name: web
      port: 8888
      protocol: TCP
      targetPort: 8888
  type: ClusterIP
apiVersion: v1
metadata:
  name: py-hello-green-service
kind: Service
spec:
  selector:
    # app: hello
    color: green
    # color: blue
  ports:
    - name: web
      port: 8888
      protocol: TCP
      targetPort: 8888
  type: ClusterIP

两个 Ingress 对象,进行灰度流量的分配

kind: Ingress
apiVersion: networking.k8s.io/v1
metadata:
  name: py-hello-ingress-normal
spec:
  rules:
    - host: py-hello.test.com
      http:
        paths:
          - path: /
            pathType: Prefix
            backend:
              service: 
                port: 
                  number: 8888
                name: py-hello-blue-service
kind: Ingress
apiVersion: networking.k8s.io/v1
metadata:
  name: py-hello-ingress-canary
  annotations:
    kubernetes.io/ingress.class: nginx
    nginx.ingress.kubernetes.io/canary: "true"                # 启用Canary
    #基于 Header 的灰度
    #nginx.ingress.kubernetes.io/canary-by-header: "Region"
    #nginx.ingress.kubernetes.io/canary-by-header-pattern: "hz|lg"    
    #基于 Cookie 的灰度
    #nginx.ingress.kubernetes.io/canary-by-cookie: "qdl"    # Cookie中包含user_from_bj的请求转发到Canary Ingress
    #基于 weight 的灰度    
    nginx.ingress.kubernetes.io/canary-weight: "20"    # 将20%的流量转发到Canary Ingress

spec:
  rules:
    - host: py-hello.test.com
      http:
        paths:
          - path: /
            pathType: Prefix
            backend:
              service: 
                port: 
                  number: 8888
                name: py-hello-green-service

实现灰度发布,就是把 canary 里面的流量分配策略进行修改即可

蓝绿发布

实现蓝绿发布,就是在灰度发布的基础上把 canary 里面的weight流量分配权重改为 100 即可。

注意:

  • 相同服务的Canary Ingress仅能够定义一个,从而使后端服务最多支持两个版本。
  • 即使流量完全切到了Canary Ingress上,旧版服务仍需存在,否则会出现报错。
总结

通过 ingress 进行灰度发布和蓝绿发布可以实现更加复杂的流量分配策略,但对应的操作也变得复杂了,对于大部分复杂的发布业务也足够用了,这种方案也可以结合发布平台稍做封装,比如一键创建新克隆版本,切换流量配比,设置流量策略等,有了这些基础功能后,再配合发布平台就可以流畅的操作了

 

  • 1
    点赞
  • 2
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
Kubernetes Ingress-Nginx是一个用于管理Kubernetes集群Ingress资源的工具。它支持使用Ingress Annotations来实现不同场景下的灰度发布和测试。其,Nginx Annotations支持基于Cookie的切分流量来实现灰度发布。具体实现方式是通过判断用户请求的Cookie是否存在灰度标识Cookie来确定是否为灰度用户,从而决定是否返回灰度版本的服务。 在配置,可以使用以下Annotations来实现灰度发布: - `nginx.ingress.kubernetes.io/canary`:可选值为true/false,表示是否开启灰度功能。 - `nginx.ingress.kubernetes.io/canary-by-cookie`:灰度发布Cookie的键。当键的值等于"always"时,灰度触发生效;其他值则不会走灰度环境。 例如,如果请求的Cookie包含名为"vip_user"的键,并且值为"always",则会生效灰度配置,访问灰度版本的服务。 要实际执行灰度发布配置,可以使用以下命令: ``` kubectl apply -f ingress-gray.yaml ``` 如果想查看服务并获取Ingress的外部端口,可以使用以下命令: ``` kubectl -n ingress-nginx get service ``` 这将显示Ingress-Nginx控制器的服务信息,包括集群IP、外部IP和端口等。 #### 引用[.reference_title] - *1* [【云原生 | Kubernetes 实战】20、K8s Ingress 实现业务灰度发布](https://blog.csdn.net/weixin_46560589/article/details/128505651)[target="_blank" data-report-click={"spm":"1018.2226.3001.9630","extra":{"utm_source":"vip_chatgpt_common_search_pc_result","utm_medium":"distribute.pc_search_result.none-task-cask-2~all~insert_cask~default-1-null.142^v91^insert_down1,239^v3^insert_chatgpt"}} ] [.reference_item] - *2* *3* [【Kubernetes】第十篇 - 灰度发布的介绍与实现](https://blog.csdn.net/ABAP_Brave/article/details/129220116)[target="_blank" data-report-click={"spm":"1018.2226.3001.9630","extra":{"utm_source":"vip_chatgpt_common_search_pc_result","utm_medium":"distribute.pc_search_result.none-task-cask-2~all~insert_cask~default-1-null.142^v91^insert_down1,239^v3^insert_chatgpt"}} ] [.reference_item] [ .reference_list ]

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值