Day 17 / 共 20 天 · 第 4 周 遥测/扩展/安装
EnvoyFilter(Higress 重用)
这是理解 Higress 怎么在 Istio 上做增强的关键一课。EnvoyFilter 是"逃生舱"——直接给 istiod 生成的 Envoy 配置打补丁。Higress 大量用它来实现 Wasm 插件、自定义 filter。
📍 你在整门课的位置 · 第 4 周「遥测 / 扩展 / 安装」(W1-3 全部 ✓)
D16 遥测→
D17 EnvoyFilter→
D18 istioctl→
D19 安装→
D20 收官
L01
逃生舱
🤔 痛点:Istio 的高层 CRD 覆盖不到我想要的 Envoy 功能
你想给 Envoy 开一个冷门 filter、调一个 Istio 没暴露的参数——翻遍 VirtualService/DestinationRule 都没有对应字段。难道就因为 Istio 没暴露高层 API,这个 Envoy 明明有的能力就用不了?
💡 本质:精装房交付后,允许你"自己动手改一处"
istiod 按高层 CRD 生成的 Envoy 配置,好比开发商交付的精装房——大部分够用,但总有几处你想改。EnvoyFilter 就是那把"允许业主自己动手改"的钥匙:在房子(配置)交付前的最后一刻,让你直接对墙面/管线(Envoy 配置对象)加一处、改一处、拆一处。强大,但也危险——改错了房子会塌(Envoy 崩)。所以它是"逃生舱",最后手段。而 Higress 恰恰把这把钥匙用到了极致(Wasm 插件全靠它注入)。
EnvoyFilter = "配置的最后一道手动改写"
istiod 从 VirtualService/DestinationRule 等高层 CRD 生成 Envoy 配置(Day 07-08)。但高层 CRD 覆盖不了 Envoy 的所有能力——有些 Envoy 高级功能(特定 filter、特殊参数)Istio 没暴露高层 API。EnvoyFilter 就是"逃生舱":让你直接对 istiod 生成的 Envoy 配置打补丁(加一个 filter、改一个字段、删一个东西)。好比"生成的配置我不满意,我手动改几处"。它强大但危险(直接操作 Envoy 底层配置,写错会崩),是"最后手段"。而 Higress 恰恰重度依赖它——因为 Higress 的很多增强能力(Wasm 插件、AI 网关 filter)就是通过 EnvoyFilter 注入的。
L02
CRD 结构
// pilot/pkg/model/envoyfilter.go:36 EnvoyFilterWrapper
// Patches map[ApplyTo][]*EnvoyFilterConfigPatchWrapper // 按 ApplyTo 分组
// Priority
// :81 EnvoyFilterConfigPatchWrapper:
// Value proto.Message(编译好的 patch 值)、Match、ApplyTo、Operation
// WasmPhase / WasmPriority(:86-87,Higress 定制!)
读法:EnvoyFilter 由一组 patch 组成。每个 patch:
ApplyTo(改哪类对象:LISTENER/HTTP_FILTER/CLUSTER…)、Match(匹配哪些具体对象)、Operation(怎么改:ADD/MERGE/REMOVE/INSERT_BEFORE…)、Value(改成什么)。Higress 加了 WasmPhase/WasmPriority——用于 Wasm 插件的执行阶段和优先级排序(L07)。📝 举个例子:一条 patch 读作一句话
applyTo: HTTP_FILTER + match: {listener: 8080, filterChain: {filter: HttpConnectionManager}} + operation: INSERT_BEFORE + value: {name: my.wasm ...}
→ 读作:"在 8080 端口那条 HCM 的 HTTP 过滤器链里,往 router 之前插一个我的 Wasm 过滤器"。四要素连起来就是一句完整的改装指令:改哪类(ApplyTo)、改哪个(Match)、怎么改(Operation)、改成啥(Value)。L03
CRD → wrapper
// envoyfilter.go:115 convertToEnvoyFilterWrapper
// 逐条 ConfigPatches 转换
// cpw.WasmPhase/WasmPriority = ...(:166 Higress)
// xds.BuildXDSObjectFromStruct(:172)非严格模式编译 patch value 成 proto
// wellKnownVersions(:102)把常见版本正则优化成前缀匹配
读法:EnvoyFilter CRD 被编译成内部 wrapper(把 patch value 从 YAML/struct 编译成 proto 对象)。非严格模式编译——为了兼容不同 Envoy API 版本(patch 可能引用较新/较旧的字段)。版本匹配正则优化(
wellKnownVersions)避免每次跑正则的开销。L04
patch 应用
// pilot/pkg/networking/core/envoyfilter/ 三个应用入口:
// listener_patch.go:40 ApplyListenerPatches
// cluster_patch.go:34 ApplyClusterMerge
// rc_patch.go:34 ApplyRouteConfigurationPatches
// Operation 语义:MERGE(合并字段)、REMOVE(删除)、ADD(新增)、INSERT_BEFORE/AFTER(过滤器链插入)
读法:生成 Listener/Cluster/Route 后(Day 08),在这里应用 EnvoyFilter 补丁。
MERGE 合并字段(改现有对象)、ADD 新增、INSERT_BEFORE/AFTER 在过滤器链的特定位置插入过滤器。这就是 Day 08 提到的 patchListeners()。L05
crash 保护
// listener_patch.go:40 ApplyListenerPatches
// 用 runtime.HandleCrash(:46)包裹 —— patch 出错 panic 不会拖垮整个推送
// 回退到 patch 前的 listener(:51)
为什么 patch 要"崩溃保护"?
EnvoyFilter 是用户手写的底层补丁——很容易写错(引用不存在的字段、类型不匹配)。如果一个坏 patch 导致 panic,可能拖垮整个 istiod 的配置推送(影响所有 Envoy)。所以应用 patch 时用
runtime.HandleCrash 包裹:某个 patch 崩了,捕获它、回退到打补丁前的配置、继续处理其他的——一个坏 patch 不会连累全局。这是"隔离故障"的防御性设计——对"用户可能写错的强大功能"必须加保护网。L06
生成流水线插入
EnvoyFilter 在 core 生成流程的固定点被应用:cluster.go 取 Push.EnvoyFilters(proxy) 后 ApplyClusterMerge;gateway.go/httproute.go 调 ApplyRouteConfigurationPatches;listener 在 patchListeners()(Day 08)。
读法:EnvoyFilter 是生成流水线的"最后一道工序"——istiod 先按高层 CRD 生成基础配置,然后过一遍 EnvoyFilter 补丁做微调/增强。所以它能改动几乎任何生成结果。这就是它作为"逃生舱"的位置——在标准生成之后、下发之前。
EnvoyFilter 卡在"生成完基础配置"和"下发给 Envoy"之间——所以它能对任何生成结果动手,也所以它一崩就影响下发(需崩溃保护,L05)。
⚠️ 常见误解:以为 EnvoyFilter 是"另一种写配置的方式",随便用。其实它是对生成结果打补丁,强耦合 Envoy 内部结构——Envoy 版本一升、字段一改,你的 patch 可能静默失效。能用高层 CRD 就别用它,它是覆盖不到时的最后手段。
L07
Higress 的 WasmPhase
Higress 怎么用 EnvoyFilter 做插件生态:
Higress 的 Wasm 插件(用 wasm-go 写,本系列最后一站)就是通过 EnvoyFilter 注入到 Envoy 的——把 Wasm filter 用
Higress 给 EnvoyFilter 加了
所以 EnvoyFilter 是 Istio(Day 17)、Envoy Wasm(Envoy 课 Day 17)、wasm-go(本系列末站)三者的连接枢纽:wasm-go 写插件 → 编译成 wasm → Higress 用 EnvoyFilter 把它插进 Envoy 过滤器链 → Envoy 的 Wasm runtime 执行。理解了这条链,就理解了整个 Higress 插件生态的技术底座。
Higress 的 Wasm 插件(用 wasm-go 写,本系列最后一站)就是通过 EnvoyFilter 注入到 Envoy 的——把 Wasm filter 用
INSERT_BEFORE/AFTER 插进过滤器链。Higress 给 EnvoyFilter 加了
WasmPhase(执行阶段:认证/统计/…)和 WasmPriority(同阶段内的优先级)——让多个 Wasm 插件能按"阶段 + 优先级"有序编排(比如认证插件在限流插件之前)。所以 EnvoyFilter 是 Istio(Day 17)、Envoy Wasm(Envoy 课 Day 17)、wasm-go(本系列末站)三者的连接枢纽:wasm-go 写插件 → 编译成 wasm → Higress 用 EnvoyFilter 把它插进 Envoy 过滤器链 → Envoy 的 Wasm runtime 执行。理解了这条链,就理解了整个 Higress 插件生态的技术底座。
L08
今日小结 + 动手
🧠 今天你应该能回答
- EnvoyFilter 为什么叫"逃生舱"?它在什么时候用?
- patch 的 ApplyTo/Operation/Match/Value 各是什么?
- 为什么 patch 应用要 crash 保护?
- EnvoyFilter 在生成流水线的什么位置?
- Higress 的 WasmPhase/WasmPriority 干什么?它怎么连接 Istio/Envoy/wasm-go?
✋ 动手
cd /Users/bitmart/work/codes/github/higress-group/istio
grep -n 'EnvoyFilterWrapper\|WasmPhase\|convertToEnvoyFilterWrapper' pilot/pkg/model/envoyfilter.go
grep -n 'func ApplyListenerPatches\|runtime.HandleCrash' pilot/pkg/networking/core/envoyfilter/listener_patch.go
明天预告 · Day 18:istioctl CLI——运维网格的命令行工具:install(安装)、analyze(静态体检)、proxy-config(看 Envoy 实际配置)、proxy-status(对比期望 vs 实况)。