当您需要对微服务应用中的工作负载进行更精细化的管理和路由控制时,可以使用动态子集路由功能。在多应用多版本发布的场景下,ASM会自动根据应用特征将工作负载划分至对应的动态子集,减轻运维人员的手动配置负担。ASM还支持通过请求的特定Header与子集特征匹配,实现更灵活的请求路由。
前提条件
已添加集群到ASM实例,且ASM实例版本为1.18及以上。
功能介绍
ASM支持通过目标规则DestinationRule将服务下的工作负载通过标签划分为不同的子集,并支持声明路由规则,指向特定的子集。这种使用方式较为简明,也可以满足绝大多数情况下的需求。但在一些场景中,这种静态分组并静态路由的方式可能不够便利。例如,在以版本将工作负载划分为不同的子集的场景中,版本可能是不断增长的。这要求运维人员在新版本发布或旧版本下线时,新增或移除在DestinationRule中相应的子集配置。在多应用多版本频繁发布的场景下,这项工作会给运维人员增加一些额外的负担。
为了提高使用体验,ASM自1.18版本起,支持动态子集路由。您可以通过指定维度(例如版本),动态地将指定维度值相同的工作负载划分至同一个动态子集。使用动态子集应对上述场景则无需运维人员手动为每个新版本静态配置子集。部署工作负载时,ASM会自动地根据应用特征将其划分至对应动态子集。同时,ASM支持配置通过请求的特定Header与子集特征进行匹配,根据请求携带的Header将请求路由到指定动态子集。
步骤一:部署应用示例
本文以hashicorp/http-echo应用为例,部署dev和prod两套环境,分别模拟开发环境和生产环境。在dev环境下部署v1、v2、v3版本,在prod环境下只部署v2、v3版本。helloworld监听在5678端口,收到请求会回复自己的环境和版本。同时,部署服务helloworld,暴露8000端口,选中app
为helloworld
的工作负载。
在ACK集群对应的KubeConfig环境下,使用以下YAML分别部署helloworld应用dev环境v1、v2和v3版本、prod环境v2和v3版本、helloworld服务以及用于发起测试的sleep应用。关于如何部署应用,请参见在ASM实例关联的集群中部署应用。
步骤二:访问指定环境的指定版本
部署目标规则和虚拟服务。
使用以下内容,为helloworld服务配置目标规则。具体操作,请参见管理目标规则。
Helloworld应用部署完毕后,在默认情况下,访问helloworld服务的请求将被K8s负载均衡分配到任意一个helloworld应用Pod。本文为helloworld应用部署2个环境多个版本(dev环境v1、v2和v3版本、prod环境v2和v3版本)。要访问指定环境和版本,需要为helloworld服务配置目标规则DestinationRule。
apiVersion: networking.istio.io/v1beta1 kind: DestinationRule metadata: name: helloworld namespace: default spec: host: helloworld.default.svc.cluster.local trafficPolicy: loadBalancer: dynamicSubset: subsetSelectors: - keys: - stage - version
以上目标规则为helloworld服务配置了一个以stage和version标签进行分组的规则。本例中部署的工作负载将被该规则分为以下几个分组。
分组
Pod
地址
stage = dev
version = v1
helloworld-dev-v1-67b6876778-nf7pz
192.168.0.5
stage = dev
version = v2
helloworld-dev-v2-68f65bbc99-v957l
192.168.0.1
stage = dev
version = v3
helloworld-dev-v3-7f6978bc56-hqzgg
192.168.0.252
stage = prod
version = v2
helloworld-prod-v2-b5745b949-p8rc4
192.168.0.103
stage = prod
version = v3
helloworld-prod-v3-6768bf56f8-6bd6h
192.168.0.104
helloworld-prod-v3-6768bf56f8-6bd6h
192.168.0.6
使用以下内容,为helloworld服务创建虚拟服务,建立请求到动态分组
key
之间的映射关系。具体操作,请参见管理虚拟服务。以上虚拟服务指定:
将请求中名为
x-version
的Header的值映射到分组名为version
的分组key
。若请求未携带x-version
Header,则使用默认值v3
。将请求中名为
x-stage
的Header的值映射到名为stage
的分组key
。若请求未携带x-stage
Header,则使用默认值prod
。
在ACK集群对应的KubeConfig环境下,执行以下命令,从sleep应用发起对helloworld应用dev环境的v1版本的访问。
关于如何通过kubectl管理集群,请参见获取集群KubeConfig并通过kubectl工具连接集群。
kubectl exec -it deploy/sleep -c sleep -- curl -H 'x-stage: dev' -H 'x-version: v1' helloworld:8000
预期输出:
Welcome to helloworld stage: dev, version: v1, ip: 192.168.0.5
由预期输出得到,请求被正确地路由至
stage
标签为dev
、version
标签为v1
的Pod。
步骤三:为分组配置回退策略
prod环境中未部署v1版本,若尝试访问prod环境的v1版本,会因为该分组不存在而报错。
kubectl exec -it deploy/sleep -c sleep -- curl -H 'x-stage: prod' -H 'x-version: v1' helloworld:8000
预期输出:
no healthy upstream # 由于分组不存在,产生报错。
为了避免分组不存在时访问失败,您可以为动态分组规则配置回退策略。下文介绍ASM动态分组支持的三种回退策略:NO_FALLBACK、ANY_ENDPOINT、DEFAULT_SUBSET。
NO_FALLBACK
为动态分组规则使用该策略,当无法匹配任何分组时,请求将会报no healthy upstream
错误。
使用如下目标规则,为
stage
、version
分组规则指定fallbackPolicy
为NO_FALLBACK
。具体操作,请参见管理目标规则。apiVersion: networking.istio.io/v1beta1 kind: DestinationRule metadata: name: helloworld namespace: default spec: host: helloworld.default.svc.cluster.local trafficPolicy: loadBalancer: dynamicSubset: subsetSelectors: - fallbackPolicy: NO_FALLBACK keys: - stage - version
执行以下命令,访问
stage
为prod
、version
为v1
的helloworld应用。kubectl exec -it deploy/sleep -c sleep -- curl -H 'x-stage: prod' -H 'x-version: v1' helloworld:8000
预期输出:
no healthy upstream # 由于分组不存在,产生报错。
ANY_ENDPOINT
为动态分组规则使用该策略,当无法匹配任何分组时,请求将被路由至服务下的任意端点。
使用如下目标规则,为
stage
、version
分组规则指定fallbackPolicy
为ANY_ENDPOINT
。具体操作,请参见管理目标规则。apiVersion: networking.istio.io/v1beta1 kind: DestinationRule metadata: name: helloworld namespace: default spec: host: helloworld.default.svc.cluster.local trafficPolicy: loadBalancer: dynamicSubset: subsetSelectors: - fallbackPolicy: ANY_ENDPOINT keys: - stage - version
执行以下命令,访问
stage
为prod
、version
为v1
的helloworld应用。第一次访问:
kubectl exec -it deploy/sleep -c sleep -- curl -H 'x-stage: prod' helloworld:8000
预期输出:
Welcome to helloworld stage: prod, version: v2, ip: 192.168.0.103 # 第一次访问被路由至prod, v2。
第二次访问:
kubectl exec -it deploy/sleep -c sleep -- curl -H 'x-stage: prod' -H 'x-version: v1' helloworld:8000
预期输出:
Welcome to helloworld stage: dev, version: v2, ip: 192.168.0.1 # 第二次访问被路由至dev, v2。
由预期输出得到,请求被路由至helloworld服务下的随机Pod。
DEFAULT_SUBSET
为动态分组规则使用该策略,当无法匹配任何分组时,请求将被路由至defaultSubset
指定的key
匹配的分组。
使用如下目标规则,为
stage
、version
分组规则指定fallbackPolicy
为DEFAULT_SUBSET
,并配置defaultSubset
的key
和value
。具体操作,请参见管理目标规则。key
value
stage
prod
version
v3
apiVersion: networking.istio.io/v1beta1 kind: DestinationRule metadata: name: helloworld namespace: default spec: host: helloworld.default.svc.cluster.local trafficPolicy: loadBalancer: dynamicSubset: defaultSubset: stage: prod version: v3 subsetSelectors: - fallbackPolicy: DEFAULT_SUBSET keys: - stage - version
执行以下命令,访问
stage
为prod
、version
为v1
的分组。第一次访问:
kubectl exec -it deploy/sleep -c sleep -- curl -H 'x-stage: prod' -H 'x-version: v1' helloworld:8000
预期输出:
Welcome to helloworld stage: prod, version: v3, ip: 192.168.0.6
第二次访问:
kubectl exec -it deploy/sleep -c sleep -- curl -H 'x-stage: prod' -H 'x-version: v1' helloworld:8000
预期输出:
Welcome to helloworld stage: prod, version: v3, ip: 192.168.0.104
由预期输出得到,由于分组不存在,触发回退,使用
stag
为prod
、version
为v3
匹配分组,符合预期。
步骤四:访问指定Pod
若您需要访问到指定Pod,可以通过ASM动态分组内置keys
为%ip%
进行分组,将每个Pod划分独立分组。
使用以下目标规则,新增一个以Pod IP维度进行分组的分组规则。具体操作,请参见管理目标规则。
apiVersion: networking.istio.io/v1beta1 kind: DestinationRule metadata: name: helloworld namespace: default spec: host: helloworld.default.svc.cluster.local trafficPolicy: loadBalancer: dynamicSubset: defaultSubset: stage: prod version: v3 subsetSelectors: - keys: - '%ip%'
使用如下虚拟服务,将请求的
x-ip
Header映射到%ip%
分组的规则,使请求可以通过x-ip
指定希望访问的Pod IP。具体操作,请参见管理虚拟服务。apiVersion: networking.istio.io/v1beta1 kind: VirtualService metadata: name: helloworld namespace: default spec: hosts: - helloworld.default.svc.cluster.local http: - headerToDynamicSubsetKey: - header: x-ip key: '%ip%' name: default route: - destination: host: helloworld.default.svc.cluster.local port: number: 8000
执行以下命令,对Pod helloworld-prod-v3-6768bf56f8-6bd6h进行访问,指定Pod地址
192.168.0.6
,进行多次访问。第一次访问:
kubectl exec -it deploy/sleep -c sleep -- curl -H 'x-ip: 192.168.0.6' helloworld:8000
预期输出:
Welcome to helloworld stage: prod, version: v3, ip: 192.168.0.6
第二次访问:
kubectl exec -it deploy/sleep -c sleep -- curl -H 'x-ip: 192.168.0.6' helloworld:8000
预期输出:
Welcome to helloworld stage: prod, version: v3, ip: 192.168.0.6
第三次访问:
kubectl exec -it deploy/sleep -c sleep -- curl -H 'x-ip: 192.168.0.6' helloworld:8000
预期输出:
Welcome to helloworld stage: prod, version: v3, ip: 192.168.0.6
由预期输出得到,请求都被路由至指定的Pod地址
192.168.0.6
,符合预期。
CRD说明
VirtualService
HTTPRoute
ASM对HTTPRoute进行扩展,增加headerToDynamicSubsetKey字段。
字段
类型
说明
headerToDynamicSubsetKey
用于配置请求Header到动态子集key的映射。数组中的每一个元素为一个Header到一个key的映射。
HeaderToMetadataSubsetKey
配置请求Header到动态子集key的映射关系或默认值。
字段
类型
说明
header
string
请求头名称。
key
string
动态子集key名称,其中%开头结尾的表示工作负载内置属性。
defaultValue
string
若请求没有携带key指定的Header,则使用该默认值。如果不配置默认值,则在请求未携带该Header时视作该维度缺失,该维度不参与匹配。
DestinationRule
ASM对trafficPolicy结构进行扩展,增加dynamicSubset字段。
TrafficPolicy
字段
类型
说明
dynamicSubset
用于配置动态分组规则。
DyunamicSubsetLB
字段
类型
说明
defaultSubset
map[string]string
用于配置默认分组,当请求无法匹配任何动态分组,且分组规则的回退策略为DEFAULT_SUBSET时,使用该配置声明的维度值选择分组。
subsetSelectors
用于配置动态分组规则,数组中每一项为一个独立的分组规则。
fallbackPolicy
指定无法匹配动态子集时的回退策略。若不指定该配置,则默认为NO_FALLBACK。
SubsetSelector
字段
类型
说明
keys
string[]
分组维度列表,值映射至工作负载标签。例如,version表示以工作负载的名为version的标签作为分组维度。除标签外,还支持以工作负载内置属性作为维度。更多信息,请参见工作负载内置属性。
fallbackPolicy
指定无法匹配动态子集时的回退策略。若不指定该配置,则使用DyunamicSubsetLB中指定的fallbackPolicy。
DynamicSubsetLB_FallbackPolicy
表示动态子集路由回退策略的枚举类型,支持的值如下:
值
说明
NO_FALLBACK
不进行回退。
ANY_ENDPOINT
使用服务下任意端点。
DEFAULT_SUBSET
使用声明的默认子集进行回退。
工作负载内置属性
属性 | 类型 | 说明 |
%ip% | string | 工作负载的Pod地址。 |
相关文档
您可以启用控制平面日志采集和日志告警,及时发现和解决潜在的风险。具体操作,请参见启用控制平面日志采集和日志告警。
您可以安装诊断工具asmctl,检测ASM存在的配置问题。具体操作,请参见安装和使用诊断工具asmctl。
您可以为ASM资源(VirtualService、DestinationRule等)的变更行为添加审计告警能力,在重要资源变动时及时发出告警通知到告警联系人。具体操作,请参见为网格资源操作配置审计告警。
您可以基于VirtualService和DestinationRule等流量规则实现流量泳道,同时通过配置流量降级,在某个版本(或者其他特征)的应用不可用时,将流量发往一个指定的降级版本(或其他特征)的应用。具体操作,请参见基于流量规则配置实现流量泳道和流量降级。
如果您需要在客户端对一个目标服务的访问过程中,使流量尽可能的在同一个可用区内流转,以保证服务间的调用延迟最低,可以使用同可用区优先路由功能。具体操作,请参见使用网格拓扑观测同可用区优先路由。