Envoy Gateway v 1.1.0 版本重要更新介绍

Posted by Huabing Blog on Wednesday, July 10, 2024
In-N-Out Burger 餐馆墙上的装饰画(摄自加州 Santa Clara)

Envoy Gateway(本文中简称 EG)在七月发布了最新的 1.1 版本。1.1 版本 EG 在 1.0 GA (General Availability)版本后的第一个功能更新版本,包含了多个新特性和改进。本文将为大家介绍我认为其中最重要的几个新特性。

Wasm 扩展

Wasm 是 Envoy 的一个重要扩展机制,通过为 Envoy 配置 Wasm 扩展,可以在 Envoy 的 HTTP 请求和响应流程中插入自定义的处理逻辑。采用 Wasm 扩展有多个优势:首先,Wasm 扩展可以用多种语言编写,比如 C++,Rust,Go 等。这使得用户在编写扩展时可以选择自己熟悉的语言,降低了学习成本。其次,Wasm 插件是独立的二进制文件,不需要编译在 Envoy 的二进制中,这解藕了 Envoy 和扩展组件的生命周期,让用户可以在运行期对 Envoy 进行灵活扩展。除此之外,由于 Wasm 运行在一个沙箱环境中,该沙箱环境对应用代码的操作权限进行了严格的控制,只能访问 Envoy 提供的指定 API,因此 Wasm 扩展也提供了很好的安全性。

Envoy 原生只支持从本地文件或者 HTTP 下载 Wasm 扩展,这两种方式具有一定的局限性,特别是缺少对 Wasm 扩展的版本管理和权限控制。在 1.1 版本中,EG 通过 EnvoyExtensionPolicy CRD 提供了对 OCI 镜像格式的 Wasm 扩展支持。OCI 镜像使得用户可以更加方便地管理 Wasm 扩展插件的不同版本,同时也支持采用私用镜像对用户进行权限控制,增强了扩展插件的安全性。

下面是一个采用 EnvoyExtensionPolicy CRD 配置 OCI 镜像格式的 Wasm 扩展的例子:

apiVersion: gateway.envoyproxy.io/v1alpha1
kind: EnvoyExtensionPolicy
metadata:
  name: oci-wasm-source-test
spec:
  targetRef:
    group: gateway.networking.k8s.io
    kind: HTTPRoute
    name: http-with-oci-wasm-source
  wasm:
  - name: wasm-filter
    code:
      type: Image
      image:
        url: "zhaohuabing/testwasm:v0.0.1"
        sha256: cdb37a856ae7dae208cdcb19378022cc81dbcae30859f58b89ae259a9575a49d

如果 Wasm 扩展插件的镜像是私有的,可以通过配置 imagePullSecrets 来指定镜像拉取的凭证,也支持 配置 pullPolicy 来指定镜像拉取的策略。

apiVersion: gateway.envoyproxy.io/v1alpha1
kind: EnvoyExtensionPolicy
metadata:
  name: oci-wasm-source-test
spec:
  targetRef:
    group: gateway.networking.k8s.io
    kind: HTTPRoute
    name: http-with-oci-wasm-source
  wasm:
  - name: wasm-filter
    rootID: my_root_id
    code:
      type: Image
      image:
        url: oci://my-private-registry/wasm-filter-2:v1.0.0
        pullSecretRef:
          name: my-pull-secret
    pullPolicy: Always

EnvoyExtensionPolicy 也支持通过 HTTP 下载 Wasm 扩展:

apiVersion: gateway.envoyproxy.io/v1alpha1
kind: EnvoyExtensionPolicy
metadata:
  name: http-wasm-source-test
spec:
  targetRef:
    group: gateway.networking.k8s.io
    kind: HTTPRoute
    name: http-with-http-wasm-source
  wasm:
  - name: wasm-filter
    rootID: my_root_id
    code:
      type: HTTP
      http:
        url: https://raw.githubusercontent.com/envoyproxy/envoy/main/examples/wasm-cc/lib/envoy_filter_http_wasm_example.wasm
        sha256: 79c9f85128bb0177b6511afa85d587224efded376ac0ef76df56595f1e6315c0

