Article / 文章中心

深入剖析全链路灰度技术内幕(3)

发布时间:2021-12-16 点击数:177
04

从 0 到 1 实践全链路灰度

Cloud Native



看到这里,相信大多数读者对全链路灰度有了大概的认识,也了解了几种解决方案以及实现细节。接下来,我们会基于文中提到的 MSE 云原生网关和 MSE 服务治理产品,从 0 到 1 对全链路灰度进行实践,一方面加深对全链路灰度的认识,另一方面可以了解下阿里云是如何将阿里巴巴内部的最佳实践输出到云产品中。


我们假设应用的架构由 MSE 云原生网关以及后端的微服务架构(Spring Cloud)来组成,后端调用链路有 3 跳,购物车(a),交易中心(b),库存中心(c),通过客户端或者是 H5 页面来访问后端服务,它们通过 Nacos 注册中心做服务发现。现在希望使用全链路灰度能力构建一个灰度环境,方便对服务 A 和服务 C 同时进行灰度验证。


MSE 云原生网关

1
前提条件


必备的资源列表


  • 已拥有一个 MSE 云原生网关
  • 已拥有一个 MSE Nacos 注册中心
  • 已拥有一个 ACK 运维集群
  • 已开通 MSE 微服务治理专业版

部署 Demo 应用程序


将下面的文件保存到 ingress-gray.yaml 中,并执行 kubectl apply -f ingress-gray.yaml 以部署应用,这里我们将要部署 A,B,C 三个应用,A 和 C 应用分别部署一个基线版本和一个灰度版本,B 应用部署一个基线版本。


有以下注意点:
  1. 全链路灰度能力是与注册中心无关的,本文用例暂以 MSE Nacos 作为注册中心,所以需要将 spring.cloud.nacos.discovery.server-addr 换成业务自己的 Nacos 注册中心地址
  2. 接入云原生网关的服务,如果需要使用灰度发布,需要在发布服务时在元数据信息增加版本标。在我们的例子,服务 A 是需要暴露给网关,所以发布时为基线版本添加spring.cloud.nacos.discovery.metadata.version=base,为灰度版本添加 spring.cloud.nacos.discovery.metadata.version=gray。

# A 应用 base 版本---apiVersion: apps/v1kind: Deploymentmetadata: labels: app: spring-cloud-a name: spring-cloud-aspec: replicas: 2 selector: matchLabels: app: spring-cloud-a template: metadata: annotations: msePilotCreateAppName: spring-cloud-a labels: app: spring-cloud-a spec: containers: - env: - name: LANG value: C.UTF-8 - name: JAVA_HOME value: /usr/lib/jvm/java-1.8-openjdk/jre - name: spring.cloud.nacos.discovery.server-addr value: mse-455e0c20-nacos-ans.mse.aliyuncs.com:8848 - name: spring.cloud.nacos.discovery.metadata.version value: base image: registry.cn-shanghai.aliyuncs.com/yizhan/spring-cloud-a:0.1-SNAPSHOT imagePullPolicy: Always name: spring-cloud-a ports: - containerPort: 20001 protocol: TCP resources: requests: cpu: 250m memory: 512Mi # A 应用 gray 版本--- apiVersion: apps/v1kind: Deploymentmetadata: labels: app: spring-cloud-a-new name: spring-cloud-a-newspec: replicas: 2 selector: matchLabels: app: spring-cloud-a-new strategy: template: metadata: annotations: alicloud.service.tag: gray msePilotCreateAppName: spring-cloud-a labels: app: spring-cloud-a-new spec: containers: - env: - name: LANG value: C.UTF-8 - name: JAVA_HOME value: /usr/lib/jvm/java-1.8-openjdk/jre - name: profiler.micro.service.tag.trace.enable value: "true" - name: spring.cloud.nacos.discovery.server-addr value: mse-455e0c20-nacos-ans.mse.aliyuncs.com:8848 - name: spring.cloud.nacos.discovery.metadata.version value: gray image: registry.cn-shanghai.aliyuncs.com/yizhan/spring-cloud-a:0.1-SNAPSHOT imagePullPolicy: Always name: spring-cloud-a-new ports: - containerPort: 20001 protocol: TCP resources: requests: cpu: 250m memory: 512Mi # B 应用 base 版本---apiVersion: apps/v1kind: Deploymentmetadata: labels: app: spring-cloud-b name: spring-cloud-bspec: replicas: 2 selector: matchLabels: app: spring-cloud-b strategy: template: metadata: annotations: msePilotCreateAppName: spring-cloud-b labels: app: spring-cloud-b spec: containers: - env: - name: LANG value: C.UTF-8 - name: JAVA_HOME value: /usr/lib/jvm/java-1.8-openjdk/jre - name: spring.cloud.nacos.discovery.server-addr value: mse-455e0c20-nacos-ans.mse.aliyuncs.com:8848 image: registry.cn-shanghai.aliyuncs.com/yizhan/spring-cloud-b:0.2-demo-SNAPSHOT  imagePullPolicy: Always name: spring-cloud-b ports: - containerPort: 8080 protocol: TCP resources: requests: cpu: 250m memory: 512Mi # C 应用 base 版本---apiVersion: apps/v1kind: Deploymentmetadata: labels: app: spring-cloud-c name: spring-cloud-cspec: replicas: 2 selector: matchLabels: app: spring-cloud-c template: metadata: annotations: msePilotCreateAppName: spring-cloud-c labels: app: spring-cloud-c spec: containers: - env: - name: LANG value: C.UTF-8 - name: JAVA_HOME value: /usr/lib/jvm/java-1.8-openjdk/jre - name: spring.cloud.nacos.discovery.server-addr value: mse-455e0c20-nacos-ans.mse.aliyuncs.com:8848 image: registry.cn-shanghai.aliyuncs.com/yizhan/spring-cloud-c:0.2-demo-SNAPSHOT imagePullPolicy: Always name: spring-cloud-c ports: - containerPort: 8080 protocol: TCP resources: requests: cpu: 250m memory: 512Mi # C 应用 gray 版本---apiVersion: apps/v1kind: Deploymentmetadata: labels: app: spring-cloud-c-new name: spring-cloud-c-newspec: replicas: 2 selector: matchLabels: app: spring-cloud-c-new template: metadata: annotations: alicloud.service.tag: gray msePilotCreateAppName: spring-cloud-c labels: app: spring-cloud-c-new spec: containers: - env: - name: LANG value: C.UTF-8 - name: JAVA_HOME value: /usr/lib/jvm/java-1.8-openjdk/jre - name: spring.cloud.nacos.discovery.server-addr value: mse-455e0c20-nacos-ans.mse.aliyuncs.com:8848 image: registry.cn-shanghai.aliyuncs.com/yizhan/spring-cloud-c:0.2-demo-SNAPSHOT imagePullPolicy: Always name: spring-cloud-c-new ports: - containerPort: 8080 protocol: TCP resources: requests: cpu: 250m memory: 512Mi

