通过云效构建CI/CD实现微服务全链路灰度

在进行应用的自动化构建和部署时,通常希望能够快速将部署后的应用发布到灰度环境,并且能够方便地对灰度环境的应用进行全链路测试,将运维效率提升到极致。本文介绍如何通过云效整合MSE全链路灰度来实现。

前提条件

整体架构

整体上应用的调用链路是,客户端入口流量首先达到网关应用,而后按顺序经过A、B、C三个应用:

image.png

在一次上线窗口中,A和C进行了迭代,进行了灰度发布。在测试流程中,需要对A和C的灰度版本进行全链路灰度的测试,调用链路如下:

image.png

通过云效,在流水线上增加一个灰度流程。每个应用走到线上环境部署阶段前,都会先发布到灰度环境。等到开发/测试人员对灰度环境的应用测试没有问题时,再手工放行流水线走到真正的线上发布部署阶段:

image.png

准备工作

本文将以A、B、C三个SpringCloud应用为例,介绍如何通过阿里云云效整合MSE全链路灰度的功能,实现将应用一键部署到灰度环境,并进行全链路灰度的测试。假设已有A、B、C三个应用的基线版本正在运行。

步骤一:开启MSE微服务治理

将ACK微服务应用接入MSE治理中心。具体操作,请参见ACK微服务应用接入MSE治理中心

步骤二:准备基线版本(若已有则可忽略)

您可以按如下步骤,部署基线环境:

  1. 创建MSE Nacos,并复制其内网域名。具体操作,请参见创建Nacos引擎

  2. 创建MSE云原生网关,并关联第一步创建的Nacos。具体操作,请参见创建MSE云原生网关新建服务来源

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

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

  5. 无状态页面,单击使用YAML创建资源。模板内容使用如下YAML示例部署A、B、C三个应用,然后单击创建

    说明

    代码中的{nacos server address}需要替换成您的Nacos内网域名,同时需要去掉大括号{}。

    # 应用 A 的基线版本
    apiVersion: apps/v1
    kind: Deployment
    metadata:
      name: spring-cloud-a
      namespace: default
    spec:
      selector:
        matchLabels:
          app: spring-cloud-a
      template:
        metadata:
          labels:
            app: spring-cloud-a
            msePilotCreateAppName: spring-cloud-a
            msePilotAutoEnable: 'on'
        spec:
          containers:
          - name: spring-cloud-a
            image: "registry.cn-hangzhou.aliyuncs.com/mse-governance-demo/spring-cloud-a:3.0.1"
            imagePullPolicy: Always
            ports:
              - containerPort: 20001
            livenessProbe:
              tcpSocket:
                port: 20001
              initialDelaySeconds: 30
              periodSeconds: 60
            env:
            - name: spring.cloud.nacos.discovery.server-addr
              value: {nacos server address}
            - name: dubbo.registry.address
              value: 'nacos://{nacos server address}:8848'
    ---
    # 应用 B 的基线版本
    apiVersion: apps/v1
    kind: Deployment
    metadata:
      name: spring-cloud-b
      namespace: default
    spec:
      selector:
        matchLabels:
          app: spring-cloud-b
      template:
        metadata:
          labels:
            app: spring-cloud-b
            msePilotCreateAppName: spring-cloud-b
            msePilotAutoEnable: 'on'
        spec:
          containers:
          - name: spring-cloud-b
            image: "registry.cn-hangzhou.aliyuncs.com/mse-governance-demo/spring-cloud-b:3.0.1"
            imagePullPolicy: Always
            ports:
              - containerPort: 20002
            livenessProbe:
              tcpSocket:
                port: 20002
              initialDelaySeconds: 30
              periodSeconds: 60
            env:
            - name: spring.cloud.nacos.discovery.server-addr
              value: {nacos server address}
            - name: dubbo.registry.address
              value: 'nacos://{nacos server address}:8848'
    ---
    # 应用 C 的基线版本
    apiVersion: apps/v1
    kind: Deployment
    metadata:
      name: spring-cloud-c
      namespace: default
    spec:
      selector:
        matchLabels:
          app: spring-cloud-c
      template:
        metadata:
          labels:
            app: spring-cloud-c
            msePilotCreateAppName: spring-cloud-c
            msePilotAutoEnable: 'on'
        spec:
          containers:
          - name: spring-cloud-c
            image: "registry.cn-hangzhou.aliyuncs.com/mse-governance-demo/spring-cloud-c:3.0.1"
            imagePullPolicy: Always
            ports:
              - containerPort: 20003
            livenessProbe:
              tcpSocket:
                port: 20003
              initialDelaySeconds: 30
              periodSeconds: 60
            env:
            - name: spring.cloud.nacos.discovery.server-addr
              value: {nacos server address}
            - name: dubbo.registry.address
              value: 'nacos://{nacos server address}:8848'
  6. 登录MSE治理中心控制台选择 治理中心 > 应用治理,在顶部选择您的命名空间。单击进入目标应用,在 QPS 数据中可以看到流量的情况,确认流量都打到未打标的节点,并没有灰度节点的流量。

    image.png

