使用 EnvoyFilter 实现数据平面可扩展性

您可以使用 EnvoyFilter API 扩展 Cloud Service Mesh 中的数据平面功能,这些功能无法通过使用其他 Istio API 来实现。借助 EnvoyFilter API,您可以自定义通过应用于工作负载的其他政策生成的 Envoy 配置,例如向 HTTP 过滤条件链添加过滤条件。

重要注意事项

  • 请注意,API Surface 与内部实现细节相关联,因此在使用此功能时必须特别小心,因为不正确的配置可能会导致网格不稳定。仅当其他 Istio API 不符合您的需求时,才使用 EnvoyFilter API。
  • EnvoyFilter API 受支持,但对哪些字段和扩展程序可用于可靠性和可支持性目的有特定限制。如需查看 EnvoyFilter API 中支持的功能的详尽列表,请参阅使用 Istio API 支持的功能(托管式控制平面)。
  • Google 提供的支持范围仅限于将用户提供的配置传播到具有 Envoy 边车的工作负载,不涵盖使用每个扩展程序 API 指定的配置的正确性。

支持的 API 字段

EnvoyFilter API 仅在TRAFFIC_DIRECTOR控制平面实现中受支持,且支持有限,如下所示:

  • targetRefs:不支持
  • configPatches[].applyTo:仅支持 HTTP_FILTER
  • configPatches[].patch.operation:与路由过滤条件搭配使用时,仅支持 INSERT_FIRST 和 INSERT_BEFORE。
  • configPatches[].patch.value.type_url:请参阅支持的扩展程序
  • configPatches[].patch.filterClass:不支持
  • configPatches[].match.proxy:不支持
  • configPatches[].match.routeConfiguration:不支持
  • configPatches[].match.cluster:不支持
  • 仅 INSERT_BEFORE 操作支持以下字段:
    • configPatches[].match.listener:仅支持 filter。
    • configPatches[].match.listener.filter.name:仅支持 envoy.filters.network.http_connection_manager。
    • configPatches[].match.listener.filter.subFilter.name:仅支持 envoy.filters.http.router。

支持的扩展程序

以下是支持的扩展程序列表,以及它们在各种发布渠道中支持的 API 字段。如需了解 API 定义及其语义,请参阅官方 Envoy 文档。

type.googleapis.com/envoy.extensions.filters.http.local_ratelimit.v3.LocalRateLimit

字段 快速 常规 稳定
stat_prefix
status
token_bucket
filter_enabled
filter_enforced
response_headers_to_add
request_headers_to_add_when_not_enforced
local_rate_limit_per_downstream_connection
enable_x_ratelimit_headers

type.googleapis.com/envoy.extensions.filters.http.grpc_web.v3.GrpcWeb

字段 快速 常规 稳定
(无字段)

type.googleapis.com/envoy.extensions.filters.http.compressor.v3.Compressor

字段 快速 常规 稳定
compressor_library
choose_first
response_direction_config.common_config.min_content_length
response_direction_config.common_config.content_type
response_direction_config.common_config.enabled
response_direction_config.disable_on_etag_header
response_direction_config.remove_accept_encoding_header
response_direction_config.uncompressible_response_codes
request_direction_config.common_config.min_content_length
request_direction_config.common_config.content_type
request_direction_config.common_config.enabled

如需了解如何更新 EnvoyFilter 压缩器配置以获得完全支持,请参阅现代化改造 EnvoyFilter 压缩器配置。

type.googleapis.com/envoy.extensions.filters.http.lua.v3.Lua

字段 快速 常规 稳定
stat_prefix
default_source_code.inline_string†

† 内嵌 Lua 脚本的重要注意事项和限制:

  • 为确保安全性和稳定性,仅允许使用部分 Lua 功能和 Envoy Lua 封装容器。如果使用不受支持的功能或超出特定补丁中记录的限制,则会导致该补丁被丢弃且不进行处理。如果 EnvoyFilter 中的所有补丁都使用不受支持的功能或超出限制,则整个 EnvoyFilter 资源都会被拒绝。
  • 复杂的 Lua 脚本可能会影响性能。全面测试脚本的资源使用情况。

不支持的 Lua 功能:
不支持以下 Lua 功能和 Envoy 提供的 Lua 封装容器:

  • Envoy 封装容器:
    • httpCall
    • filterContext
  • Lua 标准库:
    • 基本套餐:collectgarbage、dofile、getmetatable、loadfile、rawset、setfenv、setmetatable
    • 模块:module
    • 操作系统软件包:execute、remove、rename、setlocale
    • I/O 和调试库:io、debug
  • LuaJIT 扩展:ffi、jit

