问题描述:

    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]

关键步骤:

1. 独立存储:金丝雀、环境分组、多活等每个功能的路由规则,都作为独立配置项存储(例如在DB中),彼此解耦。
2. 聚合与Merge:当任一功能配置变更时,聚合层会拉取该应用所有功能的当前配置。它会根据内置策略(如“多活规则优先于金丝雀规则”)进行智能合并,解决潜在的规则匹配冲突。
3. 生成与下发:聚合层生成一个标准的、包含所有规则的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]

具体配置示例:

 1. 父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

2. 子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标准特性

    如果你的团队追求标准化和降低长期维护成本,且功能间规则冲突可控,推荐从方案二(委托模式) 开始尝试。

   如果你的路由规则合并逻辑异常复杂,超出了简单委托的能力,则可以考虑方案一。

Logo

腾讯云面向开发者汇聚海量精品云计算使用和开发经验,营造开放的云计算技术生态圈。

更多推荐