External Process 扩展

除了 Wasm 扩展,EG 1.1 版本还引入了 External Process(外部进程)扩展。通过 External Process 扩展,用户可以采用一个独立的进程来实现对 Envoy 的自定义处理逻辑。Envoy 和 External Process 进程之间通过 gRPC 进行通信,Envoy 将收到的 HTTP 请求/响应消息通过 gRPC 调用发送给 External Process 进程,External Process 处理后在通过 gRPC 将结果返回给 Envoy。

External Process 扩展的主要优势在于其实现的灵活性:除了一个 gPRC 的调用接口之外,Envoy 对扩展的实现没有任何限制。用户可以完全控制扩展进行的内部实现,包括其使用的语言,调用哪些外部服务等等。此外,由于 External Process 扩展是独立的进程,其内部的状态和资源不会影响到 Envoy 的运行,Envoy 的安全性也得到了更好的保障。

下面是一个 External Process 扩展的例子:

apiVersion: gateway.envoyproxy.io/v1alpha1
kind: EnvoyExtensionPolicy
metadata:
  name: ext-proc-example
spec:
  targetRef:
    group: gateway.networking.k8s.io
    kind: HTTPRoute
    name: myapp
  extProc:
  - backendRefs:
    - name: grpc-ext-proc
      port: 9002
    processingMode:
      request: {}
      response: 
        body: Streamed 

为非 K8s 服务提供直接支持

1.0 中 EG 支持了 Service 和 ServiceImport 两种 K8s 原生的后端服务的定义方式。对于 K8s 集群外部的服务,EG 建议通过创建 EndpointSlice 的方式来间接支持。

在 1.1 中,EG 引入了一个新的 API Backend,直接支持了非 K8s 服务的定义。除了覆盖了已通过 EndpointSlice 方式支持的 IP 地址 和 FQDN 域名两种地址类型之外,Backend 还支持了 Unix Domain Socket 地址类型。IP 地址和 FQDN 域名用于访问集群外部的服务,而 Unix Domain Socket 则可以用于访问和 Envoy 部署在同一个 Pod 中的服务。例如,External Process 扩展进程就可以作为一个 Sidecar 部署在 Envoy Pod 中,通过 Unix Domain Socket 和 Envoy 进行通信,以避免网络通信的开销。

1.1 版本中,Backend 已经支持作为 HTTPRoute 和 ExtensionPolicy 的 BackendReference,后续版本会根据用户需求逐步扩展到其他资源中。除此之外,BackendTLSPolicy 也可以被关联到 Backend 上,以支持对非 K8s 服务的 TLS 配置。

下面的例子中,我们定义了一个 Backend 对象,并将其作为 HTTPRoute 的后端服务,用于访问 httpbin.org 这个外部服务:

apiVersion: gateway.networking.k8s.io/v1
kind: HTTPRoute
metadata:
  name: backend
spec:
  parentRefs:
    - name: eg
  hostnames:
    - "www.example.com"
  rules:
    - backendRefs:
        - group: gateway.envoyproxy.io
          kind: Backend
          name: httpbin
      matches:
        - path:
            type: PathPrefix
            value: /
---
apiVersion: gateway.envoyproxy.io/v1alpha1
kind: Backend
metadata:
  name: httpbin
spec:
  endpoints:
    - fqdn:
        hostname: httpbin.org
        port: 80

支持 IP 黑白名单

IP 黑白名单是一个常见的安全控制手段,通过配置 IP 黑白名单,可以限制允许访问服务的客户端 IP 地址范围。在 1.1 版本中,EG 通过 SecurityPolicy CRD 支持了 IP 黑白名单的配置。

例如下面的 SecurityPolicy 对访问 http-with-authorization-client-ip 这个 HTTPRoute 的请求进行了访问控制。缺省的访问策略设置为 Deny,只有在策略中明确指定的 IP 段 10.0.1.0/24 和 10.0.2.0/24 这两个 IP 段才能访问该 HTTPRoute。