脚本大小和数量限制:

  • 单个脚本大小:default_source_code.inline_string 中提供的单个 Lua 内嵌脚本不能超过 50KB。
  • 脚本总大小:单个集群中所有 EnvoyFilter 资源的所有 Lua 脚本的总大小不能超过 100KB。
  • 补丁数量:单个集群中所有 EnvoyFilter 资源中的 Lua EnvoyFilter configPatches 总数上限为 10。

配置补丁评估和部分处理

当您配置具有多个 configPatches 的 EnvoyFilter 资源时,Cloud Service Mesh 会独立评估每个补丁。

  • 部分有效的配置:如果您的 EnvoyFilter 资源既包含有效补丁,又包含具有不受支持的字段或错误的补丁,则系统会接受整个资源。Cloud Service Mesh 会丢弃不受支持或无效的补丁,仅处理有效的补丁。发生这种情况时,资源上会显示 Warning 状态条件,其中列出了导致某些补丁被丢弃的不受支持的字段。
  • 完全无效的配置:如果 EnvoyFilter 中的 configPatches 均无效,则整个资源都会被拒绝,并显示错误。

用法示例

在本教程中,您将学习如何使用 Envoy 的内置本地速率限制功能,通过 EnvoyFilter API 动态限制流向服务的流量。

费用

本教程使用 Google Cloud的以下收费组件:

完成本教程后,您可以删除所创建的资源以避免持续产生费用。如需了解详情,请参阅清理。

准备工作

  • 确保您的项目已启用结算功能。
  • 在 GKE 集群上预配 Cloud Service Mesh。
  • 克隆代码库:

      git clone https://github.com/GoogleCloudPlatform/anthos-service-mesh-samples
      cd anthos-service-mesh-samples
    

部署入站流量网关

  1. 将 kubectl 的当前上下文设置为相应集群:

    gcloud container clusters get-credentials CLUSTER_NAME  \
        --project=PROJECT_ID \
        --zone=CLUSTER_LOCATION 
    
  2. 为入站流量网关创建命名空间:

    kubectl create namespace asm-ingress
    
  3. 启用用于注入的命名空间。具体步骤取决于控制平面实现。

    将默认注入标签应用于命名空间:

    kubectl label namespace asm-ingress \
        istio.io/rev- istio-injection=enabled --overwrite
    
  4. 在 anthos-service-mesh-samples 代码库中部署示例网关:

    kubectl apply -n asm-ingress \
        -f docs/shared/asm-ingress-gateway
    

    预期输出:

    serviceaccount/asm-ingressgateway configured
    service/asm-ingressgateway configured
    deployment.apps/asm-ingressgateway configured
    gateway.networking.istio.io/asm-ingressgateway configured
    

部署 Online Boutique 示例应用

  1. 将 kubectl 的当前上下文设置为相应集群(如果尚未设置):

    gcloud container clusters get-credentials CLUSTER_NAME  \
      --project=PROJECT_ID \
      --zone=CLUSTER_LOCATION 
    
  2. 为示例应用创建命名空间:

    kubectl create namespace onlineboutique
    
  3. 为 onlineboutique 命名空间添加标签以自动注入 Envoy 代理:

    kubectl label namespace onlineboutique \
       istio.io/rev- istio-injection=enabled --overwrite
    
  4. 部署示例应用、前端的 VirtualService 以及工作负载的服务账号。在本教程中,您将部署 Online Boutique,这是一个微服务演示版应用。

    kubectl apply \
      -n onlineboutique \
      -f docs/shared/online-boutique/virtual-service.yaml
    
    kubectl apply \
      -n onlineboutique \
      -f docs/shared/online-boutique/service-accounts
    

