概述
您可以基于微服务治理在不修改任何业务代码的情况下,实现全链路灰度的流量控制。本文介绍用户如何通过自建网关实现全链路灰度功能。
前提条件
1、用户已开通微服务治理中心企业版。
2、用户已开通云容器引擎。
背景信息
在微服务架构下,一次需求可能会同时修改多个微服务应用。在发布应用时,通常将这些应用划分为同一个分组,使灰度流量始终在灰度应用中流转。当上游有灰度流量时,会通过引流的方式将灰度流量引导至灰度分组,在此次链路调用过程中,如果存在一些微服务没有灰度环境,那这些请求在下游时依然能回到灰度环境中,以此实现全链路灰度。
通过使用微服务治理中心,可以在不修改业务代码的情况下,轻松实现全链路灰度。本文介绍如何通过自建网关实现全链路灰度。
部署Demo应用
准备自建入口网关msgc-zuul,准备应用msgc-app-a,msgc-app-b和msgc-app-c。调用过程是msgc-app-a –> msgc-app-b -> msgc-app-c。
步骤1:在云容器引擎集群中安装微服务治理插件:
- 登录云容器引擎控制台。
- 在左侧菜单栏选择集群,点击目标集群。
- 在集群管理页面点击插件-插件市场,选择cubems插件安装。
步骤2:为应用开启微服务治理能力:
- 登录云容器引擎控制台。
- 左侧菜单栏选择集群,点击目标集群。
- 在集群管理页面点击工作负载-无状态,选择目标命名空间。
-
在Deployment列表页选择指定Deployment,并点击全量替换,进入Deployment编辑页。
-
在Deployment编辑页点击显示高级设置,新增Pod标签: mseCubeMsAutoEnable:on。
-
在发布应用时,配置指定环境变量,可指定注入微服务治理中心的应用名、命名空间和标签等信息。
环境变量配置如下:
环境变量名 | 环境变量值 |
---|---|
MSE_APP_NAME | 接入到微服务治理中心的应用名。 |
MSE_SERVICE_TAG | 应用标签信息,如灰度应用可配置gray。 |
MSE_NAMESPACE(选填) | 接入到微服务治理中心的命名空间,默认为:default。 |
- 完成编辑后点击提交,重新发布容器即可接入。
app-a应用的配置:
基线:
apiVersion: "apps/v1"
kind: "Deployment"
metadata:
name: "app-a"
namespace: "default"
spec:
progressDeadlineSeconds: 600
replicas: 1
revisionHistoryLimit: 10
selector:
matchLabels:
name: "app-a"
template:
metadata:
labels:
mseCubeMsAutoEnable: "on"
name: "app-a"
spec:
containers:
- env:
- name: "MSE_APP_NAME"
value: "app-a"
image: "镜像仓库域名/xxx/app-a:latest"
imagePullPolicy: "Always"
name: "app-a"
ports:
- containerPort: 26160
livenessProbe:
tcpSocket:
port: 26160
initialDelaySeconds: 10
periodSeconds: 30
resources:
limits:
cpu: "1"
memory: "1Gi"
requests:
cpu: "1"
memory: "1Gi"
灰度:
apiVersion: "apps/v1"
kind: "Deployment"
metadata:
name: "app-a"
namespace: "default"
spec:
progressDeadlineSeconds: 600
replicas: 1
revisionHistoryLimit: 10
selector:
matchLabels:
name: "app-a"
template:
metadata:
labels:
mseCubeMsAutoEnable: "on"
name: "app-a"
spec:
containers:
- env:
- name: "MSE_APP_NAME"
value: "app-a"
- name: "MSE_SERVICE_TAG"
value: "gray"
image: "镜像仓库域名/xxx/app-a:latest"
imagePullPolicy: "Always"
name: "app-a"
ports:
- containerPort: 26160
livenessProbe:
tcpSocket:
port: 26160
initialDelaySeconds: 10
periodSeconds: 30
resources:
limits:
cpu: "1"
memory: "1Gi"
requests:
cpu: "1"
memory: "1Gi"
app-b应用的配置:
基线:
apiVersion: "apps/v1"
kind: "Deployment"
metadata:
name: "app-b"
namespace: "default"
spec:
progressDeadlineSeconds: 600
replicas: 1
revisionHistoryLimit: 10
selector:
matchLabels:
name: "app-b"
template:
metadata:
labels:
mseCubeMsAutoEnable: "on"
name: "app-b"
spec:
containers:
- env:
- name: "MSE_APP_NAME"
value: "app-b"
image: "镜像仓库域名/xxx/app-b:latest"
imagePullPolicy: "Always"
name: "app-b"
ports:
- containerPort: 26160
livenessProbe:
tcpSocket:
port: 26160
initialDelaySeconds: 10
periodSeconds: 30
resources:
limits:
cpu: "1"
memory: "1Gi"
requests:
cpu: "1"
memory: "1Gi"
灰度:
apiVersion: "apps/v1"
kind: "Deployment"
metadata:
name: "app-b"
namespace: "default"
spec:
progressDeadlineSeconds: 600
replicas: 1
revisionHistoryLimit: 10
selector:
matchLabels:
name: "app-b"
template:
metadata:
labels:
mseCubeMsAutoEnable: "on"
name: "app-b"
spec:
containers:
- env:
- name: "MSE_APP_NAME"
value: "app-b"
- name: "MSE_SERVICE_TAG"
value: "gray"
image: "镜像仓库域名/xxx/app-b:latest"
imagePullPolicy: "Always"
name: "app-b"
ports:
- containerPort: 26160
livenessProbe:
tcpSocket:
port: 26160
initialDelaySeconds: 10
periodSeconds: 30
resources:
limits:
cpu: "1"
memory: "1Gi"
requests:
cpu: "1"
memory: "1Gi"
app-c应用的配置:
基线:
apiVersion: "apps/v1"
kind: "Deployment"
metadata:
name: "app-c"
namespace: "default"
spec:
progressDeadlineSeconds: 600
replicas: 1
revisionHistoryLimit: 10
selector:
matchLabels:
name: "app-c"
template:
metadata:
labels:
mseCubeMsAutoEnable: "on"
name: "app-c"
spec:
containers:
- env:
- name: "MSE_APP_NAME"
value: "app-c"
image: "镜像仓库域名/xxx/app-c:latest"
imagePullPolicy: "Always"
name: "app-c"
ports:
- containerPort: 26160
livenessProbe:
tcpSocket:
port: 26160
initialDelaySeconds: 10
periodSeconds: 30
resources:
limits:
cpu: "1"
memory: "1Gi"
requests:
cpu: "1"
memory: "1Gi"
灰度:
apiVersion: "apps/v1"
kind: "Deployment"
metadata:
name: "app-c"
namespace: "default"
spec:
progressDeadlineSeconds: 600
replicas: 1
revisionHistoryLimit: 10
selector:
matchLabels:
name: "app-c"
template:
metadata:
labels:
mseCubeMsAutoEnable: "on"
name: "app-c"
spec:
containers:
- env:
- name: "MSE_APP_NAME"
value: "app-c"
- name: "MSE_SERVICE_TAG"
value: "gray"
image: "镜像仓库域名/xxx/app-c:latest"
imagePullPolicy: "Always"
name: "app-c"
ports:
- containerPort: 26160
livenessProbe:
tcpSocket:
port: 26160
initialDelaySeconds: 10
periodSeconds: 30
resources:
limits:
cpu: "1"
memory: "1Gi"
requests:
cpu: "1"
memory: "1Gi"
zuul应用的配置:
apiVersion: "apps/v1"
kind: "Deployment"
metadata:
name: "zuul"
namespace: "default"
spec:
progressDeadlineSeconds: 600
replicas: 1
revisionHistoryLimit: 10
selector:
matchLabels:
name: "zuul"
template:
metadata:
labels:
mseCubeMsAutoEnable: "on"
name: "zuul"
spec:
containers:
- env:
- name: "MSE_APP_NAME"
value: "zuul"
image: "镜像仓库域名/xxx/zuul:latest"
imagePullPolicy: "Always"
name: "zuul"
ports:
- containerPort: 26160
livenessProbe:
tcpSocket:
port: 26160
initialDelaySeconds: 10
periodSeconds: 30
resources:
limits:
cpu: "1"
memory: "1Gi"
requests:
cpu: "1"
memory: "1Gi"
创建泳道组及灰度泳道
step1:创建泳道组
- 登录微服务治理控制台。
- 在左侧导航栏选择全链路灰度,点击创建泳道组。
- 在创建泳道组页面,设置泳道组相关参数,然后单击确定。
step2:创建泳道
- 找到目标泳道组页面,点击创建第一个分流泳道。
- 设置泳道名称,选择目标应用所属标签,创建泳道。
场景应用及验证:通过设置泳道组路由规则,实现全链路灰度
step1:设置Header路由规则
设置路由规则,通过前端访问传过来不同的Header,在自建网关通过header判断将流量路由到指定的泳道。
step2:通过Header验证灰度流量
通过自建网关访问app-a->app-b->app-c。
- 访问基线环境,不带上参数名为tag的header,流量路由到基线环境。
curl http://localhost/a/callA
- 访问灰度环境,带上tag=gray的header,流量会自动路由到灰度泳道。
curl –H“tag:gray”http://localhost/a/callA
基于上述实践,可以看到,当前端请求带上tag=gray的header时,会路由到灰度环境。
step3:通过设置Parameter实现标签路由
路由规则除了设置Header以外,还可以通过设置Cookie、Parameter和Body Content实现流量路由。
设置路由规则,通过前端访问传过来不同的Parameter,在自建网关通过Parameter判断将流量路由到指定的泳道。
step4:通过Parameter验证灰度流量
通过自建网关访问app-a->app-b->app-c。
- 访问基线环境,当member不等于12345时,流量路由到基线环境。
curl http://localhost/a/callA?memberId=123
- 访问灰度环境,带上memberId=12345的参数,流量会自动路由到灰度泳道。
curl http://localhost/a/callA?memberId=12345
基于上述实践,可以看到,当前端请求带上memberId=12345的参数,会路由到灰度环境。