步骤三:创建MSE全链路灰度泳道

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

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

  3. 全链路灰度页面,单击+ 创建泳道组及泳道

    如果您已经创建过泳道组,则单击+ 创建泳道组

  4. 创建泳道组面板,设置如下相关配置,然后单击确定

    配置项

    说明

    泳道组名称

    自定义泳道组的名称。

    入口类型

    选择MSE 云原生网关

    泳道组流量入口

    选择目标云原生网关。

    泳道组涉及应用

    选择spring-cloud-aspring-cloud-bspring-cloud-c

    image

    泳道组创建完成后,在全链路灰度页面的泳道组区域,可以查看您创建的泳道组。如需变更泳道组信息,单击image.png图标,可在页面修改相关信息。

  5. 全链路灰度页面底部,单击点击创建第一个分流泳道

    如果您已经创建过泳道,则单击创建泳道

  6. 创建泳道对话框中设置相关配置,然后单击确定

    image.png

在云效上整合MSE全链路灰度

您可以根据以下两种方式集成MSE全链路灰度。

方式一:通过Flow方式构建CI/CD流水线

在本例中,使用其他 > 空模板创建云效流水线,创建后,需要进行四部分配置:

步骤一:配置云效流水线源

配置流水线的代码源。配置完成后,添加到流水线中。

  • 代码仓库:https://gitee.com/mse-group/alibabacloud-microservice-demo.git。

    为了避免网络延迟,所以采用gitee仓库。

  • 默认分支:master。

  • 选择凭证类型:选择服务连接

    由于本示例中代码仓库为公开代码仓库,所以只需要按照默认值创建即可。

image.png

步骤二:构建阶段配置

此阶段配置云效如何构建Docker镜像。删除原有的阶段和空任务,手动添加新任务。

配置项

说明

构建集群

就近选择。本示例选择北京构建集群。

服务连接

按照提示添加ACR的服务连接。通过RAM授权的方式,让云效可以推送镜像到ACR中。

仓库

选择您需要推送、部署的镜像仓库。

标签

默认${DATETIME}

Dockerfile路径

输入Dockerfile路径。本示例为mse-simple-demo/A/Dockerfile

image.png

image.png

步骤三:部署Gray阶段配置

本步骤介绍如何部署Gray节点。云效可以直接替换Kubernetes中的Workload镜像,可以直接使用此机制来发布。

配置项

说明

集群连接

授权云效修改ACK集群中Workload配置。按照授权添加对应ACK集群连接。

Kubectl版本

选择相近版本。

命名空间

输入命名空间。

Workloads类型

选择Workloads类型。本示例为Deployment。

Workloads名称

输入Workloads名称。本示例为spring-cloud-a-gray

容器名称

输入容器名称。本示例为spring-cloud-a-gray。

镜像

选择上一步构建的镜像。可以选择镜像公网地址。

image.png

步骤四:部署线上阶段配置

类似步骤三的配置:

  • Workloads名称:此处为基线环境的Workloads,值为spring-cloud-a。

  • 容器名称:spring-cloud-a。

image.png

最后,将部署Gray阶段和部署线上阶段的发模式改为手动触发

完整配置好后的效果如下图所示:

image.png

步骤五:运行流水线

