ACK Nginx Ingress 灰度发布

本文主要从使用背景、使用前提和实现原理等方面介绍了ACK Nginx Ingress 灰度发布,以及如何快速配置灰度发布流水线。

使用背景

  • 灰度及蓝绿发布:为新版本创建一个与老版本完全一致的生产环境,在不影响老版本的前提下,按照一定的规则把部分流量切换到新版本,当新版本试运行一段时间没有问题后,将用户的全量流量从老版本迁移至新版本。其中A/B测试就是一种灰度发布方式,一部分用户继续使用老版本的服务,将一部分用户的流量切换到新版本,如果新版本运行稳定,则逐步将所有用户迁移到新版本。

  • Ingress灰度发布使用背景:控制新版本流量分配权重,以小部分线上流量对服务进行验证通过cookie或者header使得部分受控用户在线上对发布进行验证。当发布验证失败后,可以快速回滚到旧版本。

使用前提

  • 使用由阿里云容器服务Kubernetes版本提供的ACK,有关内容请参见创建集群

  • Deploymentlabels内包含有Service的全部selector labels,如:

    apiVersion: apps/v1
    kind: Deployment
    metadata:  
      name: spring-boot-sample  
      labels:
        run: spring-boot-sample
    spec:  
      replicas: 2  
      selector:    
        matchLabels:
          run: spring-boot-sample 
      template:    
        metadata:
          labels:        
            run: spring-boot-sample   
        spec:
          imagePullSecrets:
          - name: acr-registry-private
          containers:
          - name: app     # 容器名称
            image: nginx
            imagePullPolicy: Always
            ports:
            - containerPort: 8080
              protocol: TCP
              
    ---
    
    apiVersion: v1
    kind: Service
    metadata:  
      name: spring-boot-service
    spec:
      type: ClusterIP
      selector:      #标签选择器,定义要访问的目标pod
        run: spring-boot-sample  
      sessionAffinity: None  
      ports:  
      - port: 8080 #服务端口    
        protocol: TCP    
        targetPort: 8080 

实现原理

如下图所示,当采用ACK Nginx Ingress灰度发布时,假定当前运行版为primary,将要发布版本为canary。

发布过程:

  1. 发布前检查:预检查当前Ingress是否有且只关联了唯一的Service实例,且Service实例下有且只有唯一版本的Deployment。

  2. 生成Canary版本:克隆primary版本的Service以及Deployment生成canary版本的ServiceDeployment,同时修改canary版本Deployment的镜像到新版本。

  3. 修改Ingress流量规则:根据发布配置调整Ingress配置,开始执行灰度。

  4. 人工验证:通过cookie或者header对灰度版本进行验证,根据结果选择完成发布或者回滚。

  5. 完成灰度:修改Ingress配置以及流量规则,下线Primary版本的Service以及Deployment实例。

  6. 回滚发布:修改Ingress配置以及流量规则,下线Canary版本的Service以及Deployment。

快速开始

一. 初始化应用部署

  1. 通过以下YAML配置文件,快速初始化应用部署。

    apiVersion: apps/v1
    kind: Deployment
    metadata:  
      name: old-nodejs  
      labels:
        run: old-nodejs
    spec:  
      replicas: 2  
      selector:    
        matchLabels:
          run: old-nodejs  
      template:    
        metadata:
          labels:        
            run: old-nodejs    
        spec:
          imagePullSecrets:
          - name: acr-registry-private
          containers:
          - name: app # 容器名称
            image: registry.xxxxx.com/xxxxx/nodejs-example:v1
            imagePullPolicy: Always
            ports:
            - containerPort: 3000
              protocol: TCP
          restartPolicy: Always #在任何情况下,只要容器不在运行状态,就自动重启容器。默认
            
    ---
    
    apiVersion: v1
    kind: Service
    metadata:  
      name: old-nodejs
    spec:
      type: NodePort
      selector:      #标签选择器,定义要访问的目标pod
        run: old-nodejs  
      sessionAffinity: None  
      ports:  
      - port: 80 #服务端口    
        protocol: TCP    
        targetPort: 3000 #应用端口  
    
    ---
    
    apiVersion: networking.k8s.io/v1
    kind: Ingress
    metadata:    
      name: gray-release
    spec:
      rules:  
      - host: www.example.com    
        http:      
          paths:
          - path: /   # 老版本服务,指定代理的路径
            pathType: Prefix
            backend:
              service:
                name: old-nodejs
                port:
                  number: 80       
  2. 将以上内容保存到gray-release.yaml文件,使用kubectl或者控制台完成应用初始化。

    kubectl apply -f gray-release.yaml

二. 配置流水线

  • 如下所示,配置如下信息:Group@1xGroup@1x

  • 配置说明:

    配置项

    说明

    集群连接

    使用集群连接,连接到自定义Kubernetes或者阿里云容器服务集群。

    Kubectl版本

    请选择与K8s集群适配的Kubectl版本。

    命名空间

    当前服务所在Kubernetes集群命名空间, 示例中为default。

    Ingress名称

    发布的目标Ingress实例名称,示例中为gray-release。

    服务端口

    Ingress后端Service 实例对外暴露的端口,示例中为80

    应用端口

    镜像对外暴露的端口,示例中为3000。

    容器名称

    应用发布时需要更新镜像的容器名,示例中为app。

    镜像

    通过前序任务镜像构建产生的镜像,或者是特定的镜像名称。

    灰度匹配方式

    选择使用header或者cookie方式进行灰度验证,并设置匹配的Key/Value。

    灰度匹配名称

    配置自定义的Cookie或者HeaderKEY。

    灰度匹配值

    配置自定义的Cookie或者HeaderValue。

    灰度版本初始化流量权重

    默认灰度版本上线后的流量权重,流量分配比。

    启动等待时间

    灰度版本发布后等待该时间后再修改Ingress配置。

    下线等待时间

    Ingress配置调整后等待该时长后再移除应用实例。

三. 运行流水线

  • 保存并运行流水线,当新版本发布后,流水线的任务将处于灰度发布中,等待人工验证,以确定后续操作。Group@1x

  • 当任务灰度中,可以查看下Ingress资源Annotations自定义注释列表,在灰度前后的资源变化。image

  • 当任务在灰度中,访问应用服务测试结果,可以观察到请求访问流量,会按照自定义配置的灰度版本权重的60%进行流量分配。用户可以通过在浏览器设置cookie的后来访问新版本的应用。

    document.cookie="foo=bar"

    Group@1x (1)Group@1x

  • 当在灰度中云效自动创建了灰度版本的服务,命名规则为:<ingressname>-<version>,查看灰度版本的详情。Group@1x

四. 确认发布完成

在人工验证成功后,在任务节点上单击继续发布按钮后,流水线将会自动完成ingress的配置调整,以及老版本的应用下线操作。Group@1x

此时查看线上应用Ingress信息,如下所示:Group@1x (2)

常见发布失败的问题

  • Ingress关联了多个Service实例时发布失败。

  • Service关联了多个Deployment实例时发布失败,ServiceLabelSelector需要确保与Deploymentlabels保持匹配。

  • 线上版本镜像和当前发布镜像未变化时,发布失败。

  • 而发布配置中的容器名称无法匹配到容器定义时发布失败。