查看服务

  1. 查看 onlineboutique 命名空间中的 Pod:

    kubectl get pods -n onlineboutique
    

    预期输出:

    NAME                                     READY   STATUS    RESTARTS   AGE
    adservice-85598d856b-m84m6               2/2     Running   0          2m7s
    cartservice-c77f6b866-m67vd              2/2     Running   0          2m8s
    checkoutservice-654c47f4b6-hqtqr         2/2     Running   0          2m10s
    currencyservice-59bc889674-jhk8z         2/2     Running   0          2m8s
    emailservice-5b9fff7cb8-8nqwz            2/2     Running   0          2m10s
    frontend-77b88cc7cb-mr4rp                2/2     Running   0          2m9s
    loadgenerator-6958f5bc8b-55q7w           2/2     Running   0          2m8s
    paymentservice-68dd9755bb-2jmb7          2/2     Running   0          2m9s
    productcatalogservice-84f95c95ff-c5kl6   2/2     Running   0          114s
    recommendationservice-64dc9dfbc8-xfs2t   2/2     Running   0          2m9s
    redis-cart-5b569cd47-cc2qd               2/2     Running   0          2m7s
    shippingservice-5488d5b6cb-lfhtt         2/2     Running   0          2m7s
    

    应用的所有 Pod 都应启动并运行,READY 列中应显示 2/2。这表示 Pod 已成功注入 Envoy 边车代理。 如果几分钟后没有显示 2/2,请查看问题排查指南。

  2. 获取外部 IP 并将其设置为变量:

    kubectl get services -n asm-ingress
    export FRONTEND_IP=$(kubectl --namespace asm-ingress \
    get service --output jsonpath='{.items[0].status.loadBalancer.ingress[0].ip}' \
    )
    

    您将看到类似如下所示的输出:

    NAME                   TYPE           CLUSTER-IP      EXTERNAL-IP   PORT(S)                                      AGE
    asm-ingressgateway   LoadBalancer   10.19.247.233   35.239.7.64   80:31380/TCP,443:31390/TCP,31400:31400/TCP   27m
    
    
  3. 在网络浏览器中访问 EXTERNAL-IP 地址。您应该会在浏览器中看到 Online Boutique 商店。

    Online Boutique 前端

应用速率限制配置

本部分将应用 EnvoyFilter 资源,以将流向 frontend 服务的所有流量限制为 5 个请求/分钟。

  1. 将 CR 应用于 frontend 服务:

    kubectl apply -f - <<EOF
    apiVersion: networking.istio.io/v1alpha3
    kind: EnvoyFilter
    metadata:
      name: frontend-local-ratelimit
      namespace: onlineboutique
    spec:
      workloadSelector:
        labels:
          app: frontend
      configPatches:
        - applyTo: HTTP_FILTER
          match:
            context: SIDECAR_INBOUND
            listener:
              filterChain:
                filter:
                  name: "envoy.filters.network.http_connection_manager"
                  subFilter:
                    name: "envoy.filters.http.router"
          patch:
            operation: INSERT_BEFORE
            value:
              name: envoy.filters.http.local_ratelimit
              typed_config:
                "@type": type.googleapis.com/udpa.type.v1.TypedStruct
                type_url: type.googleapis.com/envoy.extensions.filters.http.local_ratelimit.v3.LocalRateLimit
                value:
                  stat_prefix: http_local_rate_limiter
                  token_bucket:
                    max_tokens: 5
                    tokens_per_fill: 5
                    fill_interval: 60s
                  filter_enabled:
                    runtime_key: local_rate_limit_enabled
                    default_value:
                      numerator: 100
                      denominator: HUNDRED
                  filter_enforced:
                    runtime_key: local_rate_limit_enforced
                    default_value:
                      numerator: 100
                      denominator: HUNDRED
    EOF
    

    预期输出:

    envoyfilter.networking.istio.io/frontend-local-ratelimit created
    
  2. 验证 CR 状态未报告任何错误:

    kubectl get envoyfilter -n onlineboutique frontend-local-ratelimit -o yaml
    

    预期输出:

    ...
    status:
      conditions:
      - lastTransitionTime: "2025-06-30T14:29:25.467017594Z"
        message: This resource has been accepted. This does not mean it has been propagated
          to all proxies yet
        reason: Accepted
        status: "True"
        type: Accepted
    
  3. 移除 loadgenerator 部署,因为它会多次调用服务,从而消耗 token:

    kubectl delete -n onlineboutique deployment loadgenerator
    

    预期输出:

    deployment.apps/loadgenerator deleted
    
  4. 使用 curl 验证在 60 秒内最多允许 5 个请求。429 代码表示正在强制执行速率限制。

    for i in {1..10}; do curl -s http://${FRONTEND_IP} -o /dev/null -w "%{http_code}\n"; sleep 1; done
    

    预期输出:

    200
    200
    200
    200
    200
    429
    429
    429
    429
    429
    

清理

为避免因本教程中使用的资源导致您的 Google Cloud 账号继续产生费用,您可以删除项目或删除各个资源。

删除项目

在 Cloud Shell 中,删除项目:

  gcloud projects delete PROJECT_ID

删除资源

  • 如果您希望保留集群并移除 Online Boutique 示例,请执行以下操作:

    1. 删除应用命名空间:

      kubectl delete namespace onlineboutique
      

      预期输出:

      namespace "onlineboutique" deleted
      
    2. 删除入站流量网关命名空间:

      kubectl delete namespace asm-ingress
      

      预期输出:

      namespace "asm-ingress" deleted
      
  • 如果您想防止产生额外费用,请删除集群:

    gcloud container clusters delete CLUSTER_NAME  \
      --project=PROJECT_ID \
      --zone=CLUSTER_LOCATION 
    

问题排查

请参阅解决数据平面可扩展性问题。