配置好流水线后,您可以按照发布流程逐步运行流水线:

image.png

  1. 打包构建。手动运行刚刚的创建好的流水线,观察构建状态。

    运行成功效果如下:

    image.png

    您也可以查看日志来确定运行状态、排查问题等:

    image.png

  2. 部署Gray并验证。单击部署Gray阶段的手动触发按钮,开始部署。

    image.png

方式二:通过AppStack方式构建CI/CD流水

步骤一:在云效上创建应用并做好灰度配置

  1. 登录云效控制台,设置创建应用。进入应用首页,单击右上角新建应用(若已有则可忽略)。

  2. 单击新创建的应用。进入应用概览,选择部署编排 > 前往配置 > 选择 Kubernetes 部署 > 从模板开始 > 空模板,然后单击确定(若已有则可忽略)。

  3. 在Kubernetes部署中,创建应用发布流程(以A应用为例)。单击添加组件 > 输入名称(如spirng-cloud-a-deploy)> 空模板(若已有则可忽略)。

  4. 输入应用的YAML配置。

    一些关键的地方使用占位符取代。您可以参考以下代码部署A的Deployment(其中{{}}需要定义相应的变量,AppStack开头的表示云效预置占位符,Values开头的表示自定义占位符,可以在上方点击提取占位符后,在右边编辑占位符的值。值可以定义成常量,也可以从变量组中引用):

    apiVersion: apps/v1
    kind: Deployment
    metadata:
      name: {{ .AppStack.appName }}-{{ .AppStack.envName }}
      labels:
        run: {{ .AppStack.appName }}-{{ .AppStack.envName }}
      namespace: {{ .Values.namespace }}
    spec:
      selector:
        matchLabels:
          app: {{ .AppStack.appName }}-{{ .AppStack.envName }}
      template:
        metadata:
          labels:
            app: {{ .AppStack.appName }}-{{ .AppStack.envName }}
        spec:
          containers:
          - name: {{ .AppStack.appName }}
            image: {{ .AppStack.image.backend }}
            imagePullPolicy: Always
            ports:
              - containerPort: 20001
            livenessProbe:
              tcpSocket:
                port: 20001
              initialDelaySeconds: 30
              periodSeconds: 60
            env:
            - name: spring.cloud.nacos.discovery.server-addr
              value: 'nacos-server'
            - name: dubbo.registry.address
              value: 'nacos://nacos-server:8848'
  1. 在应用配置的spec.template.metadata.labels下加入MSE基本配置及灰度相关。

    msePilotCreateAppName: {{ .AppStack.appName }}
    msePilotAutoEnable: 'on'
    {{if eq .Values.mseGrayTag "gray" }}
    alicloud.service.tag: gray
    {{end}}
    说明
    • msePilotCreateAppName为MSE服务治理接入的应用名;msePilotAutoEnable为是否接入MSE服务治理的开关on表示开启,off表示关闭;alicloud.service.tag则是MSE用于灰度发布的节点标签。您可以在MSE服务治理控制台,节点详情页面看到节点的标签情况。更多信息,请参见ACK微服务应用接入MSE服务治理节点详情

    • 其中{{if eq .Values.mseGrayTag "gray" }}是基于GO template的方式识别当前云效发布的应用。环境变量中如果有mseGrayTag=gray的变量,则认定该应用属于灰度应用。更多信息,请参见Kubernetes 部署编排

  2. 在页面右上方,单击提取占位符。您可按需设置配置中的占位符。

    namespace设置成常量;填写default;mseGrayTag设置成变量,使用mseGrayTag。

  3. 单击保存

    保存时需要勾选可用的环境,建议全选。

    说明

    如果您使用本文中的示例A、B、C应用,则您都需要创建对应的应用,并做好相应的配置。

步骤二:在云效中加入灰度环境和灰度变量组

  1. 登录云效控制台,进入需要做灰度发布的应用(比如A和C,都需要做如下操作)。

  2. 在控制台左侧选择变量组,然后单击新建变量组,创建一个灰度环境变量组。保存后单击编辑变量,输入mseGrayTag=gray,然后保存并提交。

  3. 在控制台左侧选择环境,然后单击新建灰度环境。输入灰度环境的信息,在关联变量组一栏,单击添加关联,选中上一步创建的灰度环境变量组。

