部署在阿里云容器服务ACK集群中的Spring Cloud或Dubbo微服务应用,为了确保其升级的安全性,可以使用金丝雀发布(即灰度发布)进行小规模验证,验证通过后再全量升级。本文通过示例演示如何通过MSE实现全链路金丝雀发布。

前提条件

背景信息

本文通过模拟真实的调用链路为您演示MSE金丝雀全链路发布功能。您无需修改任何业务代码,只需要给入口应用设置流量规则,该流量的标签通过链路透传到下一个灰度版本中。在每个应用的调用过程中,符合金丝雀条件的流量会优先调用对应的金丝雀版本(即灰度版本),如果没有金丝雀版本则会自动切换回生产版本(即稳定版本)。

  1. 分别部署spring-cloud-zuul、spring-cloud-a、spring-cloud-b、spring-cloud-c这四个业务应用,以及注册中心Nacos Server。调用链路为:A->B->C。

    应用之间的调用既包含了Spring Cloud服务调用,也包含了Dubbo服务调用。

    Demo架构图
  2. 部署spring-cloud-a应用和spring-cloud-b应用的灰度版本,并给spring-cloud-a应用配置流量规则,例如设置name=xiaoming的流量规则条件。
  3. 给spring-cloud-a应用打开链路透传,验证金丝雀发布结果。此时调用链路为:Agray->Bgray->C。

步骤一:将应用接入MSE微服务治理

  1. 在ACK中安装MSE治理中心组件
    1. 登录容器服务控制台
    2. 在左侧导航栏单击市场 > 应用目录
    3. 应用目录页面搜索并单击ack-mse-pilot
    4. 详情页面选择开通该组件的集群,然后单击创建
      说明 命名空间mse-pilot,不可修改。
      创建mse组件
    安装完成后,在命名空间mse-pilot中出现mse-pilot-ack-mse-pilot应用,表示安装成功。
  2. 为ACK集群指定的命名空间开启MSE微服务治理
    1. 登录MSE治理中心控制台
    2. 在左侧导航栏选择微服务治理中心 > K8s集群列表
    3. K8s集群列表页面搜索目标集群,单击搜索图标图标,然后单击目标集群操作列下方的管理
    4. 集群详情页面命名空间列表区域,单击目标命名空间操作列下方的开启微服务治理
      开启微服务治理
    5. 开启微服务治理对话框中单击确认

步骤二:部署应用,模拟线上场景