apiVersion: gateway.envoyproxy.io/v1alpha1
kind: SecurityPolicy
metadata:
  name: authorization-client-ip
spec:
  targetRef:
    group: gateway.networking.k8s.io
    kind: HTTPRoute
    name: http-with-authorization-client-ip
  authorization:
    defaultAction: Deny
    rules:
    - action: Allow
      principal:
        clientCIDRs:
        - 10.0.1.0/24
        - 10.0.2.0/24

需要注意的是,如果客户端请求在到达 EG 之前还经过了会改变源 IP 地址的中间节点,则需要通过配置 ClientTrafficPolicy 来获取客户端的真实 IP 地址(如希望进一步了解获取客户端真实 IP 地址的原理,可以参考《如何通过 Envoy Gateway 得到客户端的真实 IP 地址?》

apiVersion: gateway.envoyproxy.io/v1alpha1
kind: ClientTrafficPolicy
metadata:
  name: enable-client-ip-detection
spec:
  clientIPDetection:
    xForwardedFor:
      numTrustedHops: 1
  targetRef:
    group: gateway.networking.k8s.io
    kind: HTTPRoute
    name: http-with-authorization-client-ip

支持会话保持

对于有状态的服务,来自同一个客户端的多个 HTTP 请求需要被路由到同一个后端到服务实例上进行处理,以保证客户端的请求能够被正确处理。EG 1.1 中支持了一致性哈希负载均衡算法,以支持会话保持(Session Persistence)。目前版本支持按照客户端 IP 地址或者 HTTP header 两种方式来保持会话。

下面是一个采用客户端 IP 地址来进行会话保持的例子。

apiVersion: gateway.envoyproxy.io/v1alpha1
kind: BackendTrafficPolicy
metadata:
  name: policy-for-route-1
spec:
  targetRef:
    group: gateway.networking.k8s.io
    kind: HTTPRoute
    name: httproute-1
  loadBalancer:
    type: ConsistentHash
    consistentHash:
      type: SourceIP

支持自定义 Filter 顺序

EG 中提供了 BacendTrafficPolicy, SecurityPolicy等灵活的策略来对请求进行处理,这些策略是通过 Envoy 的 HTTP Filter 来实现的。EG 向 Envoy 下发的 Filter 执行顺序是固定的,该顺序在大部分情况下是合理的,但是在某些情况下,用户可能希望调整缺省的 Filter 执行顺序。例如,用户可能希望把 Rate Limit Filter 放在最前面,以便在请求到达后立即对请求进行限流,减少后续 Filter 的处理压力。

在 1.1 版本中,EG 在 EnvoyProxy CRD 中增加了一个新的字段 filterOrder,用户可以通过该字段来指定 Filter 的执行顺序。

下面是一个自定义 Filter 顺序的例子,其中指定了 Wasm Filter 在 JWT Filter 之前执行,CORS Filter 在 Basic Auth Filter 之后执行。

apiVersion: gateway.envoyproxy.io/v1alpha1
kind: EnvoyProxy
metadata:
  name: custom-proxy-config
  namespace: envoy-gateway-system
spec:
  filterOrder:
    - name: envoy.filters.http.wasm
      before: envoy.filters.http.jwt_authn
    - name: envoy.filters.http.cors
      after: envoy.filters.http.basic_authn

总结

Envoy Gateway 1.1 版本引入了多个新特性和改进,包括 Wasm 扩展的 OCI 镜像支持,External Process 扩展,非 K8s 服务的直接支持,IP 黑白名单,会话保持,自定义 Filter 顺序等。这些新特性和改进使得 EG 在更多的场景下可以发挥作用,为用户提供了更多的灵活性和可定制性。同时,EG 1.1 版本也修复了之前版本中的一些 bug,提升了稳定性和性能。

根据我从社区中接到的反馈得知,一些大型的企业用户已经开始在其产品或者服务中采用 Envoy Gateway,包括 SAP,Docker,Siemens 等。欢迎大家下载试用 EG 1.1 版本,并向社区反馈您的使用体验和建议。

EG 1.1 版本的详细更新内容可以参考Relase 变更清单