当应用通过云效发布到灰度环境时,会自动加入mseGrayTag=gray,并在我们的应用YAML中添加alicloud.service.tag: gray标签,这样就完成了灰度环境发布的应用,能够携带灰度标签alicloud.service.tag: gray

说明

如果您使用本文中的示例A、B、C应用,建议您除灰度环境和灰度变量组外,再创建其他环境和对应的变量组,以方便您的测试。但是需要明确的是,其他环境的变量组不应该添加变量mseGrayTag=gray

步骤三:使用云效AppStack研发流程进行应用灰度发布

如果您的云效菜单中没有研发流程变更按钮,您可以在创建应用后按以下步骤开启变更流程的功能:

image.png

开启后,您可以按照以下子步骤创建灰度环境发布流程并进行应用发布。

子步骤 1:新增灰度研发流程和变更信息

  1. 如果您尚未配置任何研发流程,请单击研发流程 > 前往配置,输入研发流程名称,选择Java k8s 应用标准研发流程模板,完成后进入第二步。如果您已存在一些研发配置,单击研发流程 > 研发流程设置 > 新建研发流程输入研发流程名称,选择Java k8s 应用标准研发流程模板,单击创建

    说明

    如果您使用本文中的示例A、B、C应用,您还需要在应用概览页面代码源设置中配置代码源。A、B、C应用源码可以从github上获取。更多内容,请参见mse-simple-demo

  2. 在上一步配置的研发流程中,选择生产阶段 > 编辑流水线。在合适的节点处(一般为生产环境部署之前),单击加号图标或者添加任务按钮添加灰度任务。

    image.png

  3. 在当前流程下方的变更集成方式中,选择运行固定分支,选择master分支(可按需设置)。

  4. 流水线配置完毕后,保存当前的流水线。

子步骤2:进行灰度发布

  1. 单击研发流程,选择上一步创建的灰度发布流程,然后单击运行

    image.png

  2. 当流程执行完毕后,查看您的集群是否已经启动了灰度应用。

    应用名称为步骤一:在云效上创建应用并做好灰度配置中配置的名称,格式为:应用名-环境名。

    image.png

子步骤3:发布生产环境

灰度验证通过后,即可继续发布生产环境。点击手动触发生产环境发布,查看生产发布批次,观测新老版本号,部署完成后观测生产监控日志。

image

image

子步骤4:销毁灰度环境

生产发布成功后,销毁灰度环境资源,所有流量都进入生产环境。

image

至此即完成了应用基线环境的准备、灰度流程配置、灰度发布验证、生产发布、灰度销毁完整流程。

其他参考

针对AppStack方式灰度发布,支持扩缩容和应用回滚。更多信息,请参见2.3 回滚。如果是Flow方式,则需要登录容器服务管理控制台进行相关操作。

验证全链路灰度是否生效

如果您启动的是您自己的灰度应用,则您可以考虑按照您的方式去做验证。如果您使用本文中示例的A、B、C应用程序,您可以按照一定的访问条件(比如携带特定的灰度header或query参数)直接访问MSE云原生网关,查看结果是否包含gray字样,包含则表明全链路灰度生效。如本文示例中配置的全链路灰度路由规则:请求参数中携带group=gray的去往灰度泳道。

image.png

发起符合条件的请求,则结果如下(A和C进行了灰度发布,B没有进行灰度发布,所以请求去往了B的基线环境)所示:

> curl -X GET http://47.96.XX.XXX/A/a?group=gray
Agray[192.168.110.161][config=base] -> B[192.168.110.14] -> Cgray[192.168.110.160]

如果请求条件不符合条件,则去往A、B、C的基线环境:

> curl -X GET http://47.96.XX.XXX/A/a?group=xxx
A[192.168.110.162][config=base] -> B[192.168.110.57] -> C[192.168.110.62]

您还可以在MSE控制台上看到刚刚发起的灰度请求:

image.png

相关文档

通过云效AppStack和MSE微服务引擎实现灰度发布的具体内容,请参见MSE+云效AppStack实现应用服务全链路灰度