配置基于ALB网关的全链路灰度

在微服务架构中,当需求开发涉及到多个微服务的改动时,每个微服务通常会有灰度环境或分组来接受灰度流量。如果希望上游应用灰度环境中的流量也能进入到下游应用的灰度环境中,请确保一个请求始终在灰度环境中传递。即使调用链路上存在一些没有灰度环境的微服务应用,它们在请求下游应用时,也能够回到下游应用的灰度环境中。借助阿里云ALB负载均衡的灵活路由功能和MSE的全链路灰度能力,您可以轻松实现全链路灰度,而无需修改业务代码。

全链路灰度实现流程

image

注意事项

  • 如果您使用的是Flannel网络插件,则ALB Ingress后端Service服务仅支持NodePort和LoadBalancer类型。

  • ALB的交换机所在的VPC需要与ACK集群的VPC一致。关于ALB支持的地域,请参见支持的地域与可用区

场景示例:按照域名路由,实现全链路灰度

若应用的架构由ALB负载均衡以及后端的微服务架构(Spring Cloud)组成,后端调用链路有3个:交易中心(A)、商品中心(B)和库存中心(C),可以通过客户端或者是HTML来访问后端服务,这些服务之间通过Nacos注册中心实现服务发现。

您可以通过不同的域名来区分线上基线环境和灰度环境,灰度环境可单独配置域名,例如,通过访问www.example.com请求灰度环境,通过访问www.aliyundoc.com请求基线环境。

如图所示,调用链路为Ingress-ALB > A > B > C,其中A可以是一个Spring Boot的应用。

场景

准备工作

创建Kubernetes集群

创建Kubernetes集群,且集群版本为1.18及以上版本。具体操作,请参见创建ACK托管集群创建ACK专有集群

通过Kubectl工具连接ACK集群

通过Kubectl工具连接ACK集群。具体操作,请参见获取集群KubeConfig并通过kubectl工具连接集群

安装ALB Ingress Controller组件

为ACK集群安装ALB Ingress Controller组件。以下两种方式选择一种即可。

  • 在ACK创建集群时,通过在组件配置向导页面的Ingress字段右侧,选择ALB Ingress,为集群安装ALB Ingress Controller组件。

  • 若已创建ACK集群,在组件管理页面,可安装ALB Ingress Controller组件。具体操作,请参见管理组件

开启MSE微服务治理

  1. MSE微服务治理开通页面,开通微服务治理专业版。

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

  2. 将ACK微服务应用接入MSE治理中心,您可以选择您需要的方式实现应用接入。更多信息,请参见ACK微服务应用接入MSE治理中心

    为ACK命名空间中的应用开启MSE微服务治理

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

    2. 在左侧导航栏,选择治理中心 > 应用治理

    3. 应用列表页面,单击ACK应用接入

    4. ACK应用接入对话框中,进行配置,配置完成后,单击确定

      image

      配置项

      说明

      集群类型

      选择ACK集群或者ACK Serverless集群

      说明

      如果您尚未授权容器服务调用微服务引擎,则需要单击请授权进行授权。

      集群名称/ID

      选择接入MSE微服务治理的集群名称/ID,可通过关键词搜索。

      ack-onepilot

      显示ack-onepilot接入状态。

      • 如果您未安装ack-onepilot,单击ack-onepilot右侧的点击安装,安装完成后状态会显示为已安装

      • 如果您使用子账号接入,提示没有权限使用时,您可以登录容器服务管理控制台进入目标集群,然后单击运维管理>组件管理,然后找到ack-onepilot,点击安装。

      说明
      • 该步骤接入的组件为ack-onepilot,您可以登录容器服务管理控制台进入目标集群,然后单击运维管理>组件管理查看详情。

      • ack-onepilot安装后会自动注入探针,可能会导致应用启动耗时增加(10s内)。

      接入类型

      选择命名空间接入

      容器集群命名空间

      选择容器集群命名空间

      治理命名空间

      选择治理命名空间。在对应命名空间下重新部署现有应用或新创建的应用,均会接入到MSE微服务治理中。关于命名空间的相关信息,请参见微服务命名空间管理

    为单个应用开启MSE微服务治理

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

    2. 在左侧导航栏,选择治理中心 > 应用治理

    3. 应用列表页面,单击ACK应用接入

    4. ACK应用接入对话框中,进行配置,配置完成后,单击确定

      image

      配置项

      说明

      集群类型

      选择ACK集群或者ACK Serverless集群

      说明

      如果您尚未授权容器服务调用微服务引擎,则需要单击请授权进行授权。

      集群名称/ID

      选择接入MSE微服务治理的集群名称/ID,可通过关键词搜索。

      ack-onepilot

      显示ack-onepilot接入状态。

      • 如果您未安装ack-onepilot,单击ack-onepilot右侧的点击安装,安装完成后状态会显示为已安装

      • 如果您使用子账号接入,提示没有权限使用时,您可以登录容器服务管理控制台进入目标集群,然后单击运维管理>组件管理,然后找到ack-onepilot,点击安装。

      说明
      • 该步骤接入的组件为ack-onepilot,您可以登录容器服务管理控制台进入目标集群,然后单击运维管理>组件管理查看详情。

      • ack-onepilot安装后会自动注入探针,可能会导致应用启动耗时增加(10s内)。

      接入类型

      选择单个应用接入

      接入步骤

      按照接入步骤进行操作。

      Step 1:进入集群工作负载-无状态应用页面,切换到应用的命名空间下

      Step 2:找到所接入的应用,点击「查看Yaml」

      Step 3:按以下格式编辑Labels,完成后点击「更新」

      spec:
        template:
          metadata:
            labels:
              # 填写“on”表示开启接入,需加上双引号
              msePilotAutoEnable: "on"
              # 填写接入到的治理命名空间,值不存在可自动新建
              mseNamespace: 202401
              # 填写接入MSE的实际应用名称,需加上双引号
              msePilotCreateAppName: "your-deployment-name"

