在服务网格ASM中,流量标签是指将流量进行标记以便进行更细致的流量控制和管理。通过为应用服务之间的流量请求打上特定的标签,可以将它们划分到不同的服务或者版本中,并根据标签来进行流量控制、熔断降级、限流等操作。
服务网格ASM新增扩展了流量标签TrafficLabel 自定义资源CRD。 通过该CRD定义具体的流量标签逻辑,实现为命名空间、工作负载进行设置流量标签。
TrafficLabel 定义说明
- 若ASM实例版本为1.17或以上,支持使用apiVersion: istio.alibabacloud.com/v1。若您在ACK集群进行了相关配置,请将对应的TrafficLabel CRD中的apiVersion: istio.alibabacloud.com/v1beta1修改为apiVersion: istio.alibabacloud.com/v1,再重新进行部署。
- 若ASM实例版本为1.17之前的版本,建议升级到1.17版本, 或提交工单获得支持。
例如, 在1.17或以上版本中使用如下参数定义:
apiVersion: istio.alibabacloud.com/v1
kind: TrafficLabel
metadata:
name: example
namespace: default
spec:
workloadSelector:
labels:
app: httpbin
rules:
- labels:
- name: asm-labels-test
valueFrom:
- $getLabel(ASM_TRAFFIC_TAG)
版本1.17或更新版本
如果ASM实例版本升级为1.17或以上,使用apiVersion: istio.alibabacloud.com/v1。
apiVersion: istio.alibabacloud.com/v1
kind: TrafficLabel
metadata:
name: example
namespace: default
spec:
workloadSelector:
labels:
app: httpbin
rules:
- labels:
- name: asm-labels-test-a
valueFrom:
- $getInboundRequestHeader(headerName)
- $getExternalInboundRequestHeader(contextId, headerName)
- $getLocalOutboundRequestHeader(headerName)
- $getLabel(labelName)
Spec定义说明
字段 | 类型 | 描述 | 是否必须 |
---|---|---|---|
workloadSelector | WorkloadSelector | 表示作用于的工作负载范围。选择器决定在哪里应用该流量标签。如果未设置,选择器将匹配当前命名空间下的所有工作负载。 | 否 |
rules | []TrafficLabelRule | 表示设置标签的规则描述 | 是 |
WorkloadSelector 属性字段
字段 | 类型 | 描述 | 是否必须 |
---|---|---|---|
labels | map《string, string》 | 一个或多个标签,表示应在其上应用流量标签 | 否 |
TrafficLabelRule 属性字段
字段 | 类型 | 描述 | 是否必须 |
---|---|---|---|
labels | []Label | 表示要设置的标签名称与值 | 是 |
Label 属性字段
字段 | 类型 | 描述 | 是否必须 |
---|---|---|---|
name | string | 标签名称, 符合http 请求头的命名规范 | 是 |
valueFrom | []string | 标签值。 valueFrom的参数值采用自然顺序的优先级, 优先从第一行获取标签值,当获取不到时才会从第二行获取标签值, 以此类推。具体说明参见下面的valueFrom 属性值定义。 | 是 |
valueFrom 属性值定义
支持 $getInboundRequestHeader(headerName)、$getExternalInboundRequestHeader(headerName, contextId)、$getLocalOutboundRequestHeader(headerName)、$getLabel(labelName) 4种变量。
简要说明如下:
变量定义 | 支持的工作负载类型 | 描述 |
---|---|---|
$getInboundRequestHeader(headerName) | 网关 | 从进入网关的请求头中获取名称为headerName的标头值 |
$getExternalInboundRequestHeader(headerName, contextId) | Sidecar代理 | 从进入Sidecar代理的请求中获取名称为headerName的标头值 |
$getLocalOutboundRequestHeader(headerName) | Sidecar代理 | 从由应用服务发出至Sidecar代理的请求中获取名称为headerName的标头值 |
$getLabel(labelName) | 网关或者Sidecar代理 | 从网关Pod/Sidecar容器所属Pod的标签中获取名称为labelName的标签值 |
详细说明如下:
$getInboundRequestHeader(headerName)
$getInboundRequestHeader(headerName)是个函数型变量,需要从出口请求头中获取,其中参数headerName是指请求头的关键字key。如果参数值为空, 默认为x-asm-prefer-tag。
说明 仅针网关生效, 对于对Sidecar代理不生效。
对于入口网关来说, 如下图所示,会为出口请求中附加1个新请求头:
- 名称为流量标签TrafficLabel CRD中定义的标签名(如上述示例中的asm-labels-test-a), 值为tagValue;
$getExternalInboundRequestHeader(headerName, contextId)
$getExternalInboundRequestHeader(headerName,contextId)是个函数型变量,需要从流量请求的上下文中获取,其中:
- 参数headerName是指请求头的关键字key,必填项, 且值不能为空, 例如x-asm-prefer-tag。
- 参数contextId是指一个贯穿整个调用链路的请求头字段, 其值可以是某一个用户指定的入口请求头, 或者可以使用Tracing系统中的Trace ID。必填项, 且值不能为空。
说明 仅针对Sidecar代理生效, 对于网关不生效。
Sidecar包含入口和出口两种类型的流量,流量打标本质上是对出口流量设置标签。默认情况下, Sidecar代理从入口请求头(名称为headerName)中获取对应的值, 并以此作为流量打标的标签值tagValue。
为将标签值tagValue附加到出口流量请求中, 在Sidecar代理的内部逻辑中维持一个map, 其中contextId需要是一个贯穿整个调用链路的请求头字段, 其值可以是某一个用户指定的入口请求头, 或者使用x-request-id作为contextId。
当业务容器发起出口请求时,Sidecar代理会通过contextId查找上下文map。若找到关联tagValue,则Sidecar代理会为出口请求中附加2个新请求头:
- 名称为headerName, 值为tagValue;
- 名称为流量标签TrafficLabel CRD中定义的标签名(如上述示例中的asm-labels-test-a), 值为tagValue;
说明
- map存储在Envoy内存中,默认30秒过期。
- 业务应用接入Trace系统时, TraceID会贯穿整个调用链路的请求, 因此可以使用TraceID作为上述contextId。 具体来说, 采用不同的Trace系统则会有不同TraceID。更多信息参见Tracing。
- 虽然Istio代理能够自动发送Tracing Span信息,但是应用程序仍然需要传播相关的HTTP标头,以便在代理发送Span时,可以将Span正确地关联到单个跟踪中, 具体参见:https://help.aliyun.com/document_detail/149551.html?spm=a2c4g.375313.0.0.56a356279kDUsS#h2-url-2。
- 若没有传播对应的HTTP标头,则出口流量会因为找不到关联的contextId, Sidecar代理将无法从map 找到对应的流量标签值。
$getLocalOutboundRequestHeader(headerName)
$getLocalOutboundRequestHeader(headerName)是个函数型变量,需要从出口请求头中获取,其中参数headerName是指请求头的关键字key,可以根据业务容器实际的请求头进行指定。
说明 仅针对Sidecar代理生效, 对于网关不生效。
当注入了Sidecar代理的业务容器发起出口请求时, 如下图所示,Sidecar代理会为出口请求中附加1个新请求头:
- 名称为流量标签TrafficLabel CRD中定义的标签名(如上述示例中的asm-labels-test-a), 值为tagValue;
$getLabel(labelName)
$getLabel(labelName)是指从Sidecar代理所属的Pod或网关Pod(注意不是Deployment)中获取名称为labelName的标签对应的值,并将该值附加到出口流量上。如果labelName为空, 即默认从工作负载Pod上的标签ASM_TRAFFIC_TAG取值.
例如以下工作负载定义了ASM_TRAFFIC_TAG值为test, 那么通过$getLabel(ASM_TRAFFIC_TAG)可以获取标签值为test。
apiVersion: apps/v1
kind: Deployment
metadata:
name: productpage-v1
labels:
app: productpage
version: v1
spec:
replicas: 1
selector:
matchLabels:
app: productpage
version: v1
template:
metadata:
annotations:
sidecar.istio.io/logLevel: debug
labels:
app: productpage
version: v1
ASM_TRAFFIC_TAG: test
spec:
serviceAccountName: bookinfo-productpage
containers:
- name: productpage
image: docker.io/istio/examples-bookinfo-productpage-v1:1.16.2
imagePullPolicy: IfNotPresent
ports:
- containerPort: 9080
volumeMounts:
- name: tmp
mountPath: /tmp
volumes:
- name: tmp
emptyDir: {
}
版本1.16或之前
建议升级到1.17版本, 或提交工单获得支持。
使用示例
注意: 以下示例基于1.17版本或以上。
示例1:按照工作负载进行流量打标签
通过定义workloadSelector根据标签选择对应的工作负载, 可以实现对某个命名空间下的工作负载进行流量打标签。
例如, 按照入门文档https://help.aliyun.com/document_detail/149547.html 部署bookinfo应用之后, 以下示例是针对productpage工作负载进行打标签。
apiVersion: istio.alibabacloud.com/v1
kind: TrafficLabel
metadata:
name: productpage
namespace: default
spec:
workloadSelector:
labels:
app: productpage
rules:
- labels:
- name: asm-labels-test-a
valueFrom:
- $getExternalInboundRequestHeader(header1, x-request-id)
- $getLabel(header2)
1)将上述内容保存为文件productpage-trafficlabel.yaml, 并执行如下命令:
kubectl apply -n default -f productpage-trafficlabel.yaml
2) 查看productpage工作负载对应的代理的配置:
kubectl exec -it -n default deploy/productpage-v1 -c istio-proxy -- curl localhost:15000/config_dump
在对应的Listener Config(type.googleapis.com/envoy.admin.v3.ListenersConfigDump)/ dynamic_listeners下的type.googleapis.com/envoy.config.listener.v3.Listener/envoy.filters.network.http_connection_manager/http_filters, 会添加如下类似的filter配置内容:
{
"name": "com.aliyun.traffic_label",
"typed_config": {
"@type": "type.googleapis.com/envoy.config.filter.traffic_label.v3alpha.TrafficLabel",
}
},
3) 此外, 查看其他工作负载如details Pod对应的代理的配置, 可以看到没有相关的filter出现:
kubectl exec -it -n default deploy/details-v1 -c istio-proxy -- curl localhost:15000/config_dump |grep type.googleapis.com/envoy.config.filter.traffic_label.v3alpha.TrafficLabel
执行上述命令之后, 返回结果为空。
示例2:按照命名空间进行流量打标签
如果不定义workloadSelector字段, 将对命名空间下所有的工作负载进行流量打标签。 例如, 如下配置将对命名空间default下的所有工作负载进行流量打标签。
apiVersion: istio.alibabacloud.com/v1
kind: TrafficLabel
metadata:
name: all-workload-for-ns
namespace: default
spec:
rules:
- labels:
- name: asm-labels-test-b
valueFrom:
- $getExternalInboundRequestHeader(header1, x-request-id)
- $getLabel(header2)
1)将上述内容保存为文件all-workload-for-ns-trafficlabel.yaml, 并执行如下命令:
kubectl apply -n default -f all-workload-for-ns-trafficlabel.yaml
2) 此时, 查看工作负载如details Pod对应的代理的配置, 可以看到有相关的filter出现:
kubectl exec -it -n default deploy/details-v1 -c istio-proxy -- curl localhost:15000/config_dump |grep type.googleapis.com/envoy.config.filter.traffic_label.v3alpha.TrafficLabel
得到类似的结果如下:
"@type": "type.googleapis.com/envoy.config.filter.traffic_label.v3alpha.TrafficLabel",