完成云原生网关初步配置


第一步,为云原生网关添加 Nacos 服务来源,服务管理,来源管理,点击创建来源,

云原生网关初步配置

选择 MSE Nacos 服务来源,选择需要关联的 Nacos 注册中心,点击确定。

Nacos 注册中心


第二步,导入要通过云原生网关暴露给外部的服务。选择服务管理,服务列表,点击创建服务。

选择服务来源为 MSE Nacos,选择服务 sc-A。

创建sc-A服务

点击服务 A 的策略配置,为入口服务 A 创建多版本,版本划分依据服务注册时所带的元数据信息 version(注意,这里可以是任意可以区分服务版本的标签值,取决于用户注册服务时所采用的元数据信息),创建以下两个版本 base 和 gray。

base 和 gray


2
路由配置

创建基线环境的路由匹配规则,关联域名 base.example.com,路由到服务 sc-A 的 base 版本中。


创建基线环境


创建灰度环境的路由匹配规则,关联的域名与基线环境保持一致,注意此处增加了请求头相关的配置,并且路由的目标服务为服务 sc-A 的 gray 版本。

创建灰度环境


这时,我们有了如下两条路由规则,

路由规则



此时,访问
base.example.com 路由到基线环境
curl -H "Host: base.example.com" http://118.31.118.69/aA[172.21.240.105] -> B[172.21.240.106] -> C[172.21.240.46]

如何访问灰度环境呢?只需要在请求中增加一个 header x-mse-tag: gray 即可。
	
									
									
curl -H "Host: base.example.com" -H "x-mse-tag: gray" http://118.31.118.69/aAgray[172.21.240.44] -> B[172.21.240.146] -> Cgray[172.21.240.147]

可以看到 云原生网关 将灰度流量路由到了 A 和 C 的灰度版本,由于B没有指定的灰度版本,所以流量自动回退到基线版本。
3
分析

从上面可以看出,我们只需要开通 MSE 微服务治理专业版,在云原生网关配置入口服务的路由规则,并且对入口流量进行灰度染色,即可满足我们对 A 和 C 全链路灰度的要求。另外还有一个很重要的点是,业务需要自行对节点打标并对入口服务开启链路传递。为 Pod 模板的 Annotations添加 alicloud.service.tag 键值对完成节点打标,Java Agent 会在业务向注册中心时登记节点时自动为其添加这个元数据信息,同时需要为入口服务的业务容器添加环境变量 profiler.micro.service.tag.trace.enable=true 开启链路传递灰度标识。MSE 服务治理组件默认使用 x-mse-tag 来标识流量,并在整个调用链路中传递。


另外,您可以设置其他自定义或业务已有的字段来标识流量,更多详情操作、场景展示参考文档:https://help.aliyun.com/document_detail/359851.html


05

总结

Cloud Native


本文从单体架构向微服务架构演进过程中带来的挑战展开,着重对其子领域服务发布在单体架构和微服务架构体系下的形态进行分析,引出了分布式应用场景中特有的全链路灰度问题。针对业务对全链路能力的要求,介绍了基于物理环境隔离和基于逻辑环境隔离两种方案,其中对基于逻辑环境隔离方案进行详细分析,对涉及到的各个技术点也进行了很好的解释,接着提出了三种基于逻辑环境隔离的落地方案,并进行了简单的对比分析,最后引出了阿里云 MSE 云原生、MSE 服务治理和服务网格 ASM 是如何提供不限于全链路灰度的流量治理能力。


