问题描述:
istio的路由是virtual service来实现的,而vs的管理粒度是应用这个粒度的,通常叫法是upstream。这种实现逻辑已经焊死了一个功能变更,就需要修改整个应用粒度的路由信息的关联方式。
官方文档定义了VirtualService的 hosts 字段,它指定了规则生效的目标服务。在传统模式下,一个应用(如 reviews.prod.svc.cluster.local)的所有路由规则都必须堆叠在同一个VS里。以你提到的三个功能为例,它们可能产生如下冲突:
冲突场景举例 (以 reviews 服务为例):
· 功能1: 金丝雀发布
· 规则: 将 10% 的流量路由到标签为 version: v2 的实例。
· 功能2: 环境分组
· 规则: 来自测试用户(header 带 env: test)的流量,路由到标签为 env: test 的实例。
· 功能3: 多活
· 规则: 来自 region: bj 的流量,优先路由到同区域(region: bj)的实例。
如果这三个功能由不同团队、在不同时间维护同一个VS文件,非常容易发生配置冲突或顺序错乱,导致流量不按预期路由。
除此之外,istio的路由功能是在envoy的out bound这个上面实现的,也就是说每次的路由变更必须准确的变更到所有来源应用,也就是down streams上面才行,否则就会存在流量有损。
问题: 我们应该如何保证不同场景路由的变更,不会影响存量的路由功能呢?
方案一:自定义聚合层(代码Merge)
这个方案的核心是引入一个"配置聚合层",它负责从数据库(或配置中心)读取针对同一应用的所有独立路由功能配置,按照预设的优先级和策略进行合并,最终生成一个完整的、下发到Istio的VirtualService。
交互流程如下:
功能配置存储
↓ (读取)
代码聚合层\] → (根据优先级策略Merge) ↓ (生成) \[完整VirtualService
↓ (下发)
Istio
关键步骤:
-
独立存储:金丝雀、环境分组、多活等每个功能的路由规则,都作为独立配置项存储(例如在DB中),彼此解耦。
-
聚合与Merge:当任一功能配置变更时,聚合层会拉取该应用所有功能的当前配置。它会根据内置策略(如"多活规则优先于金丝雀规则")进行智能合并,解决潜在的规则匹配冲突。
-
生成与下发:聚合层生成一个标准的、包含所有规则的VirtualService YAML文件,并通过Kubernetes API下发到Istio。
优点与挑战:
· 优点:灵活性强,可定制复杂的合并逻辑和优先级策略。
· 挑战:需自行开发和维护聚合层,并编写充分的测试用例来保证合并后的配置始终正确,避免流量有损。
备注:笔者目前是采用的这种方式。
方案二:使用Istio原生委托模式
这个方案利用了Istio原生支持的VirtualService委托(Delegate)机制。官方文档明确指出,可以通过 Delegate 字段将路由规则委派给其他VirtualService。
实现方式:
· 父VirtualService (根VS):定义一个范围较宽的匹配规则(例如匹配所有流量),但其具体路由动作不在此定义,而是通过 delegate 字段委派出去。注意,根据文档,委托VirtualService的 hosts 字段应为空。
· 子VirtualService (功能VS):每个具体的路由功能(金丝雀、环境分组、多活)都定义在自己的VirtualService中。这些子VS会继承父VS中定义的 hosts,并只专注于自己的匹配条件和路由目标。
交互流程如下:
父 VirtualService
(hosts: reviews.prod.svc.cluster.local)
| (通过 delegate 字段关联)
├──→ [子 VS: 金丝雀发布]
├──→ [子 VS: 环境分组]
└──→ [子 VS: 多活转发]
↓ (共同作用)
Istio
具体配置示例:
- 父VirtualService (根路由,负责委派)
apiVersion: networking.istio.io/v1beta1
kind: VirtualService
metadata:
name: reviews-root
spec:
hosts:
- reviews.prod.svc.cluster.local
http:
将所有流量路由规则的决策,委托给同命名空间下名称前缀为 reviews- 的VirtualService
- delegate:
name: reviews-canary # 委托给金丝雀子VS
- delegate:
name: reviews-env-group # 委托给环境分组子VS
- 子VirtualService: 金丝雀发布 (专注于金丝雀逻辑)
apiVersion: networking.istio.io/v1beta1
kind: VirtualService
metadata:
name: reviews-canary
spec:
hosts: [] # 委托VS的hosts必须为空,继承父VS的hosts
http:
-
route:
-
destination:
host: reviews.prod.svc.cluster.local
subset: v1
weight: 90
- destination:
host: reviews.prod.svc.cluster.local
subset: v2
weight: 10
优点与适用场景:
· 优点:架构清晰,功能解耦。各团队可独立管理自己的子VS,变更互不影响。这是Istio原生支持的方式,更稳定。
注意:需确保父子VS在同一命名空间,且需事先规划好父VS的委派策略。子VS的规则匹配范围不应有重叠冲突,否则行为可能不确定。
方案对比与选择建议
· 方案一(自定义聚合)
· 核心:外部代码逻辑合并
· 解耦程度:配置存储解耦,但需中央聚合器
· 维护性:需维护合并逻辑与大量测试
· 适用场景:有复杂、自定义合并逻辑需求,或已有配置管理平台
· 方案二(委托模式)
· 核心:Istio原生委派机制
· 解耦程度:VS资源级别完全解耦
· 维护性:遵循Istio原生方式,不同团队可独立管理
· 适用场景:团队自治要求高,希望采用Istio标准特性
如果你的团队追求标准化和降低长期维护成本,且功能间规则冲突可控,推荐从方案二(委托模式) 开始尝试。
如果你的路由规则合并逻辑异常复杂,超出了简单委托的能力,则可以考虑方案一。