无法使 lua-based EnvoyFilter 工作

Unable to make lua-based EnvoyFilter to work

我正在尝试让 EnvoyFilters 在我的安装中工作。 出于测试目的,我正在尝试设置 lua 过滤器来记录哑消息并将 header 添加到响应中。

这是我的配置:

apiVersion: networking.istio.io/v1alpha3
kind: EnvoyFilter
metadata:
  name: dumb-filter
  namespace: istio-system
spec:
  # workloadSelector:
  #   labels:
  #     istio: ingressgateway
  configPatches:
  # - applyTo: VIRTUAL_HOST
  - applyTo: HTTP_ROUTE
    match:
      context: GATEWAY
      # context: ANY
      routeConfiguration:
        vhost:
          # name: "<domain>:443"
          route:
            #TODO: Understand name compose logic
            name: https.443.https.geth-dedicated.default
    patch:
      operation: MERGE
      value:
        name: envoy.filters.http.lua
        typed_config:
          "@type": type.googleapis.com/envoy.extensions.filters.http.lua.v3.Lua
          inlineCode: |
            function envoy_on_response(response_handle)
              response_handle:headers():add("dm3ch-test", "dm3ch")
              response_handle:logErr("Bye Bye.")
            end

目前我没有看到日志消息或测试 header 响应。 我已经试过了:

Istio 版本信息:

❯ istioctl version
client version: 1.11.4
control plane version: 1.12.0-alpha.1
data plane version: 1.12.0-alpha.1 (1 proxies)

路由配置json:

