基于Istio EnvoyFilter的全链路灰度实现

需求

我有这么一个请求链路:我发起请求访问服务 A, A会访问B, B会访问C, 这三个服务都部署在了enable Istio 的K8s集群的namespace中,且这三个服务都有同一个label: canary=true, 希望所有带个label的pod,在发起对外请求时,都自动增加一个header: canary=true, 如何实现?


方案

要实现这个需求,您可以创建一个 EnvoyFilter,为带有 canary=true 标签的所有 Pod 的出站请求自动添加 canary=true header。这里是一个配置示例:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
apiVersion: networking.istio.io/v1alpha3
kind: EnvoyFilter
metadata:
name: add-canary-header
spec:
workloadSelector:
labels:
canary: "true"
configPatches:
- applyTo: HTTP_ROUTE
match:
context: SIDECAR_OUTBOUND
routeConfiguration:
vhost:
route:
action: ANY
patch:
operation: MERGE
value:
route:
request_headers_to_add:
- header:
key: "canary"
value: "true"

这个配置将为所有带有 canary=true 标签的 Pod 的出站请求自动添加 canary=true header。请注意,这个配置假设服务 A、B 和 C 之间的请求都是通过 HTTP 发送的。如果您使用的是其他协议,那么您可能需要对 EnvoyFilter 配置进行相应的修改。

在此配置中,我们使用 workloadSelector 选择带有 canary=true 标签的所有 Pod,然后应用 configPatches 修改 Envoy 代理的 HTTP 路由配置,以添加自定义 header。


QA

上述配置中,vhost是什么意思?

在上述 EnvoyFilter 配置中,vhost 是一个缩写,表示 “virtual host”(虚拟主机)。虚拟主机是 Envoy 代理中用于 HTTP 路由的一个概念。每个虚拟主机都有一个或多个域名(如 example.com),以及与这些域名关联的一组路由规则。

在配置示例中,我们使用 vhost 配置以下匹配规则:

1
2
3
4
5
6
match:
context: SIDECAR_OUTBOUND
routeConfiguration:
vhost:
route:
action: ANY

这里的匹配规则表示,我们希望在所有出站(SIDECAR_OUTBOUND)的 HTTP 路由中应用此 EnvoyFilter 配置。通过指定 action: ANY,我们要求 Envoy 代理在与任何目标服务之间的请求中添加 canary=true header。

简而言之,在这个配置中,vhost 是用来表示 Envoy 代理中的虚拟主机,以便我们可以为与任何目标服务之间的请求添加自定义 header。


**上述配置中,patch.operation为什么使用MERGE而不使用INSERT_BEFORE?

在上述 EnvoyFilter 配置中,我们使用 MERGE 作为 patch.operation 的值,因为我们想要合并(修改)现有的 HTTP 路由配置,而不是在现有配置之前插入新的配置。

MERGEINSERT_BEFOREEnvoyFilter 中具有不同的用途:

  1. MERGE:用于合并或更新现有配置。在此示例中,我们希望修改现有的 HTTP 路由配置,为所有带有 canary=true 标签的 Pod 的出站请求添加 canary=true header。因此,我们使用 MERGE 操作来更新现有路由配置的 request_headers_to_add 部分,而不会影响其他配置。

    1
    2
    3
    4
    5
    6
    7
    8
    patch:
    operation: MERGE
    value:
    route:
    request_headers_to_add:
    - header:
    key: "canary"
    value: "true"
  2. INSERT_BEFORE:用于在现有配置之前插入新的配置。这在某些情况下可能有用,例如在现有过滤器链之前添加新的 Envoy 过滤器。然而,在这个示例中,我们的目标是在现有的 HTTP 路由配置中添加一个自定义 header,而不是在现有配置之前插入一个完全新的配置。因此,使用 INSERT_BEFORE 不适用于此场景。

总之,我们在这个示例中使用 MERGE 而不是 INSERT_BEFORE,是因为我们希望合并(修改)现有的 HTTP 路由配置,以添加自定义 header,而不是在现有配置之前插入新的配置。