WasmPlugin资源的调用与绑定流程
在Higress中,WasmPlugin资源是通过一系列步骤被处理、转换并最终绑定到Envoy代理上执行的。以下将详细解释这个过程的代码逻辑和时序。
WasmPlugin资源定义
首先,WasmPlugin是一个Kubernetes自定义资源(CRD),它的定义在API扩展包中.
WasmPlugin资源包含多个关键字段,如URL(指向Wasm模块或OCI容器)、配置信息、执行阶段等:
message WasmPlugin {
// URL of a Wasm module or OCI container. If no scheme is present,
// defaults to `oci://`, referencing an OCI image. Other valid schemes
// are `file://` for referencing .wasm module files present locally
// within the proxy container, and `http[s]://` for .wasm module files
// hosted remotely.
string url = 2;
// SHA256 checksum that will be used to verify Wasm module or OCI container.
// If the `url` field already references a SHA256 (using the `@sha256:`
// notation), it must match the value of this field. If an OCI image is
// referenced by tag and this field is set, its checksum will be verified
// against the contents of this field after pulling.
string sha256 = 3;
// The pull behaviour to be applied when fetching an OCI image. Only
// relevant when images are referenced by tag instead of SHA. Defaults
// to IfNotPresent, except when an OCI image is referenced in the `url`
// and the `latest` tag is used, in which case `Always` is the default,
// mirroring K8s behaviour.
// Setting is ignored if `url` field is referencing a Wasm module directly
// using `file://` or `http[s]://`
PullPolicy image_pull_policy = 4;
// Credentials to use for OCI image pulling.
// Name of a K8s Secret in the same namespace as the `WasmPlugin` that
// contains a docker pull secret which is to be used to authenticate
// against the registry when pulling the image.
string image_pull_secret = 5;
// Public key that will be used to verify signatures of signed OCI images
// or Wasm modules. Must be supplied in PEM format.
string verification_key = 6;
// The configuration that will be passed on to the plugin.
google.protobuf.Struct plugin_config = 7;
// The plugin name to be used in the Envoy configuration (used to be called
// `rootID`). Some .wasm modules might require this value to select the Wasm
// plugin to execute.
string plugin_name = 8;
// Determines where in the filter chain this `WasmPlugin` is to be injected.
PluginPhase phase = 9;
// Determines ordering of `WasmPlugins` in the same `phase`.
// When multiple `WasmPlugins` are applied to the same workload in the
// same `phase`, they will be applied by priority, in descending order.
// If `priority` is not set, or two `WasmPlugins` exist with the same
// value, the ordering will be deterministically derived from name and
// namespace of the `WasmPlugins`. Defaults to `0`.
google.protobuf.Int32Value priority = 10;
// Specifies the failure behavior for the plugin due to fatal errors.
FailStrategy fail_strategy = 13;
// Configuration for a Wasm VM.
// more details can be found [here](https://www.envoyproxy.io/docs/envoy/latest/api-v3/extensions/wasm/v3/wasm.proto#extensions-wasm-v3-vmconfig).
VmConfig vm_config = 11;
// 这里定义了WasmPlugin自定义资源的结构,包含URL、配置信息、执行阶段等关键字段
// Extended by Higress, the default configuration takes effect globally
google.protobuf.Struct default_config = 101;
// Extended by Higress, matching rules take effect
repeated MatchRule match_rules = 102;
// disable the default config
google.protobuf.BoolValue default_config_disable = 103;
}
WasmPlugin资源处理流程
- 资源监听与事件触发
Higress控制器会监听WasmPlugin资源的变化(创建、更新、删除),并触发相应的处理函数。当WasmPlugin资源发生变化时,会调用AddOrUpdateWasmPlugin或DeleteWasmPlugin方法:
- 资源转换
WasmPlugin资源需要被转换为Istio的WasmPlugin格式,这是通过convertIstioWasmPlugin方法实现的:
这个转换过程会处理以下内容:
-
设置选择器,确定插件应用到哪些工作负载
-
复制URL、SHA256等基本信息
-
处理插件配置信息
-
处理VM配置(如环境变量)
// 注册处理WasmPlugin资源变更的处理函数,这些处理函数会将WasmPlugin资源的变更转换为xDS配置,并通过Istio的XDS服务器下发到Envoy代理
func (m *IngressConfig) RegisterEventHandler(kind config.GroupVersionKind, f istiomodel.EventHandler) {
IngressLog.Infof("register resource %v", kind)
switch kind {
case gvk.VirtualService:
m.virtualServiceHandlers = append(m.virtualServiceHandlers, f)
case gvk.Gateway:
m.gatewayHandlers = append(m.gatewayHandlers, f)
case gvk.DestinationRule:
m.destinationRuleHandlers = append(m.destinationRuleHandlers, f)
case gvk.EnvoyFilter:
m.envoyFilterHandlers = append(m.envoyFilterHandlers, f)
case gvk.ServiceEntry:
m.serviceEntryHandlers = append(m.serviceEntryHandlers, f)
// 当资源类型为WasmPlugin时,将处理函数添加到wasmPluginHandlers列表中
case gvk.WasmPlugin:
m.wasmPluginHandlers = append(m.wasmPluginHandlers, f)
}
for _, remoteIngressController := range m.remoteIngressControllers {
remoteIngressController.RegisterEventHandler(kind, f)
}
for _, remoteGatewayController := range m.remoteGatewayControllers {
remoteGatewayController.RegisterEventHandler(kind, f)
}
}
3. 配置处理
WasmPlugin资源支持全局配置和基于规则的匹配配置: ingress_config.go
如果defaultConfigDisable为true且没有有效的匹配规则,则不会生成Istio WasmPlugin资源:
- 资源存储与通知
转换后的Istio WasmPlugin资源会被存储在内存中,并通过处理器函数通知Istio控制平面
当资源被删除时,也会触发相应的通知
WasmPlugin资源的应用
当用户创建一个WasmPlugin资源时, 这个资源会经过上述处理流程,最终被转换为Istio的WasmPlugin资源,并应用到Envoy代理上。
路由级或域名级匹配
WasmPlugin资源支持通过matchRules字段实现更精细的控制,可以将插件应用到特定的入口或域名
代码时序图
插件执行流程
当HTTP请求到达Envoy代理时,Wasm插件会根据其配置的阶段(Phase)和优先级(Priority)在HTTP过滤器链中的特定位置执行:
- 请求阶段:处理请求头部和请求体
- 响应阶段:处理响应头部和响应体
插件的执行是由Envoy的Wasm运行时环境管理的,它会调用插件中注册的各种处理函数,如onHttpRequestHeaders、onHttpRequestBody等。
总结
WasmPlugin资源的处理流程可以概括为以下几个步骤:
- 用户创建或更新WasmPlugin资源
- Higress控制器监听到资源变化并触发处理函数
- 资源被转换为Istio WasmPlugin格式
- 转换后的资源被存储并通知Istio控制平面
- Istio控制平面通过xDS协议将配置下发到Envoy代理
- Envoy代理加载Wasm模块并在HTTP过滤器链中执行插件
这个流程确保了WasmPlugin资源能够正确地被应用到Envoy代理上,并在HTTP请求处理过程中执行相应的逻辑。
WasmPlugin资源的处理流程
- 用户创建或更新WasmPlugin资源
用户通过Kubernetes API创建或更新WasmPlugin自定义资源。这个资源的定义在api/extensions/v1alpha1/wasmplugin.proto文件中
WasmPlugin资源包含多个关键字段,如URL、配置信息、执行阶段等。一个典型的WasmPlugin资源YAML示例如下:
- Higress控制器监听到资源变化并触发处理函数
Higress控制器通过Kubernetes的Informer机制监听WasmPlugin资源的变化。当资源发生变化时,会触发相应的处理函数。
在pkg/ingress/kube/wasmplugin/controller.go中,WasmPluginController负责监听WasmPlugin资源:
type WasmPluginController controller.Controller[listersv1.WasmPluginLister] func NewController(client kubeclient.Client, options common.Options) WasmPluginController { var informer cache.SharedIndexInformer if options.WatchNamespace == "" { informer = client.HigressInformer().Extensions().V1alpha1().WasmPlugins().Informer() } else { informer = client.HigressInformer().InformerFor(&v1.WasmPlugin{}, func(client versioned.Interface, resyncPeriod time.Duration) cache.SharedIndexInformer { return informersv1.NewWasmPluginInformer(client, options.WatchNamespace, resyncPeriod, nil) }) } return controller.NewCommonController("wasmplugin", listersv1.NewWasmPluginLister(informer.GetIndexer()), informer, GetWasmPlugin, options.ClusterId) } func GetWasmPlugin(lister listersv1.WasmPluginLister, namespacedName types.NamespacedName) (controllers.Object, error) { return lister.WasmPlugins(namespacedName.Namespace).Get(namespacedName.Name) } // WasmPluginController监听WasmPlugin资源的变化 // 当WasmPlugin资源发生变化时,该控制器会被触发相应的处理函数 type WasmPluginController struct { // 客户端接口,用于与Kubernetes API交互 client client.Interface // WasmPlugin资源的列表器,用于获取WasmPlugin资源 wasmPluginLister listerv1.WasmPluginLister // WasmPlugin资源的共享索引通知器,用于监听资源变化 wasmPluginInformer cache.SharedIndexInformer // 处理函数列表,当资源变化时会调用这些函数 handlers [] func (util.ClusterNamespacedName) }
当WasmPlugin资源发生变化时,会调用AddOrUpdateWasmPlugin方法: ingress_config.go:1045-1054
这个方法首先检查资源的命名空间是否匹配,然后从lister中获取WasmPlugin资源。
- 资源被转换为Istio WasmPlugin格式
获取到WasmPlugin资源后,需要将其转换为Istio的WasmPlugin格式,这是通过convertIstioWasmPlugin方法实现的.
这个转换过程会处理以下内容:
- 设置选择器,确定插件应用到哪些工作负载(通过
Selector字段) - 复制URL、SHA256等基本信息
- 处理插件配置信息(
PluginConfig字段) - 设置执行阶段(
Phase字段)和优先级(Priority字段) - 设置失败策略(
FailStrategy字段)
- 配置处理
WasmPlugin资源支持全局配置和基于规则的匹配配置。如果设置了defaultConfigDisable为true且没有有效的匹配规则,则不会生成Istio WasmPlugin资源: ingress_config.go:934-939 ingress_config.go:1035-1038
这里的逻辑是:
- 如果
DefaultConfigDisable为false,则使用DefaultConfig作为插件配置 - 如果有匹配规则,则处理匹配规则
- 如果
DefaultConfigDisable为true且没有有效的匹配规则,则返回nil,不生成资源 - 转换后的资源被存储并通知Istio控制平面
转换后的Istio WasmPlugin资源会被存储在内存中,并通过处理器函数通知Istio控制平面
这里的代码将转换后的WasmPlugin资源存储在wasmPlugins映射中,然后通过wasmPluginHandlers通知Istio控制平面。
当资源被删除时,也会触发相应的通知: ingress_config.go:1096-1108
这里的代码从wasmPlugins映射中删除资源,然后通过wasmPluginHandlers通知Istio控制平面资源已被删除。
- Istio控制平面通过xDS协议将配置下发到Envoy代理
Istio控制平面(Istiod)接收到WasmPlugin资源的变更通知后,会将其转换为Envoy的配置,并通过xDS协议下发到Envoy代理。
在pkg/ingress/config/ingress_config.go中,RegisterEventHandler方法注册了处理WasmPlugin资源变更的处理函数:
func (m *IngressConfig) RegisterEventHandler(kind config.GroupVersionKind, f istiomodel.EventHandler) {
IngressLog.Infof("register resource %v", kind)
switch kind {
// ...其他资源类型...
case gvk.WasmPlugin:
m.wasmPluginHandlers = append(m.wasmPluginHandlers, f)
}
// ...
}
这些处理函数会将WasmPlugin资源的变更转换为xDS配置,并通过Istio的XDS服务器下发到Envoy代理。
- Envoy代理加载Wasm模块并在HTTP过滤器链中执行插件
Envoy代理接收到xDS配置后,会加载Wasm模块并在HTTP过滤器链中执行插件。
Wasm插件在Envoy中的执行是由Envoy的Wasm运行时环境管理的。根据插件的配置(如Phase和Priority),插件会在HTTP过滤器链中的特定位置执行。
插件的执行流程如下:
- 请求阶段:处理请求头部(
onHttpRequestHeaders)和请求体(onHttpRequestBody) - 响应阶段:处理响应头部(
onHttpResponseHeaders)和响应体(onHttpResponseBody)