深入剖析全链路灰度技术内幕(3)
从 0 到 1 实践全链路灰度
Cloud Native
前提条件
必备的资源列表
- 已拥有一个 MSE 云原生网关
- 已拥有一个 MSE Nacos 注册中心
- 已拥有一个 ACK 运维集群
- 已开通 MSE 微服务治理专业版
部署 Demo 应用程序
将下面的文件保存到 ingress-gray.yaml 中,并执行 kubectl apply -f ingress-gray.yaml 以部署应用,这里我们将要部署 A,B,C 三个应用,A 和 C 应用分别部署一个基线版本和一个灰度版本,B 应用部署一个基线版本。
-
全链路灰度能力是与注册中心无关的,本文用例暂以 MSE Nacos 作为注册中心,所以需要将 spring.cloud.nacos.discovery.server-addr 换成业务自己的 Nacos 注册中心地址
- 接入云原生网关的服务,如果需要使用灰度发布,需要在发布服务时在元数据信息增加版本标。在我们的例子,服务 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: 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: 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,选择服务 sc-A。
点击服务 A 的策略配置,为入口服务 A 创建多版本,版本划分依据服务注册时所带的元数据信息 version(注意,这里可以是任意可以区分服务版本的标签值,取决于用户注册服务时所采用的元数据信息),创建以下两个版本 base 和 gray。
路由配置
创建基线环境的路由匹配规则,关联域名 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 来标识流量,并在整个调用链路中传递。
总结
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: 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: 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