当您需要在多个服务间实现全链路的灰度发布时,可以通过配置TrafficLabel来识别流量特征,将网关入口流量分为正常流量和灰度流量。灰度流量特征会在请求调用链经过的各个服务间进行传递,从而实现全链路灰度发布。本文介绍如何通过TrafficLabel能力来实现微服务的全链路灰度发布。
前提条件
- 已创建ASM企业版或旗舰版实例,且版本为v1.10.5.40及以上。具体操作,请参见创建ASM实例。
- 已创建Kubernetes托管版集群。具体操作,请参见创建Kubernetes托管版集群。
- 已添加集群到ASM实例。具体操作,请参见添加集群到ASM实例。
- 已在ASM实例启用链路追踪。具体操作,请参见创建ASM实例或编辑ASM实例。
- 已创建ASM网关。具体操作,请参见创建入口网关服务。
- 已在ACK集群下开启应用监控。具体操作,请参见应用性能监控。说明 本文示例应用通过Java Agent方式对接ARMS,若非Java的其他多语言应用需要对接ARMS,请参见应用监控接入概述。
- 已通过kubectl连接ACK集群。具体操作,请参见获取集群KubeConfig并通过kubectl工具连接集群。
- 已通过kubectl连接ASM集群。具体操作,请参见通过控制面kubectl访问Istio资源。
背景信息
灰度发布有多种实现方式,例如基于ASM完成蓝绿和灰度发布。该灰度方式偏重于单个服务的发布,通过使用Istio原生提供的VirtualService标签路由和权重分流进行实现。

这种情况下对业务进行功能灰度验证:入口流量分为正常流量和灰度流量。User服务需要对请求流量做流量特征识别,若是灰度流量则需要请求灰度的Cart。该场景不再是简单的按流量比例灰度分发到后端不同的版本,而且灰度流量特征会在请求调用链经过的各个服务间进行传递。
ASM全链路灰度功能基于流量打标和标签路由功能。更多信息,请参见流量打标和标签路由。
Demo介绍
您可以单击文件,直接下载Demo示例编排及相关配置。
Demo的架构图如下:

apiVersion: v1
kind: Service
metadata:
name: spring-boot-istio-client
spec:
type: ClusterIP
ports:
- name: http
port: 80
targetPort: 19090
selector:
app: spring-boot-istio-client
---
apiVersion: apps/v1
kind: Deployment
metadata:
name: spring-boot-istio-client
spec:
replicas: 2
selector:
matchLabels:
app: spring-boot-istio-client
version: base
template:
metadata:
annotations:
armsPilotAutoEnable: 'on'
armsPilotCreateAppName: spring-boot-istio-client
labels:
app: spring-boot-istio-client
version: base
spec:
containers:
- name: spring-boot-istio-client
image: registry.cn-hangzhou.aliyuncs.com/aliacs-app-catalog/spring-boot-istio-client:Abase
imagePullPolicy: Always
tty: true
ports:
- name: http
protocol: TCP
containerPort: 19090
---
apiVersion: v1
kind: Service
metadata:
name: spring-boot-istio-server
spec:
type: ClusterIP
ports:
- name: http
port: 18080
targetPort: 18080
- name: grpc
port: 18888
targetPort: 18888
selector:
app: spring-boot-istio-server
---
apiVersion: apps/v1
kind: Deployment
metadata:
name: spring-boot-istio-server
spec:
replicas: 2
selector:
matchLabels:
app: spring-boot-istio-server
version: base
template:
metadata:
annotations:
armsPilotAutoEnable: 'on'
armsPilotCreateAppName: spring-boot-istio-server
labels:
app: spring-boot-istio-server
version: base
spec:
containers:
- name: spring-boot-istio-server
image: registry.cn-hangzhou.aliyuncs.com/aliacs-app-catalog/spring-boot-istio-server:Bbase
imagePullPolicy: Always
tty: true
ports:
- name: http
protocol: TCP
containerPort: 18080
- name: grpc
protocol: TCP
containerPort: 18888
---
apiVersion: apps/v1
kind: Deployment
metadata:
name: spring-boot-istio-client-gray
spec:
replicas: 2
selector:
matchLabels:
app: spring-boot-istio-client
version: gray
template:
metadata:
annotations:
armsPilotAutoEnable: 'on'
armsPilotCreateAppName: spring-boot-istio-client
labels:
app: spring-boot-istio-client
version: gray
spec:
containers:
- name: spring-boot-istio-client
image: registry.cn-hangzhou.aliyuncs.com/aliacs-app-catalog/spring-boot-istio-client:Agray
imagePullPolicy: Always
tty: true
ports:
- name: http
protocol: TCP
containerPort: 19090
---
apiVersion: apps/v1
kind: Deployment
metadata:
name: spring-boot-istio-server-gray
spec:
replicas: 2
selector:
matchLabels:
app: spring-boot-istio-server
version: gray
template:
metadata:
annotations:
armsPilotAutoEnable: 'on'
armsPilotCreateAppName: spring-boot-istio-server
labels:
app: spring-boot-istio-server
version: gray
spec:
containers:
- name: spring-boot-istio-server
image: registry.cn-hangzhou.aliyuncs.com/aliacs-app-catalog/spring-boot-istio-server:Bgray
imagePullPolicy: Always
tty: true
ports:
- name: http
protocol: TCP
containerPort: 18080
- name: grpc
protocol: TCP
containerPort: 18888
本示例服务中的应用都是SpringBoot的Java应用,且开启了ARMS应用监控。具体操作,请参见应用性能监控 。template.metadata
配置示例如下。 template:
metadata:
annotations:
armsPilotAutoEnable: 'on'
armsPilotCreateAppName: spring-boot-istio-server
步骤一:在ACK集群下部署Demo微服务
kubectl apply -f demo.yaml
步骤二:配置简单路由
- 使用以下内容,创建名为istio-config.yaml的文件。
apiVersion: networking.istio.io/v1beta1 kind: Gateway metadata: name: simple-springboot-gateway spec: selector: istio: ingressgateway servers: - hosts: - "*" port: name: http number: 80 protocol: HTTP --- apiVersion: networking.istio.io/v1beta1 kind: VirtualService metadata: name: springboot-istio-client-vs spec: gateways: - simple-springboot-gateway hosts: - "*" http: - match: - uri: prefix: "/hello" route: - destination: host: spring-boot-istio-client --- apiVersion: networking.istio.io/v1beta1 kind: VirtualService metadata: name: springboot-istio-server-vs spec: hosts: - spring-boot-istio-server http: - route: - destination: host: spring-boot-istio-server --- apiVersion: networking.istio.io/v1beta1 kind: DestinationRule metadata: name: springboot-istio-client-dr spec: host: spring-boot-istio-client trafficPolicy: loadBalancer: simple: ROUND_ROBIN subsets: - labels: version: base name: version-base - labels: version: gray name: version-gray --- apiVersion: networking.istio.io/v1beta1 kind: DestinationRule metadata: name: springboot-istio-server-dr spec: host: spring-boot-istio-server trafficPolicy: loadBalancer: simple: ROUND_ROBIN subsets: - labels: version: base name: version-base - labels: version: gray name: version-gray
- 执行以下命令,配置路由。
kubectl --kubeconfig <ASM实例的kubeconfig文件> apply -f istio-config.yaml
- 验证服务访问是否可以连通。
步骤三:配置TrafficLabel
- 使用以下内容,创建文件traffic_label_default.yaml。
--- apiVersion: istio.alibabacloud.com/v1beta1 kind: TrafficLabel metadata: name: example1 namespace: default spec: rules: - labels: - name: userdefinelabel1 valueFrom: - $getContext(x-b3-traceid) - $localLabel attachTo: - opentracing # 表示生效的协议,空为都不生效,*为都生效。 protocols: "*" hosts: # 表示生效的服务。 - "*" --- apiVersion: istio.alibabacloud.com/v1beta1 kind: TrafficLabel metadata: name: ingressgateway namespace: istio-system spec: hosts: - '*' rules: - attachTo: - opentracing labels: - name: userdefinelabel1 valueFrom: - $getContext(x-b3-traceid) - $localLabel protocols: '*' workloadSelector: labels: app: istio-ingressgateway
说明apiVersion字段说明:- 若ASM实例版本为1.16及以上,支持使用
apiVersion: istio.alibabacloud.com/v1
。若您在ACK集群进行了相关配置,请将对应的TrafficLabel CRD中的apiVersion: istio.alibabacloud.com/v1beta1
修改为apiVersion: istio.alibabacloud.com/v1
,再重新进行部署。 - 若ASM实例版本为1.16以下,支持使用
apiVersion: istio.alibabacloud.com/v1beta1
。
- 若ASM实例版本为1.16及以上,支持使用
- 执行以下命令,使用ASM实例的kubeconfig进行部署。
kubectl --kubeconfig <ASM实例的kubeconfig文件> apply -f traffic_label_default.yaml
该TrafficLabel定义针对default下所有服务生效,也就是demo.yaml下部署的A和B服务。
说明 本示例Demo对接ARMS,采用zipkin trace类型的traceId
,因此getContext
参数为x-b3-traceid
。
步骤四:验证TrafficLabel路由
- 验证A→B是否符合预期,其中包括流向A的灰度流量打到灰度版本,以及Base流量打到Base版本。
配置B服务的TrafficLabel路由b-vs-tf.yaml,在A服务侧生效,对应如下模型:
- 验证ASM网关→A是否符合预期。配置A服务的TrafficLabel路由a-vs-tf.yaml,在ASM网关侧生效。预期结果为入口请求灰度流量打到A的灰度版本,Base流量打到A的Base版本,并传递到B服务。说明 ASM网关也支持TrafficLabel路由。
- 验证TrafficLabel路由对应的权重分流是否符合预期。
泳道模式(流量特征不传递)