❯ istioctl proxy-config route istio-ingress-675cb54bc9-5r8cs.istio-system --name https.443.https.geth-dedicated.default -o json
[
    {
        "name": "https.443.https.geth-dedicated.default",
        "virtualHosts": [
            {
                "name": "<domain>:443",
                "domains": [
                    "<domain>",
                    "<domain>:*"
                ],
                "routes": [
                    {
                        "match": {
                            "prefix": "/",
                            "caseSensitive": true
                        },
                        "route": {
                            "cluster": "outbound|8545||geth-dedicated.default.svc.cluster.local",
                            "timeout": "0s",
                            "retryPolicy": {
                                "retryOn": "connect-failure,refused-stream,unavailable,cancelled,retriable-status-codes",
                                "numRetries": 2,
                                "retryHostPredicate": [
                                    {
                                        "name": "envoy.retry_host_predicates.previous_hosts"
                                    }
                                ],
                                "hostSelectionRetryMaxAttempts": "5",
                                "retriableStatusCodes": [
                                    503
                                ]
                            },
                            "hashPolicy": [
                                {
                                    "connectionProperties": {
                                        "sourceIp": true
                                    }
                                }
                            ],
                            "maxGrpcTimeout": "0s"
                        },
                        "metadata": {
                            "filterMetadata": {
                                "istio": {
                                    "config": "/apis/networking.istio.io/v1alpha3/namespaces/default/virtual-service/geth-dedicated"
                                }
                            }
                        },
                        "decorator": {
                            "operation": "geth-dedicated.default.svc.cluster.local:8545/*"
                        }
                    }
                ],
                "includeRequestAttemptCount": true
            }
        ],
        "validateClusters": false

如果有人能咨询我我做错了什么或者我怎样才能更好地调试为什么没有应用过滤器,我会很高兴。

P.S。我的目标是在 request/response 处理 ingressgateway istio 部署期间仅针对特定虚拟服务调用自定义逻辑

问题是你的待办事项#TODO: Understand name compose logic。您需要将此名称值设置为 VirtualService 的路由名称。您还需要使用类型为 LuaPerRoutetyped_per_filter_config

如果您的 VirtualService 看起来像这样:

apiVersion: networking.istio.io/v1beta1
kind: VirtualService
metadata:
  name: reviews-route
spec:
  hosts:
  - reviews.prod.svc.cluster.local
  http:
  - name: "reviews-v2-routes"
    route:
    - destination:
        host: reviews.prod.svc.cluster.local
        subset: v2
  - name: "reviews-v1-route"
    route:
    - destination:
        host: reviews.prod.svc.cluster.local
        subset: v1

您的 EnvoyFilter 需要这样设置:

apiVersion: networking.istio.io/v1alpha3
kind: EnvoyFilter
metadata:
  name: dumb-filter
  namespace: istio-system
spec:
  workloadSelector:
    labels:
      istio: ingressgateway
  configPatches:
  - applyTo: HTTP_ROUTE
    match:
      routeConfiguration:
        vhost:
          route:
            # name from virtual service route that the filter should apply to
            name: reviews-v1-route
    patch:
      operation: MERGE
      value:
        # 'custom' as prefix, can be anything
        name: custom.dumb-filter
        # set lua per route filter
        typed_per_filter_config:
          envoy.filters.http.lua:
            "@type": type.googleapis.com/envoy.extensions.filters.http.lua.v3.LuaPerRoute
            source_code:
              inline_string: |
                function envoy_on_response(response_handle)
                  response_handle:headers():add("dm3ch-test", "dm3ch")
                  response_handle:logErr("Bye Bye.")
                end

注:

这需要一个已经应用的 lua 过滤器,因为 LuaPerRoute 只会覆盖现有过滤器。

Chris 的回答非常有用,但不幸的是它还不够完整。 :(

这是我的发现:

  • 无法在 HTTP_ROUTE 上使用 type.googleapis.com/envoy.extensions.filters.http.lua.v3.Lua 过滤器(但可以使用 LuaPerRoute)
  • type.googleapis.com/envoy.extensions.filters.http.lua.v3.LuaPerRoute 本身不允许定义新的 lua 过滤器,它只允许禁用现有的 Lua 过滤器或覆盖它的源代码 envoy docs

因此,要使 lua 仅应用于一个 http 路由的自定义逻辑,您需要定义“全局”Lua 过滤器并使用 LuaPerRoute 覆盖特定 http 路由的代码过滤器。

这是我的清单,使我能够让它发挥作用:

apiVersion: networking.istio.io/v1beta1
kind: VirtualService
metadata:
  name: geth-dedicated
  namespace: default
spec:
  gateways:
  - geth-dedicated # I'm ommiting gateway creation in this snippet
  hosts:
  - <domain>
  http:
  - match:
    - uri:
        prefix: /
    name: geth-public
    route:
    - destination:
        host: geth-dedicated
        port:
          number: 8545
---
apiVersion: networking.istio.io/v1alpha3
kind: EnvoyFilter
metadata:
  name: dumb-filter
  namespace: istio-system # Namespace where istio gateway pods are actually running
spec:
  workloadSelector:
    labels:
      istio: ingressgateway
  configPatches:
  # Patch that creates "global" lua filter that does nothing useful
  - applyTo: HTTP_FILTER
    match:
      listener:
        filterChain:
          filter:
            name: envoy.filters.network.http_connection_manager
            subFilter:
              name: envoy.filters.http.router
    patch:
      operation: INSERT_BEFORE
      value:
        name: envoy.lua
        typed_config:
          '@type': type.googleapis.com/envoy.extensions.filters.http.lua.v3.Lua
          inlineCode: |
            function envoy_on_request(request_handle)
              -- Empty lua function
            end
  # Filter for http route that overrides "global" filter lua source code
  - applyTo: HTTP_ROUTE
    match:
      context: GATEWAY
      routeConfiguration:
        vhost:
          route:
            name: geth-public # Corresponds to http[0].name in VirtualService
    patch:
      operation: MERGE
      value:
        name: envoy.lua
        typed_per_filter_config:
          envoy.filters.http.lua:
            '@type': type.googleapis.com/envoy.extensions.filters.http.lua.v3.LuaPerRoute
            source_code:
              inline_string: |
                function envoy_on_response(response_handle)
                  response_handle:logErr("Goodbye my brain.")
                  response_handle:headers():add("dm3ch-test", "dm3ch wins")
                end