基于虚拟服务委托机制扩展泳道路由能力

针对标准泳道托管资源限制用户自定义配置的情况,为实现路由策略与泳道隔离的解耦,可创建自定义虚拟服务(VirtualService)并指向泳道生成的委托(Delegate)虚拟服务,从而允许在不破坏泳道隔离性的前提下,为泳道服务注入超时、重试等自定义路由策略。

工作原理

在标准模式下,流量泳道会自动创建并托管一个包含hosts字段的VirtualService,该资源全权负责流量的接管与版本(Subset)分发,用户无法直接修改以注入自定义策略。

启用委托(Delegate)功能后,ASM 对路由过程进行了调整:

  1. 解除Host绑定:ASM 自动剥离原VirtualService中的hosts字段,它不再直接处理入口流量,而是等待其他VirtualService将流量委托给它。

  2. 构建委托关系:用户需创建一个新的自定义VirtualService来指定hosts及超时、重试等高级策略,并将流量委托给原VirtualService,完成最终的泳道版本匹配和路由。

这种组合式路由机制,实现了路由策略的解耦:既允许灵活定义顶层治理规则,又保留了泳道原生的自动化隔离能力。

为泳道服务启用自定义路由规则

前提条件

  1. 部署完成的宽松泳道示例环境,请参考宽松模式流量泳道实施前的准备

  2. 通过场景一:在链路中透传trace ID方式来实现应用版本隔离。

步骤一:为目标服务启用委托虚拟服务

此步骤修改泳道自动生成的VirtualService,使其进入可被委托的状态。

  1. 登录ASM控制台,在左侧导航栏,选择服务网格 > 网格管理

  2. 网格管理页面,单击目标实例名称,然后在左侧导航栏,选择流量管理中心 > 流量泳道

  3. 泳道服务列表下,找到需要操作的服务(例如mockb),在其对应的启用委托虚拟服务列,单击启用开关。

步骤二:创建自定义虚拟服务并委托路由

启用委托后,必须创建自定义虚拟服务来接管流量,并将其委托给泳道虚拟服务,以恢复并扩展路由能力。

  1. 在实例左侧导航栏,选择流量管理中心 > 流量泳道

  2. 单击 创建,配置一个新的虚拟服务。

    • 作用范围:开启作用于所有Sidecar,以匹配泳道VirtualService的东西向流量范围。

    • 所属服务:选择要配置的服务,例如mockb.default.svc.cluster.local

    • 虚拟服务代理:这是实现委托的关键。必须将流量委托给泳道自动创建的VirtualService。

      • 虚拟服务名:命名规则trafficlabel-vs-{泳道组名称}-{服务命名空间}-{服务名称}

        示例:对于test泳道组内、default命名空间下的mockb服务,其对应的虚拟服务名trafficlabel-vs-test-default-mockb
      • 虚拟服务所属命名空间:泳道自动创建的VirtualService统一位于 istio-system 命名空间。

以下通过两个具体场景,演示配置自定义VirtualService的高级路由项。

场景一:为泳道内服务启用故障注入

  1. 此场景为泳道中的mockb服务增加50%的请求中止故障。在创建虚拟服务页面,完成以下配置。

    控制台

    在虚拟服务创建页面,开启故障注入:开启请求中止,在中止响应码输入502,在故障注入百分比输入50

    YAML示例

    apiVersion: networking.istio.io/v1beta1
    kind: VirtualService
    metadata:
      name: my-mockb-fault-injection
      namespace: default
    spec:
      hosts:
        - mockb.default.svc.cluster.local
      http:
        - name: my-mockb-fault-rule
          fault:
            abort:
              percentage:
                value: 50
              httpStatus: 502
          delegate:
            name: trafficlabel-vs-test-default-mockb
            namespace: istio-system
  2. 在目标ASM实例详情页,左侧导航栏选择ASM网关 > 入口网关,查看并记录目标网关的服务地址

  3. <ASM_GATEWAY_IP>替换为网关地址,向应用入口(/mock)发送100次请求。

    for i in {1..100}; do
      curl -s -H 'x-asm-prefer-tag: s1' -H "my-trace-id: x000$i" http://<ASM_GATEWAY_IP>/mock
      echo ''
      sleep 0.5
    done

    预期输出:约一半的请求因故障注入而中止,另一半请求则成功完成了整个链路调用,并保持在v1版本的泳道中。

    -> mocka(version: v1, ip: 10.144.xxx.xxx)fault filter abort
    -> mocka(version: v1, ip: 10.144.xxx.xxx)-> mockb(version: v1, ip: 10.144.xxx.xxx)-> mockc(version: v1, ip: 10.144.xxx.xxx)
    -> mocka(version: v1, ip: 10.144.xxx.xxx)fault filter abort
    -> mocka(version: v1, ip: 10.144.xxx.xxx)-> mockb(version: v1, ip: 10.144.xxx.xxx)-> mockc(version: v1, ip: 10.144.xxx.xxx)
    ...

场景二:为泳道内服务启用路由级熔断

此场景为从mockamockb的调用配置路由级熔断。

  1. 完成自定义虚拟服务创建后,配置熔断降级规则。

    1. ASM实例详情页,左侧导航栏选择流量管理中心 > 熔断降级,然后单击创建

    2. 配置熔断规则:

      • 熔断流量类型:选择服务间调用东西向流量熔断

      • 关联工作负载:选择调用方工作负载,标签名输入app标签值输入 mocka

      • 服务域名:输入mockb.default.svc.cluster.local

      • 服务端口8000

      • 匹配虚拟服务路由项:单击选择路由项,勾选步骤二中创建的路由名称。

      • 配置具体的熔断策略。

  2. 为验证熔断规则是否生效,可使用直接响应插件临时让mockb服务持续返回错误。

    1. ASM实例详情页,左侧导航栏选择插件扩展中心 > 插件市场,搜索定位直接响应插件,进入插件页后单击新建插件实例

    2. 在新建页面,插件生效范围选择工作负载生效,然后单击添加工作负载到生效范围,搜索并选择mockb服务。

    3. 插件配置:使用以下配置,使mockb服务的/路径在被访问时直接返回502状态码。

      patch_context: SIDECAR_INBOUND
      port: '8000'
      path: /
      response: direct_response
      response_status: '502'
  3. 验证实际效果。

    1. 在目标ASM实例详情页,左侧导航栏选择ASM网关 > 入口网关,查看并记录目标网关的服务地址

    2. <ASM_GATEWAY_IP>替换为网关地址,向应用入口(/mock)发送20次请求。

      for i in {1..20}; do
        curl -s -H 'x-asm-prefer-tag: s1' -H "my-trace-id: x000$i" http://<ASM_GATEWAY_IP>/mock
        echo ''
        sleep 1
      done
    3. 预期输出:在连续几次请求收到direct_response(由插件模拟的502错误)后,后续请求的输出变为break,表明从mockamockb的调用已被熔断。

      -> mocka(version: v1, ip: 10.144.xxx.xxx)direct_response
      -> mocka(version: v1, ip: 10.144.xxx.xxx)direct_response
      ...
      -> mocka(version: v1, ip: 10.144.xxx.xxx)break
      -> mocka(version: v1, ip: 10.144.xxx.xxx)break
      -> mocka(version: v1, ip: 10.144.xxx.xxx)break
      ...

      测试完成后,及时关闭直接响应插件,以恢复mockb服务的正常访问。