此场景中,您只需修改TrafficLabel定义,去除$getContext(x-b3-traceid)
以关闭流量标签的传递。颜色标记从$localLabel
获取即可。
apiVersion: istio.alibabacloud.com/v1beta1
kind: TrafficLabel
metadata:
name: example1
namespace: default
spec:
rules:
- labels:
- name: userdefinelabel1
valueFrom:
- $localLabel
attachTo:
- opentracing
# 表示生效的协议,空为都不生效,*为都生效。
protocols: "*"
hosts: # 表示生效的服务。
- "*"
localLabel是从服务Deploymen下Pod的Label中获取流量标识,因此Demo例子下的Deployment需要添加Pod标签ASM_TRAFFIC_TAG: version-base
,例如:
template:
metadata:
annotations:
armsPilotAutoEnable: "on"
armsPilotCreateAppName: spring-boot-istio-client
creationTimestamp: null
labels:
ASM_TRAFFIC_TAG: version-base
app: spring-boot-istio-client
version: base
如果是Gray版本对应的Deployment,则需要添加ASM_TRAFFIC_TAG: version-gray
标签。
ASM网关侧的流量灰度
如上文中的a-vs-tf.yaml,配置入口流量<gatewayIP>/hello
接口的灰度,对入口请求有一定的要求:要求流量标识通过x-asm-prefer-tag
指定流量Tag,如上测试是curl -H 'x-asm-prefer-tag: xxx'
手动指定的。
实际业务场景下,客户端App或者真实用户通过浏览器访问未必会设置该Header,这种情形下,您可以通过ASM网关的自定义Header功能以及Lua插件的能力,将业务场景的灰度映射到x-asm-prefer-tag
Header,进行标准化处理。
EnvoyFilter
设置使用iPhone13的用户为灰度流量,示例如下。apiVersion: networking.istio.io/v1alpha3
kind: EnvoyFilter
metadata:
labels:
provider: "asm"
asm-system: "true"
name: gateway-lua-filter-add-x-asm-prefer-tag-header
namespace: istio-system
spec:
workloadSelector:
labels:
istio: ingressgateway
configPatches:
- applyTo: HTTP_FILTER
match:
proxy:
proxyVersion: "^1.*"
context: GATEWAY
listener:
filterChain:
filter:
name: "envoy.filters.network.http_connection_manager"
subFilter:
name: "envoy.filters.http.router"
patch:
operation: INSERT_BEFORE
value:
name: envoy.lua
typed_config:
"@type": "type.googleapis.com/envoy.extensions.filters.http.lua.v3.Lua"
inlineCode: |
function envoy_on_request(request_handle)
local user_agent = request_handle:headers():get("user-agent")
request_handle:logInfo("user_agent:"..user_agent)
if string.match(user_agent,"^.*iPhone13.*") then
request_handle:headers():add("x-asm-prefer-tag","version-gray")
else
request_handle:headers():add("x-asm-prefer-tag","version-base")
end
end
function envoy_on_response(response_handle)
end
FAQ
为什么全链路灰度功能没有生效?
全链路灰度功能生效的前提是应用的Trace能力生效,本文的SpringCloud服务采用ARMS无侵入方式接入Trace,若测试结果不符合预期,请确认是否正确开启了应用性能监控,您可以通过以下方式检查是否开启应用性能监控:

若您是在部署Demo服务后开启的应用性能监控,您需要在开启应用性能监控后,重新部署Demo服务。关于开启应用监控的具体操作,请参见应用性能监控。