# A 应用 base 版本---apiVersion: apps/v1kind: Deploymentmetadata: labels: app: spring-cloud-a name: spring-cloud-aspec: replicas: 2 selector: matchLabels: app: spring-cloud-a template: metadata: annotations: msePilotCreateAppName: spring-cloud-a labels: app: spring-cloud-a spec: containers: - env: - name: LANG value: C.UTF-8 - name: JAVA_HOME value: /usr/lib/jvm/java-1.8-openjdk/jre - name: spring.cloud.nacos.discovery.server-addr value: mse-455e0c20-nacos-ans.mse.aliyuncs.com:8848 - name: spring.cloud.nacos.discovery.metadata.version value: base image: registry.cn-shanghai.aliyuncs.com/yizhan/spring-cloud-a:0.1-SNAPSHOT imagePullPolicy: Always name: spring-cloud-a ports: - containerPort: 20001 protocol: TCP resources: requests: cpu: 250m memory: 512Mi # A 应用 gray 版本--- apiVersion: apps/v1kind: Deploymentmetadata: labels: app: spring-cloud-a-new name: spring-cloud-a-newspec: replicas: 2 selector: matchLabels: app: spring-cloud-a-new strategy: template: metadata: annotations: alicloud.service.tag: gray msePilotCreateAppName: spring-cloud-a labels: app: spring-cloud-a-new spec: containers: - env: - name: LANG value: C.UTF-8 - name: JAVA_HOME value: /usr/lib/jvm/java-1.8-openjdk/jre - name: profiler.micro.service.tag.trace.enable value: "true" - name: spring.cloud.nacos.discovery.server-addr value: mse-455e0c20-nacos-ans.mse.aliyuncs.com:8848 - name: spring.cloud.nacos.discovery.metadata.version value: gray image: registry.cn-shanghai.aliyuncs.com/yizhan/spring-cloud-a:0.1-SNAPSHOT imagePullPolicy: Always name: spring-cloud-a-new ports: - containerPort: 20001 protocol: TCP resources: requests: cpu: 250m memory: 512Mi # B 应用 base 版本---apiVersion: apps/v1kind: Deploymentmetadata: labels: app: spring-cloud-b name: spring-cloud-bspec: replicas: 2 selector: matchLabels: app: spring-cloud-b strategy: template: metadata: annotations: msePilotCreateAppName: spring-cloud-b labels: app: spring-cloud-b spec: containers: - env: - name: LANG value: C.UTF-8 - name: JAVA_HOME value: /usr/lib/jvm/java-1.8-openjdk/jre - name: spring.cloud.nacos.discovery.server-addr value: mse-455e0c20-nacos-ans.mse.aliyuncs.com:8848 image: registry.cn-shanghai.aliyuncs.com/yizhan/spring-cloud-b:0.2-demo-SNAPSHOT  imagePullPolicy: Always name: spring-cloud-b ports: - containerPort: 8080 protocol: TCP resources: requests: cpu: 250m memory: 512Mi # C 应用 base 版本---apiVersion: apps/v1kind: Deploymentmetadata: labels: app: spring-cloud-c name: spring-cloud-cspec: replicas: 2 selector: matchLabels: app: spring-cloud-c template: metadata: annotations: msePilotCreateAppName: spring-cloud-c labels: app: spring-cloud-c spec: containers: - env: - name: LANG value: C.UTF-8 - name: JAVA_HOME value: /usr/lib/jvm/java-1.8-openjdk/jre - name: spring.cloud.nacos.discovery.server-addr value: mse-455e0c20-nacos-ans.mse.aliyuncs.com:8848 image: registry.cn-shanghai.aliyuncs.com/yizhan/spring-cloud-c:0.2-demo-SNAPSHOT imagePullPolicy: Always name: spring-cloud-c ports: - containerPort: 8080 protocol: TCP resources: requests: cpu: 250m memory: 512Mi # C 应用 gray 版本---apiVersion: apps/v1kind: Deploymentmetadata: labels: app: spring-cloud-c-new name: spring-cloud-c-newspec: replicas: 2 selector: matchLabels: app: spring-cloud-c-new template: metadata: annotations: alicloud.service.tag: gray msePilotCreateAppName: spring-cloud-c labels: app: spring-cloud-c-new spec: containers: - env: - name: LANG value: C.UTF-8 - name: JAVA_HOME value: /usr/lib/jvm/java-1.8-openjdk/jre - name: spring.cloud.nacos.discovery.server-addr value: mse-455e0c20-nacos-ans.mse.aliyuncs.com:8848 image: registry.cn-shanghai.aliyuncs.com/yizhan/spring-cloud-c:0.2-demo-SNAPSHOT imagePullPolicy: Always name: spring-cloud-c-new ports: - containerPort: 8080 protocol: TCP resources: requests: cpu: 250m memory: 512Mi