EnvoyFilter 提供了一种机制来定制 Istio Pilot 生成的 Envoy 配置。使用 EnvoyFilter 修改某些字段的值,添加特定的过滤器,甚至添加全新的侦听器、集群等。
EnvoyFilter 生效的顺序:
- 首先是配置在根命名空间中的所有 EnvoyFilter,
- 其次是配置在工作负载命名空间中的所有匹配的 EnvoyFilter
根命名空间(Root Namespace): MeshConfig 中配置的 rootNamespace
注意:
- 当多个 EnvoyFilter 被绑定到给定命名空间中的相同工作负载时,将按照创建时间的顺序依次应用。如果有多个 EnvoyFilter 配置相互冲突,那么将无法确定哪个配置被应用。
- 要将 EnvoyFilter 资源应用于系统中的所有工作负载(sidecar 和 gateway)上,请在 config 根命名空间中定义该资源,不要使用 workloadSelector。
- 要将 EnvoyFilter 应用到系统中的所有工作负载( sidecar 和网关)的时候,建议在配置根命名空间中定义,而不要使用 workloadSelector 。
属性 | 数据类型 | 说明 | 是否必填 |
---|---|---|---|
workloadSelector | WorkloadSelector | 用于选择应用此补丁的pod或虚拟机 | 否 |
configPatches | EnvoyConfigObjectPatch[] | 具有匹配条件的补丁 | 是 |
priority | int32 | 定义了补丁集在上下文中应用顺序的优先级 | 否 |
其中,如果 workloadSelector 没有被配置,此补丁将应用于相同名称空间中所有工作负载的实例; priority 的默认值为0,取值范围是[min-int32, max-int32], priority 为负的补丁将在默认priority 之前处理,priority 为正的补丁将在默认priority 之后处理。
属性 | 数据类型 | 说明 | 是否必填 |
---|---|---|---|
applyTo | ApplyTo | 指定在Envoy配置中应用补丁的位置 | 否 |
match | EnvoyConfigObjectMatch | 用于匹配监听器、路由或集群 | 否 |
patch | Patch | 与操作一起应用的补丁。 | 否 |
其中,ApplyTo可以配置的值有:
名称 | 说明 |
---|---|
LISTENER | 将补丁应用于监听器。 |
FILTER_CHAIN | 将补丁应用于过滤器链。 |
NETWORK_FILTER | 应用补丁到网络过滤器链,修改现有的过滤器或添加一个新的过滤器。 |
HTTP_FILTER | 将补丁应用于HTTP连接管理器中的HTTP过滤器链,以修改现有的过滤器或添加新的过滤器。 |
ROUTE_CONFIGURATION | 将补丁应用于HTTP连接管理器内的Route配置。 |
VIRTUAL_HOST | 将补丁应用于路由配置内部的虚拟主机。 |
HTTP_ROUTE | 在路由配置中将补丁应用于匹配的虚拟主机内的路由对象。 |
CLUSTER | 将补丁应用到集群。 |
EXTENSION_CONFIG | 在ECDS输出中应用补丁或添加扩展配置。 |
BOOTSTRAP | 将补丁应用于初始化配置。 |
Field | Type | Description | Required |
---|---|---|---|
operation | Operation | Determines how the patch should be applied. | No |
value | Struct5 | The JSON config of the object being patched. This will be merged using proto merge semantics with the existing proto in the path. | No |
filterClass | FilterClass | Determines the filter insertion order. | No |
Name | Description |
---|---|
INVALID | |
MERGE | Merge the provided config with the generated config using
proto merge semantics. If you are specifying config in its
entirety, use |
ADD | Add the provided config to an existing list (of listeners,
clusters, virtual hosts, network filters, or http
filters). This operation will be ignored when |
REMOVE | Remove the selected object from the list (of listeners,
clusters, virtual hosts, network filters, routes, or http
filters). Does not require a value to be specified. This
operation will be ignored when |
INSERT_BEFORE | Insert operation on an array of named objects. This operation is typically useful only in the context of filters or routes, where the order of elements matter. Routes should be ordered based on most to least specific matching criteria since the first matching element is selected. For clusters and virtual hosts, order of the element in the array does not matter. Insert before the selected filter or sub filter. If no filter is selected, the specified filter will be inserted at the front of the list. |
INSERT_AFTER | Insert operation on an array of named objects. This operation is typically useful only in the context of filters or routes, where the order of elements matter. Routes should be ordered based on most to least specific matching criteria since the first matching element is selected. For clusters and virtual hosts, order of the element in the array does not matter. Insert after the selected filter or sub filter. If no filter is selected, the specified filter will be inserted at the end of the list. |
INSERT_FIRST | Insert operation on an array of named objects. This operation is typically useful only in the context of filters or routes, where the order of elements matter. Routes should be ordered based on most to least specific matching criteria since the first matching element is selected. For clusters and virtual hosts, order of the element in the array does not matter. Insert first in the list based on the presence of selected filter or not. This is specifically useful when you want your filter first in the list based on a match condition specified in Match clause. |
REPLACE | Replace contents of a named filter with new contents.
|
Name | Description |
---|---|
UNSPECIFIED | Control plane decides where to insert the filter.
Do not specify |
AUTHN | Insert filter after Istio authentication filters. |
AUTHZ | Insert filter after Istio authorization filters. |
STATS | Insert filter before Istio stats filters. |
Name | Description |
---|---|
ANY | All listeners/routes/clusters in both sidecars and gateways. |
SIDECAR_INBOUND | Inbound listener/route/cluster in sidecar. |
SIDECAR_OUTBOUND | Outbound listener/route/cluster in sidecar. |
GATEWAY | Gateway listener/route/cluster. |
Envoy 缺省会把 http header 的 key 转换为小写,例如有一个 http header Test-Upper-Case-Header: some-value,经过 envoy 代理后会变成 test-upper-case-header: some-value。这个在正常情况下没问题,RFC 2616 规范也说明了处理 HTTP Header 应该是大小写不敏感的。 Envoy 只支持两种规则:
- 全小写 (默认使用的规则)
- 首字母大写 (默认没有启用)
apiVersion: networking.istio.io/v1alpha3
kind: EnvoyFilter
metadata:
name: http-header-proper-case-words
namespace: istio-system
spec:
configPatches:
- applyTo: NETWORK_FILTER # http connection manager is a filter in Envoy
match:
# context omitted so that this applies to both sidecars and gateways
listener:
name: XXX # 指定 cos 使用的listener name,可以从config_dump中查询到
filterChain:
filter:
name: "envoy.http_connection_manager"
patch:
operation: MERGE
value:
name: "envoy.http_connection_manager"
typed_config:
"@type": "type.googleapis.com/envoy.config.filter.network.http_connection_manager.v2.HttpConnectionManager"
http_protocol_options:
header_key_format:
proper_case_words: {}
apiVersion: networking.istio.io/v1alpha3
kind: EnvoyFilter
metadata:
name: http-options
namespace: istio-system
spec:
configPatches:
- applyTo: NETWORK_FILTER
match:
context: ANY
listener:
filterChain:
filter:
name: "envoy.http_connection_manager"
patch:
operation: MERGE
value:
typed_config:
"@type": "type.googleapis.com/envoy.extensions.filters.network.http_connection_manager.v3.HttpConnectionManager"
max_request_headers_kb: 96 # 96KB, 请求 header 最大限制
- applyTo: HTTP_FILTER
match:
context: GATEWAY
listener:
filterChain:
filter:
name: "envoy.http_connection_manager"
patch:
operation: INSERT_BEFORE
value:
name: "envoy.filters.http.buffer"
typed_config:
'@type': "type.googleapis.com/envoy.extensions.filters.http.buffer.v3.Buffer"
max_request_bytes: 1048576 # 1MB, 请求最大限制
The example below declares a global default EnvoyFilter resource in the root namespace called istio-config, that adds a custom protocol filter on all sidecars in the system, for outbound port 9307. The filter should be added before the terminating tcp_proxy filter to take effect. In addition, it sets a 30s idle timeout for all HTTP connections in both gateways and sidecars.
apiVersion: networking.istio.io/v1alpha3
kind: EnvoyFilter
metadata:
name: custom-protocol
namespace: istio-config # as defined in meshConfig resource.
spec:
configPatches:
- applyTo: NETWORK_FILTER
match:
context: SIDECAR_OUTBOUND # will match outbound listeners in all sidecars
listener:
portNumber: 9307
filterChain:
filter:
name: "envoy.filters.network.tcp_proxy"
patch:
operation: INSERT_BEFORE
value:
# This is the full filter config including the name and typed_config section.
name: "envoy.extensions.filters.network.mongo_proxy"
typed_config:
"@type": "type.googleapis.com/envoy.extensions.filters.network.mongo_proxy.v3.MongoProxy"
...
- applyTo: NETWORK_FILTER # http connection manager is a filter in Envoy
match:
# context omitted so that this applies to both sidecars and gateways
listener:
filterChain:
filter:
name: "envoy.filters.network.http_connection_manager"
patch:
operation: MERGE
value:
name: "envoy.filters.network.http_connection_manager"
typed_config:
"@type": "type.googleapis.com/envoy.extensions.filters.network.http_connection_manager.v3.HttpConnectionManager"
common_http_protocol_options:
idle_timeout: 30s
The following example enables Envoy’s Lua filter for all inbound HTTP calls arriving at service port 8080 of the reviews service pod with labels “app: reviews”, in the bookinfo namespace. The lua filter calls out to an external service internal.org.net:8888 that requires a special cluster definition in envoy. The cluster is also added to the sidecar as part of this configuration.
apiVersion: networking.istio.io/v1alpha3
kind: EnvoyFilter
metadata:
name: reviews-lua
namespace: bookinfo
spec:
workloadSelector:
labels:
app: reviews
configPatches:
# The first patch adds the lua filter to the listener/http connection manager
- applyTo: HTTP_FILTER
match:
context: SIDECAR_INBOUND
listener:
portNumber: 8080
filterChain:
filter:
name: "envoy.filters.network.http_connection_manager"
subFilter:
name: "envoy.filters.http.router"
patch:
operation: INSERT_BEFORE
value: # lua filter specification
name: envoy.filters.http.lua
typed_config:
"@type": "type.googleapis.com/envoy.extensions.filters.http.lua.v3.Lua"
inlineCode: |
function envoy_on_request(request_handle)
-- Make an HTTP call to an upstream host with the following headers, body, and timeout.
local headers, body = request_handle:httpCall(
"lua_cluster",
{
[":method"] = "POST",
[":path"] = "/acl",
[":authority"] = "internal.org.net"
},
"authorize call",
5000)
end
# The second patch adds the cluster that is referenced by the lua code
# cds match is omitted as a new cluster is being added
- applyTo: CLUSTER
match:
context: SIDECAR_OUTBOUND
patch:
operation: ADD
value: # cluster specification
name: "lua_cluster"
type: STRICT_DNS
connect_timeout: 0.5s
lb_policy: ROUND_ROBIN
load_assignment:
cluster_name: lua_cluster
endpoints:
- lb_endpoints:
- endpoint:
address:
socket_address:
protocol: TCP
address: "internal.org.net"
port_value: 8888
The following example overwrites certain fields (HTTP idle timeout and X-Forward-For trusted hops) in the HTTP connection manager in a listener on the ingress gateway in istio-system namespace for the SNI host app.example.com:
apiVersion: networking.istio.io/v1alpha3
kind: EnvoyFilter
metadata:
name: hcm-tweaks
namespace: istio-system
spec:
workloadSelector:
labels:
istio: ingressgateway
configPatches:
- applyTo: NETWORK_FILTER # http connection manager is a filter in Envoy
match:
context: GATEWAY
listener:
filterChain:
sni: app.example.com
filter:
name: "envoy.filters.network.http_connection_manager"
patch:
operation: MERGE
value:
typed_config:
"@type": "type.googleapis.com/envoy.extensions.filters.network.http_connection_manager.v3.HttpConnectionManager"
xff_num_trusted_hops: 5
common_http_protocol_options:
idle_timeout: 30s
apiVersion: networking.istio.io/v1alpha3
kind: EnvoyFilter
metadata:
name: myns-ext-authz
namespace: myns
spec:
configPatches:
- applyTo: HTTP_FILTER
match:
context: SIDECAR_INBOUND
patch:
operation: ADD
filterClass: AUTHZ # This filter will run *after* the Istio authz filter.
value:
name: envoy.filters.http.ext_authz
typed_config:
"@type": type.googleapis.com/envoy.extensions.filters.http.ext_authz.v3.ExtAuthz
grpc_service:
envoy_grpc:
cluster_name: acme-ext-authz
initial_metadata:
- key: foo
value: myauth.acme # required by local ext auth server.
apiVersion: networking.istio.io/v1alpha3
kind: EnvoyFilter
metadata:
name: higress-trace
namespace: higress-system
spec:
configPatches:
- applyTo: NETWORK_FILTER
match:
context: GATEWAY
listener:
filterChain:
filter:
name: envoy.filters.network.http_connection_manager
patch:
operation: MERGE
value:
name: envoy.filters.network.http_connection_manager
typed_config:
'@type': type.googleapis.com/envoy.extensions.filters.network.http_connection_manager.v3.HttpConnectionManager
tracing:
provider:
name: envoy.tracers.skywalking
typed_config:
'@type': type.googleapis.com/envoy.config.trace.v3.SkyWalkingConfig
client_config:
service_name: gateway
grpc_service:
envoy_grpc:
cluster_name: outbound|11800||skywalking-oap-server.op-system.svc.cluster.local
timeout: 0.250s
random_sampling:
value: 100
- applyTo: HTTP_FILTER
match:
context: GATEWAY
listener:
filterChain:
filter:
name: envoy.filters.network.http_connection_manager
subFilter:
name: envoy.filters.http.router
patch:
operation: MERGE
value:
name: envoy.filters.http.router
typed_config:
'@type': type.googleapis.com/envoy.extensions.filters.http.router.v3.Router
start_child_span: true
Envoy Filter 分为三类:
- Listener Filter:用于操作处理 L4 连接中的元数据。
- Network Filter:用于操作处理 L4 连接中的原始数据。
- HTTP Filter:用于操作处理 L7 连接中的 HTTP 请求与响应。
每个监听器同样会定义一组位于数据路径中的 Filter,并形成一组过滤器链 Filter Chain。通过这样的一组过滤器,用户可以配置 Envoy 来针对出站流量做特定的任务,包括数据协议处理、生成调用的统计信息、执行 RBAC 权限等
为了更好地理解这些 Envoy Filter 以及 Filter Chain,下面来看一个实际的例子。这个就是 Istio 官方示例 bookinfo 中的第一个服务 productpage。首先, productpage pod 中 Envoy Proxy 配置了一个监听 9080 端口的监听器,进入这个 pod 的端口 9080 上的流量请求都会被拦截到这个 proxy 中,然后请求就会经过这些 Filter Chain 进行处理。具体如下:
-
第一个 filter 是 envoy.filters.network.metadata_exchange,它的主要作用顾名思义,用来在 filter 之间交换元数据。
-
第二个 filter: envoy.http_connection_manager,它下面通常会有以下几个跟 http 特定的 filter,包括:
-
envoy.filters.http.wasm/envoy.wasm.metadata_exchange(用于元数据交互)
-
Istio_authn filter(用于授权认证)
-
envoy.filters.http.cors(处理跨域资源共享的 filter)
-
envoy.filters.http.fault(故障注入过滤器,可以用来测试微服务架构中容错能力,用户可以自定义错误代码来实现延时注入或者终止请求,在不同的失败场景下提供错误处理的能力,例如服务失败、服务过载、服务高延时等情况,这个也是较为常用的 filter)
-
envoy.filters.http.wasm/envoy.wasm.stats、envoy.filters.http.wasm/xxx-wasmfilter(用户自定义的 wasm 实现的filter)
-
envoy.filters.http.router(实现 HTTP 转发,几乎所有 HTTP 场景下都会使用到这一过滤器)
-
备注:可以通过请求这个 URL 地址获取配置信息:kubectl exec -it [productpage-xxx] -c istio-proxy curl localhost:15000/config_dump