分别部署spring-cloud-zuul、spring-cloud-a、spring-cloud-b、spring-cloud-c这四个业务应用,以及注册中心Nacos Server。您也可以直接在Demo中获取对应的源码。

  1. 容器服务控制台左侧导航栏中,单击集群
  2. 集群列表页面中,单击目标集群名称或者目标集群右侧操作列下的详情
  3. 在集群管理页左侧导航栏中,选择工作负载 > 无状态
  4. 无状态页面选择命名空间,然后单击使用YAML创建资源
    本文示例中部署spring-cloud-zuul、spring-cloud-a、spring-cloud-b、spring-cloud-c这四个业务应用,以及一个注册中心Nacos Server应用,用于实现服务发现。
    • spring-cloud-zuul应用YAML:
      apiVersion: apps/v1
      kind: Deployment
      metadata:
        name: spring-cloud-zuul
      spec:
        selector:
          matchLabels:
            app: spring-cloud-zuul
        template:
          metadata:
            labels:
              app: spring-cloud-zuul
              msePilotCreateAppName: spring-cloud-zuul
          spec:
            containers:
              - env:
                  - name: JAVA_HOME
                    value: /usr/lib/jvm/java-1.8-openjdk/jre
                image: registry.cn-shanghai.aliyuncs.com/yizhan/spring-cloud-zuul:1.0.0
                imagePullPolicy: Always
                name: spring-cloud-zuul
                ports:
                  - containerPort: 20000
      
      ---
      apiVersion: v1
      kind: Service
      metadata:
        annotations:
          service.beta.kubernetes.io/alibaba-cloud-loadbalancer-spec: slb.s1.small
          service.beta.kubernetes.io/alicloud-loadbalancer-address-type: internet
        name: zuul-slb
      spec:
        ports:
          - port: 80
            protocol: TCP
            targetPort: 20000
        selector:
          app: spring-cloud-zuul
        type: LoadBalancer
      status:
        loadBalancer: {}
    • spring-cloud-a应用YAML:
      apiVersion: apps/v1
      kind: Deployment
      metadata:
        name: spring-cloud-a
      spec:
        selector:
          matchLabels:
            app: spring-cloud-a
        template:
          metadata:
            labels:
              app: spring-cloud-a
              msePilotCreateAppName: 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:1.0.0
                imagePullPolicy: Always
                name: spring-cloud-a
                ports:
                  - containerPort: 20001
                livenessProbe:
                  tcpSocket:
                    port: 20001
                  initialDelaySeconds: 10
                  periodSeconds: 30
    • spring-cloud-b应用YAML:
      apiVersion: apps/v1
      kind: Deployment
      metadata:
        name: spring-cloud-b
      spec:
        selector:
          matchLabels:
            app: spring-cloud-b
        template:
          metadata:
            labels:
              app: spring-cloud-b
              msePilotCreateAppName: 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:1.0.0
                imagePullPolicy: Always
                name: spring-cloud-b
                ports:
                  - containerPort: 20002
                livenessProbe:
                  tcpSocket:
                    port: 20002
                  initialDelaySeconds: 10
                  periodSeconds: 30
    • spring-cloud-c应用YAML:
      apiVersion: apps/v1
      kind: Deployment
      metadata:
        name: spring-cloud-c
      spec:
        selector:
          matchLabels:
            app: spring-cloud-c
        template:
          metadata:
            labels:
              app: spring-cloud-c
              msePilotCreateAppName: 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:1.0.0
                imagePullPolicy: Always
                name: spring-cloud-c
                ports:
                  - containerPort: 20003
                livenessProbe:
                  tcpSocket:
                    port: 20003
                  initialDelaySeconds: 10
                  periodSeconds: 30
    • Nacos Server应用YAML:
      apiVersion: apps/v1
      kind: Deployment
      metadata:
        name: nacos-server
      spec:
        selector:
          matchLabels:
            app: nacos-server
        template:
          metadata:
            annotations:
            labels:
              app: nacos-server
          spec:
            containers:
              - env:
                  - name: MODE
                    value: "standalone"
                image: registry.cn-shanghai.aliyuncs.com/yizhan/nacos-server:latest
                imagePullPolicy: IfNotPresent
                name: nacos-server
                ports:
                  - containerPort: 8848
      
      ---
      apiVersion: v1
      kind: Service
      metadata:
        name: nacos-server
      spec:
        type: ClusterIP
        selector:
          app: nacos-server
        ports:
          - name: http
            port: 8848
            targetPort: 8848
    执行以下命令查看部署结果:
    kubectl get svc,deploy

    预期输出:

    NAME                   TYPE           CLUSTER-IP        EXTERNAL-IP     PORT(S)        AGE
    service/kubernetes     ClusterIP      192.168.XX.XX       <none>          443/TCP        4h40m
    service/nacos-server   ClusterIP      192.168.XX.XX       <none>          8848/TCP       99m
    service/zuul-slb       LoadBalancer   192.168.XX.XX    47.100.XX.XX     80:30767/TCP     25m
    
    NAME                                READY   UP-TO-DATE   AVAILABLE   AGE
    deployment.apps/nacos-server        1/1     1            1           99m
    deployment.apps/spring-cloud-a      1/1     1            1           26m
    deployment.apps/spring-cloud-b      1/1     1            1           25m
    deployment.apps/spring-cloud-c      1/1     1            1           25m
    deployment.apps/spring-cloud-zuul   1/1     1            1           25m

