配置基于阿里云Nginx Ingress的全链路灰度

通过阿里云Nginx Ingress提供的全链路灰度能力,可以在不需要修改任何您的业务代码的情况下,实现全链路流量控制。本文介绍通过阿里云Nginx Ingress实现全链路灰度功能。

前提条件

已创建Kubernetes集群。具体操作,请参见创建Kubernetes托管版集群

使用限制

由于全链路灰度功能整合了标签路由功能,因此不推荐已经加入全链路流量控制的应用同时配置金丝雀发布和标签路由规则功能呢。

说明

使用本功能时,阿里云Nginx Ingress不支持同时使用nginx.ingress.kubernetes.io/configuration-snippet

限制项

限制值

备注

Spring Cloud版本

Spring Cloud Edgware及以上版本。

无。

Dubbo版本

2.5.3~2.7.8

Dubbo 3.0及以上版本当前处于灰度中,如有场景需求,请加入钉群(钉群号:34754806)联系技术支持。

客户端类型

  • Resttemplate。

  • Spring Cloud OpenFeign。

无。

Java应用JDK版本

目前支持JDK 1.6、1.7、1.8版本应用接入。

JDK 1.11版本当前处于灰度中,如有场景需求,请加入钉群(钉群号:34754806)联系技术支持。

负载均衡类型

  • 支持Ribbon 2.0.及以上版本。

  • 支持LoadBalancer 3.0.x及以上版本。

无。

Spring Cloud Gateway版本

支持Spring Cloud Gateway 2.1.0.RELEASE及以上版本。

无。

Spring Cloud Zuul版本

1.3.x。

无。

注册中心类型

  • Nacos。

  • Eureka。

  • ZooKeeper。

微服务治理能力无关注册中心,可以是MSE托管注册中心,也可以是自建注册中心。

背景信息

在微服务场景中,当您部署的Spring Cloud应用或Dubbo应用存在升级版本时,由于应用间的调用是随机的,会导致无法将具有一定特征的流量路由到应用的目标版本。全链路流量控制功能将应用的相关版本隔离成一个独立的运行环境(即泳道),通过设置Ingress路由规则,将满足规则的请求流量路由到应用的目标版本。

本文以电商架构中的下单场景为例,介绍从Ingress网关到微服务的全链路流控功能。假设应用的架构由Nginx Ingress网关以及后端的微服务架构(Spring Cloud)组成,后端调用链路有3个:购物车(A)、交易中心(B)和库存中心(C),可以通过客户端或者是HTML来访问后端服务,这些服务之间通过Nacos注册中心实现服务发现。

客户下单后流量从Ingress网关进来,调用交易中心,交易中心再调用商品中心,商品中心调用下游的库存中心。

交易中心和商品中心各有两个新版本(1和2)在运行,需要对这两个新版本进行灰度验证。此时通过Nginx Ingress网关将满足特定流控规则的请求流量路由到新版本,其余流量全部路由到线上(正式)版本。示例图

名词解释

  • 泳道

    为相同版本应用定义的一套隔离环境。只有满足了流控路由规则的请求流量才会路由到对应泳道里的打标应用。一个应用可以属于多个泳道,一个泳道可以包含多个应用,应用和泳道是多对多的关系。

  • 泳道组

    泳道的集合。泳道组的作用主要是为了区分不同团队或不同场景。

准备工作

安装Ingress-nginx组件

  1. 访问ack-ingress-nginx-v1组件的安装详情页,在页面右上方单击一键部署,在基本信息页面,选择目标集群命名空间,然后单击下一步
    说明 命名空间推荐使用kube-system
  2. 参数配置页面,确认组件参数信息,然后单击确定
    安装完成后,在命名空间kube-system中出现ack-ingress-nginx-v1-default应用,表示安装成功。应用
  3. 在目标集群下,选择配置管理 > 配置项,在页面顶部,选择命名空间为kube-system

  4. 在目标配置项nginx-configuration操作列,单击编辑。在编辑页面底部,单击+ 添加,添加如下两个配置项的名称和值。

    • 配置项名称设置为use-mse,配置项值设置为true

    • 配置项名称设置为mse-app-name,配置项值设置为您希望接入的MSE应用名称。

    说明

    这种Ingress接入方式会实际上会走AHAS产品计费,每个节点收费标准可以参考计费概述