部署Demo应用程序

  1. 登录容器服务管理控制台,在左侧导航栏选择集群

  2. 集群列表页面,单击目标集群名称,然后在左侧导航栏,选择工作负载 > 无状态

  3. 无状态页面,选择命名空间,然后单击使用YAML创建资源,对模板进行相关配置,完成配置后单击创建

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

    # A应用base版本
    ---
    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-hangzhou.aliyuncs.com/mse-governance-demo/spring-cloud-a:3.0.1
            imagePullPolicy: Always
            name: spring-cloud-a
            ports:
            - containerPort: 20001
            livenessProbe:
              tcpSocket:
                port: 20001
              initialDelaySeconds: 10
              periodSeconds: 30
    
    # A应用gray版本
    ---
    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
            - name: profiler.micro.service.tag.trace.enable
              value: "true"
            image: registry.cn-hangzhou.aliyuncs.com/mse-governance-demo/spring-cloud-a:3.0.1
            imagePullPolicy: Always
            name: spring-cloud-a-new
            ports:
            - containerPort: 20001
            livenessProbe:
              tcpSocket:
                port: 20001
              initialDelaySeconds: 10
              periodSeconds: 30
    
    # B应用base版本
    ---
    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-hangzhou.aliyuncs.com/mse-governance-demo/spring-cloud-b:3.0.1
            imagePullPolicy: Always
            name: spring-cloud-b
            ports:
            - containerPort: 8080
            livenessProbe:
              tcpSocket:
                port: 20002
              initialDelaySeconds: 10
              periodSeconds: 30
    
    # B应用gray版本
    ---
    apiVersion: apps/v1
    kind: Deployment
    metadata:
      name: spring-cloud-b-new
    spec:
      replicas: 2
      selector:
        matchLabels:
          app: spring-cloud-b-new
      template:
        metadata:
          labels:
            alicloud.service.tag: gray
            msePilotCreateAppName: spring-cloud-b
            app: spring-cloud-b-new
        spec:
          containers:
          - env:
            - name: JAVA_HOME
              value: /usr/lib/jvm/java-1.8-openjdk/jre
            image: registry.cn-hangzhou.aliyuncs.com/mse-governance-demo/spring-cloud-b:3.0.1
            imagePullPolicy: Always
            name: spring-cloud-b-new
            ports:
            - containerPort: 8080
            livenessProbe:
              tcpSocket:
                port: 20002
              initialDelaySeconds: 10
              periodSeconds: 30
    
    # C应用base版本
    ---
    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-hangzhou.aliyuncs.com/mse-governance-demo/spring-cloud-c:3.0.1
            imagePullPolicy: Always
            name: spring-cloud-c
            ports:
            - containerPort: 8080
            livenessProbe:
              tcpSocket:
                port: 20003
              initialDelaySeconds: 10
              periodSeconds: 30
    
    # C应用gray版本
    ---
    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-hangzhou.aliyuncs.com/mse-governance-demo/spring-cloud-c:3.0.1
            imagePullPolicy: IfNotPresent
            name: spring-cloud-c-new
            ports:
            - containerPort: 8080
            livenessProbe:
              tcpSocket:
                port: 20003
              initialDelaySeconds: 10
              periodSeconds: 30
    
    # Nacos Server
    ---
    apiVersion: apps/v1
    kind: Deployment
    metadata:
      name: nacos-server
    spec:
      replicas: 1
      selector:
        matchLabels:
          app: nacos-server
      template:
        metadata:
          labels:
            app: nacos-server
        spec:
          containers:
          - env:
            - name: MODE
              value: standalone
            image: registry.cn-hangzhou.aliyuncs.com/mse-governance-demo/nacos-server:v2.1.2
            imagePullPolicy: Always
            name: nacos-server
          dnsPolicy: ClusterFirst
          restartPolicy: Always
    
    # Nacos Server Service配置
    ---
    apiVersion: v1
    kind: Service
    metadata:
      name: nacos-server
    spec:
      ports:
      - port: 8848
        protocol: TCP
        targetPort: 8848
      selector:
        app: nacos-server
      type: ClusterIP
                    