步骤三:部署spring-cloud-a应用的灰度版本

  1. 容器服务控制台上部署spring-cloud-a应用的灰度版本,对应的YAML如下:
    apiVersion: apps/v1
    kind: Deployment
    metadata:
      name: spring-cloud-a-gray
    spec:
      selector:
        matchLabels:
          app: spring-cloud-a-gray
      template:
        metadata:
          annotations:
            alicloud.service.tag: gray
          labels:
            app: spring-cloud-a-gray
            msePilotCreateAppName: 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:1.0.0
              imagePullPolicy: Always
              name: spring-cloud-a-gray
              ports:
                - containerPort: 20001
              livenessProbe:
                tcpSocket:
                  port: 20001
                initialDelaySeconds: 10
                periodSeconds: 30
  2. 登录MSE治理中心控制台,在左侧导航栏选择微服务治理中心 > 应用列表
  3. 单击spring-cloud-a应用名称,在应用概览页面左侧导航栏单击应用详情
    可以看到,所有流量请求都是去往spring-cloud-a应用未打标的版本,即稳定版本。spring-cloud-a应用详情

步骤四:为spring-cloud-a应用配置灰度规则

  1. 应用详情页面,单击标签路由
  2. 在打了gray标签的应用流量规则下方单击添加
  3. 创建标签路由面板中配置流量规则,然后单击确定

    本文示例中设置的流量规则条件为name=xiaoming

    为spring-cloud-a配置流量规则

    关于流量规则的配置,请参见配置标签路由

    流量规则生效后,在应用详情页面可以查看流量分布结果。流量规则生效结果

步骤五:部署spring-cloud-b应用的灰度版本

  1. 容器服务控制台上部署spring-cloud-b应用的灰度版本,对应的YAML如下:
    apiVersion: apps/v1
    kind: Deployment
    metadata:
      name: spring-cloud-b-gray
    spec:
      selector:
        matchLabels:
          app: spring-cloud-b-gray
      template:
        metadata:
          annotations:
            alicloud.service.tag: gray
          labels:
            app: spring-cloud-b-gray
            msePilotCreateAppName: 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:1.0.0
              imagePullPolicy: Always
              name: spring-cloud-b-gray
              ports:
                - containerPort: 20002
              livenessProbe:
                tcpSocket:
                  port: 20002
                initialDelaySeconds: 10
                periodSeconds: 30
  2. 登录MSE治理中心控制台,在左侧导航栏选择微服务治理中心 > 应用列表
  3. 单击spring-cloud-b应用名称,在应用概览页面左侧导航栏单击应用详情
    可以看到,所有流量请求都是去往spring-cloud-b应用未打标的版本,即稳定版本。spring cloud b应用详情

步骤六:验证全链路金丝雀发布

  1. 在spring-cloud-a应用配置的灰度规则中打开链路透传的开关,然后单击确定
    说明 打开链路透传开关后,name=xiaoming的灰度流量能在全链路里进行透传,且无需重复地配置规则。
    为spring-cloud-a应用配置流量规则
  2. 容器服务控制台集群详情页面左侧导航栏选择网络 > 服务
  3. 单击zuul-slb服务所对应的外部端点地址。
  4. 在服务调用页面输入/A/a?name=xiaoming,然后单击开始调用
    全链路金丝雀发布已经生效。服务调用结果

    此时,spring-cloud-b应用的请求数据如下:

    spring cloud b应用流量曲线

步骤七:验证通过后,完成发布

  1. 灰度版本的镜像验证通过之后,将spring-cloud-a和spring-cloud-b应用的镜像版本更新成最新的镜像版本。您可以通过修改应用的YAML文件或ACK控制台操作。
  2. 将spring-cloud-a-gray和spring-cloud-b-gray这两个灰度版本应用的副本数量设置为0,便于您之后继续使用时,只需更新镜像版本,然后对应用进行扩容,不需要再重新创建应用。
    说明
    • 灰度规则可以继续保留,您无需反复地配置流量规则。
    • 当找不到对应的节点时,流量会请求到未打标的应用版本,即稳定版本。