开启MSE微服务治理

  1. 开通微服务治理专业版。

    1. 登录MSE产品页

    2. 在MSE产品页单击立即购买,选择微服务治理页签。

    3. 微服务治理按量付费页面,选择版本专业版,仔细阅读并勾选服务协议,然后单击立即开通

      关于微服务治理的计费详情,请参见计费概述

  2. 安装MSE微服务治理组件。

    1. 登录容器服务控制台
    2. 在左侧导航栏,选择市场 > 应用市场,在搜索框中输入ack-onepilot,单击该组件。
    3. ack-onepilot页面右上方,单击一键部署,在创建页面,选择集群和命名空间,设置组件发布名称,单击下一步,然后单击确定
      说明 建议使用默认的命名空间ack-onepilot
      安装完成后,在命名空间ack-onepilot中出现ack-onepilot应用,表示安装成功。
  3. 为应用开启微服务治理。

    1. 登录MSE治理中心控制台
    2. 在左侧导航栏,选择治理中心 > 运维中心 > K8s集群列表。在目标集群操作列,单击管理
    3. 集群详情页面,在目标命名空间操作列,单击开启微服务治理。然后单击确定

部署Demo应用程序

  1. 登录容器服务管理控制台
  2. 在左侧导航栏,选择集群,然后单击目标集群名称。
  3. 在左侧导航栏,选择工作负载 > 无状态
  4. 无状态页面,选择命名空间,然后单击使用YAML创建资源

  5. 对模板进行相关配置,完成配置后单击创建

    本文示例中部署A、B、C三个应用,每个应用分别部署一个基线版本和一个灰度版本;并部署一个Nacos server应用,用于实现服务发现。

    • A应用

      • 基线(base)版本YAML:

        apiVersion: apps/v1
        kind: Deployment
        metadata:
          name: spring-cloud-a
        spec:
          replicas: 2
          selector:
            matchLabels:
              app: spring-cloud-a
          template:
            metadata:
              labels:
                msePilotCreateAppName: spring-cloud-a
                app: spring-cloud-a
            spec:
              containers:
              - env:
                - name: JAVA_HOME
                  value: /usr/lib/jvm/java-1.8-openjdk/jre
                image: registry.cn-shanghai.aliyuncs.com/yizhan/spring-cloud-a:0.1-SNAPSHOT
                imagePullPolicy: Always
                name: spring-cloud-a
                ports:
                - containerPort: 20001
                livenessProbe:
                  tcpSocket:
                    port: 20001
                  initialDelaySeconds: 10
                  periodSeconds: 30
      • 灰度(gray)版本YAML:

        apiVersion: apps/v1
        kind: Deployment
        metadata:
          name: spring-cloud-a-new
        spec:
          replicas: 2
          selector:
            matchLabels:
              app: spring-cloud-a-new
          strategy:
          template:
            metadata:
              labels:
                alicloud.service.tag: gray
                msePilotCreateAppName: spring-cloud-a
                app: spring-cloud-a-new
            spec:
              containers:
              - env:
                - name: JAVA_HOME
                  value: /usr/lib/jvm/java-1.8-openjdk/jre
                image: registry.cn-shanghai.aliyuncs.com/yizhan/spring-cloud-a:0.1-SNAPSHOT
                imagePullPolicy: Always
                name: spring-cloud-a-new
                ports:
                - containerPort: 20001
                livenessProbe:
                  tcpSocket:
                    port: 20001
                  initialDelaySeconds: 10
                  periodSeconds: 30
    • B应用

      • 基线(base)版本YAML:

        apiVersion: apps/v1
        kind: Deployment
        metadata:
          name: spring-cloud-b
        spec:
          replicas: 2
          selector:
            matchLabels:
              app: spring-cloud-b
          strategy:
          template:
            metadata:
              labels:
                msePilotCreateAppName: spring-cloud-b
                app: spring-cloud-b
            spec:
              containers:
              - env:
                - name: JAVA_HOME
                  value: /usr/lib/jvm/java-1.8-openjdk/jre
                image: registry.cn-shanghai.aliyuncs.com/yizhan/spring-cloud-b:0.1-SNAPSHOT
                imagePullPolicy: Always
                name: spring-cloud-b
                ports:
                - containerPort: 8080
                livenessProbe:
                  tcpSocket:
                    port: 20002
                  initialDelaySeconds: 10
                  periodSeconds: 30

    • C应用

      • 基线(base)版本YAML:

        apiVersion: apps/v1
        kind: Deployment
        metadata:
          name: spring-cloud-c
        spec:
          replicas: 2
          selector:
            matchLabels:
              app: spring-cloud-c
          template:
            metadata:
              labels:
                msePilotCreateAppName: spring-cloud-c
                app: spring-cloud-c
            spec:
              containers:
              - env:
                - name: JAVA_HOME
                  value: /usr/lib/jvm/java-1.8-openjdk/jre
                image: registry.cn-shanghai.aliyuncs.com/yizhan/spring-cloud-c:0.1-SNAPSHOT
                imagePullPolicy: Always
                name: spring-cloud-c
                ports:
                - containerPort: 8080
                livenessProbe:
                  tcpSocket:
                    port: 20003
                  initialDelaySeconds: 10
                  periodSeconds: 30
      • 灰度(gray)版本YAML:

        apiVersion: apps/v1
        kind: Deployment
        metadata:
          name: spring-cloud-c-new
        spec:
          replicas: 2
          selector:
            matchLabels:
              app: spring-cloud-c-new
          template:
            metadata:
              labels:
                alicloud.service.tag: gray
                msePilotCreateAppName: spring-cloud-c
                app: spring-cloud-c-new
            spec:
              containers:
              - env:
                - name: JAVA_HOME
                  value: /usr/lib/jvm/java-1.8-openjdk/jre
                image: registry.cn-shanghai.aliyuncs.com/yizhan/spring-cloud-c:0.1-SNAPSHOT
                imagePullPolicy: IfNotPresent
                name: spring-cloud-c-new
                ports:
                - containerPort: 8080
                livenessProbe:
                  tcpSocket:
                    port: 20003
                  initialDelaySeconds: 10
                  periodSeconds: 30
    • Nacos Server应用YAML:

      apiVersion: apps/v1
      kind: Deployment
      metadata:
        name: nacos-server
      spec:
        replicas: 1
        selector:
          matchLabels:
            app: nacos-server
        template:
          metadata:
            labels:
              msePilotAutoEnable: "off"
              app: nacos-server
          spec:
            containers:
            - env:
              - name: MODE
                value: standalone
              image: nacos/nacos-server:v2.2.0
              imagePullPolicy: Always
              name: nacos-server
            dnsPolicy: ClusterFirst
            restartPolicy: Always
      
      # Nacos Server Service 配置
      ---
      apiVersion: v1
      kind: Service
      metadata:
        name: nacos-server
      spec:
        ports:
        - name: nacos-server-8848-8848
          port: 8848
          protocol: TCP
          targetPort: 8848
        - name: nacos-server-9848-9848
          port: 9848
          protocol: TCP
          targetPort: 9848
        selector:
          app: nacos-server
        type: ClusterIP                            
  6. 针对入口应用A,配置K8s Service。

    1. 在集群详情页面左侧导航栏,选择网络 > 服务

    2. 服务页面选择命名空间,然后单击使用YAML创建资源

    3. 对模板进行相关配置,完成配置后单击创建

      apiVersion: v1
      kind: Service
      metadata:
        name: spring-cloud-a
      spec:
        ports:
          - name: http
            port: 20001
            protocol: TCP
            targetPort: 20001
        selector:
          app: spring-cloud-a