配置网络

针对入口应用A配置两个K8s Service,spring-cloud-a-base对应A的base版本,spring-cloud-a-gray对应A的gray版本。

apiVersion: v1
kind: Service
metadata:
  name: spring-cloud-a-base
spec:
  ports:
    - name: http
      nodePort: 32605
      port: 20001
      protocol: TCP
      targetPort: 20001
  selector:
    app: spring-cloud-a
  sessionAffinity: None
  type: NodePort

---
apiVersion: v1
kind: Service
metadata:
  name: spring-cloud-a-gray
spec:
  ports:
    - name: http
      nodePort: 31622
      port: 20001
      protocol: TCP
      targetPort: 20001
  selector:
    app: spring-cloud-a-new
  sessionAffinity: None
  type: NodePort

步骤一:配置ALB路由

  1. 创建ALB Config。具体操作,请参见创建AlbConfig

    重要

    ALB交换机所在的VPC需与集群所在的VPC一致,否则会影响业务使用。

  2. 配置Ingress。

    拷贝以下内容到gray-ingress.yaml文件中。

    • 1.19版本以下集群。

      apiVersion: networking.k8s.io/v1beta1
      kind: Ingress
      metadata:
        name: demo
        namespace: default
      spec:
        ingressClassName: alb
        rules:
          - host: www.aliyundoc.com
            http:
              paths:
                - path: /a
                  backend:
                    serviceName: spring-clud-a-base
                    servicePort: 20001
          - host: www.example.com
            http:
              paths:
                - backend:
                    serviceName: spring-cloud-a-gray
                    servicePort: 20001
                  path: /a
                  pathType: ImplementationSpecific
    • 1.19及以上版本集群。

      apiVersion: networking.k8s.io/v1
      kind: Ingress
      metadata:
        name: cafe-ingress
      spec:
        ingressClassName: alb
        rules:
         - host: www.aliyundoc.com
           http:
            paths:
            # 配置Context Path
            - path: /a
              pathType: ImplementationSpecific
              backend:
                service:
                  name: spring-clud-a-base
                  port:
                    number: 20001
         - host: www.example.com
           http:
            paths:
            # 配置Context Path
            - path: /a
              pathType: ImplementationSpecific
              backend:
                service:
                  name: spring-clud-a-base-gray
                  port:
                    number: 20001
  3. 执行如下命令。

    kubectl apply -f gray-ingress.yaml

    执行命令若没有出现对应的ADDRESS(端点),可前往以下页面查看事件,并对照本文的前提条件排查错误。事件

步骤二:配置MSE全链路灰度

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

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

  3. 单击创建泳道组及泳道。如果您选择的微服务空间内已经创建过泳道组,则单击+创建泳道组
  4. 创建泳道组面板,配置泳道组相关参数,然后单击确定

    添加spring-cloud-a、spring-cloud-b和spring-cloud-c应用到泳道组。创建泳道组

  5. 全链路灰度页面底部,单击点击创建第一个分流泳道。在创建泳道面板,设置流控泳道相关参数,选择标签gray,然后单击确定

    创建泳道

步骤三:验证结果

  • 访问www.aliyundoc.com路由到基线环境。

    # 测试命令
    curl -H"Host:aliyundoc.base.com" http://alb-828vagckg5omzfy49n.cn-beijing.alb.aliyuncs.com/a
    # 测试结果
    A[172.18.XX.XX] -> B[172.18.XX.XX] -> C[172.18.XX.XX]%
  • 访问www.example.com路由到灰度环境。

    # 测试命令
    curl -H"Host:www.example.com" http://alb-828vagckg5omzfy49n.cn-beijing.alb.aliyuncs.com/a
    # 测试结果
    Agray[172.18.XX.XX] -> Bgray[172.18.XX.XX] -> Cgray[172.18.XX.XX]%
说明

其中alb-828vagckg5omzfy49n.cn-beijing.alb.aliyuncs.com为ALB的地址。