步骤一:创建泳道组

  1. 登录MSE治理中心控制台,并在顶部菜单栏选择地域。

  2. 在左侧导航栏,选择治理中心 > 全链路灰度

  3. 全链路灰度页面,单击创建泳道组及泳道。如果您选择的微服务空间内已经创建过泳道组,则单击+创建泳道组

  4. 创建泳道组对话框,设置泳道组相关参数,然后单击确定

    配置项

    描述

    泳道组名称

    自定义设置泳道组的名称。

    入口类型

    选择阿里云Ingress网关

    入口应用

    选择您的入口应用或入口网关所涉及的所有相关服务。

    开启消息灰度

    • 开启状态,表示打开泳道组所有应用的消息灰度开关。

    • 关闭状态,表示关闭泳道组所有应用的消息灰度开关。

    开启数据库灰度

    • 开启状态,表示打开泳道组所有应用的数据库灰度开关。

    • 关闭状态,表示关闭泳道组所有应用的数据库灰度开关。

    泳道组创建完成后,在全链路灰度页面的泳道组涉及应用区域出现您所创建的泳道组。请检查入口应用和所涉及的应用是否正确,如需变更泳道组信息,请单击右侧的编辑图标并修改相关信息。

步骤二:创建泳道

  1. 全链路灰度页面顶部,选择和创建泳道组时相同的地域,然后底部单击点击创建第一个分流泳道

    如果您选择的微服务空间内已经创建过泳道,则单击创建泳道

    说明

    加入全链路流量控制的应用,不推荐同时使用金丝雀发布和标签路由等功能。

  2. 创建泳道对话框,设置流控泳道相关参数,然后单击确定

    配置项

    描述

    泳道名称

    自定义设置流控泳道的名称。

    配置应用标签

    配置方式:在容器服务控制台去应用YAML的spec.template.metadata.labels下增加alicloud.service.tag:{tag}

    添加应用

    当STPE 2配置应用标签完成后,单击刷新按钮,下拉框中会出现相应的标签列表,选择对应的标签,就会自动添加相应的应用。

    路由规则

    设置相应的路由规则条件。

    • Path:选择需要匹配的路径,可以多选,也可以不填写。如果不填写,会匹配任意路径。

    • 条件模式:路由条件之间的关系。

    • 条件列表:单击下方的+ 添加新的规则条件,新增规则条件。

  3. 全链路灰度页面的流量分配区域,查看泳道信息。

    • 单击图标图标,查看该泳道的流量比例。

    • 单击应用状态图标图标,可在泳道列表的操作列,设置该泳道应用的状态。

      • 开启泳道:单击开启,创建的泳道将会生效,即流量会按照泳道方式进行流转,满足规则的流量会优先流向标记有当前泳道对应标签的应用版本,如果没有对应标签的应用版本则流向未打标的应用版本。

      • 关闭泳道:单击关闭,关闭创建的泳道,即该应用往后的流量会流向未打标的应用版本。

      • 修改泳道:单击编辑,修改当前泳道的配置信息。

      • 删除泳道:单击删除,删除目标泳道。

  4. 配置流量入口的Ingress规则,访问www.base.com路由到A应用的base版本。

    apiVersion: networking.k8s.io/v1beta1
    kind: Ingress
    metadata:
      name: spring-cloud-a-base
    spec:
      rules:
      - host: www.base.com
        http:
          paths:
          - backend:
              serviceName: spring-cloud-a-base
              servicePort: 20001
            path: /

步骤三:配置基线环境的Ingress规则

使用curl命令访问example.com路由到基线环境。

curl -H"Host:www.example.com" http://106.14.XX.XX/a

返回结果如下。

A[172.18.XX.XX] -> B[172.18.XX.XX] -> C[172.18.XX.XX]%

步骤四:配置灰度环境的Ingress规则

使用curl命令访问example.com路由到灰度环境。

curl -H"Host:www.gray.com" http://106.14.XX.XX/a

返回结果如下。灰度流量优先访问了A和C的灰度版本,由于B没有灰度版本,所以访问了B的基线版本。

Agray[172.18.XX.XX] -> B[172.18.XX.XX] -> Cgray[172.18.XX.XX]%

控制台查看应用的流量监控图

  • 查看单个应用的监控图。

    1. 全链路灰度页面,单击目标泳道组页签。

    2. 泳道组及涉及的应用区域,单击目标应用名称,在右侧会出现对应的QPS监控图

  • 查看泳道组内所有应用的监控图。

    1. 全链路灰度页面,单击目标泳道组页签。

    2. QPS监控图右侧,单击查看所有应用监控(流量逃逸观测),可以查看该泳道所有应用的流量监控图。