3. Mutating 与 Validating Webhook:两种 Webhook 的区别、调用顺序、典型应用场景
Kubernetes 准入控制(Admission Control)中的 Webhook 分为 MutatingAdmissionWebhook 和 ValidatingAdmissionWebhook 两种类型。它们在 API 请求持久化之前介入,但职责、调用顺序和典型用途截然不同。理解两者的差异是编写可靠 Webhook 的基础,也是校准存储版本漂移的关键前提。
3.1 核心职责对比
| 对比维度 | Mutating Webhook | Validating Webhook |
|---|---|---|
| 核心职责 | 修改(Mutate)传入的对象 | 校验(Validate)传入的对象 |
| 是否可修改对象 | 是,可增删改字段、注入 Sidecar、设置默认值 | 否,只能读取,不可修改 |
| 返回结果 | 返回修改后的对象 JSON Patch | 返回允许(Allowed)或拒绝(Denied) |
| 失败策略 | Fail / Ignore | Fail / Ignore |
| 超时控制 | 30 秒(可配置) | 30 秒(可配置) |
| 幂等性要求 | 必须幂等,避免重复注入 | 通常无幂等要求 |
关键原则:Mutating Webhook 必须保证幂等性。如果同一个 Pod 创建请求被多次拦截,注入 Sidecar 的 JSON Patch 不能重复添加同一个容器或 Volume,否则会导致 API 请求失败。
3.2 调用顺序与执行流程
在 Kubernetes API Server 处理一个创建、更新或删除请求时,Webhook 的调用顺序是固定的:
- 认证与授权(非 Webhook 阶段)
- Mutating Webhooks(按配置顺序执行)
- 对象 Schema 校验(内置校验)
- Validating Webhooks(按配置顺序执行)
- 持久化到 etcd
这种顺序设计有明确的工程考量:先让 Mutating Webhook 修改对象(如注入 Sidecar、设置默认值),再让 Validating Webhook 对修改后的完整对象进行校验。如果顺序颠倒,Validating Webhook 校验的将是一个不完整的对象,导致误判。
存储版本漂移校准提示:当 Webhook 修改了对象字段(Mutating),但 etcd 中存储的版本与 Webhook 修改后的版本不一致时,Validating Webhook 可能基于旧版本规则进行校验,导致拒绝本应通过的请求。校准策略通常是在 Validating Webhook 中增加版本兼容性检查。
3.3 典型应用场景
3.3.1 Mutating Webhook:注入 Sidecar
最经典的 Mutating Webhook 场景是 Sidecar 注入,例如 Istio 的 sidecar-injector。当用户创建 Pod 时,Webhook 拦截请求,自动向 Pod 的 spec.containers 中添加一个 Envoy 代理容器,并挂载必要的 Volume。
// 注入 Sidecar 的 JSON Patch 示例
[
{
"op": "add",
"path": "/spec/containers/-",
"value": {
"name": "istio-proxy",
"image": "istio/proxyv2:1.18.0",
"args": ["proxy", "sidecar"],
"ports": [
{ "containerPort": 15090, "protocol": "TCP" }
]
}
},
{
"op": "add",
"path": "/spec/volumes/-",
"value": {
"name": "istio-envoy",
"emptyDir": {}
}
}
]
幂等性陷阱:如果 Webhook 不检查容器是否已存在,直接执行
add 操作,当请求被重试或 Webhook 被多次调用时,Pod 中会出现多个同名容器,导致 API Server 拒绝该请求。正确的做法是先检查 /spec/containers 中是否已有 name: istio-proxy,有则跳过。
3.3.2 Validating Webhook:校验规则
Validating Webhook 用于执行 不可修改的校验逻辑,例如:
- 资源配额校验:检查 Namespace 中 Deployment 的总副本数是否超过限制。
- 安全策略校验:禁止容器以 root 用户运行,或禁止使用 hostNetwork。
- 存储版本兼容性校验:检查请求中的资源版本是否与集群中存储的版本兼容,防止存储版本漂移导致的数据不一致。
- 命名规范校验:强制资源名称符合正则表达式规则。
// Validating Webhook 拒绝响应示例
{
"apiVersion": "admission.k8s.io/v1",
"kind": "AdmissionReview",
"response": {
"uid": "705ab4f5-6393-11e8-b7cc-42010a800002",
"allowed": false,
"status": {
"code": 403,
"message": "Pod 使用 hostNetwork 被禁止,请移除 spec.hostNetwork: true"
}
}
}
3.4 两种 Webhook 的协同工作模式
在实际生产环境中,Mutating 和 Validating Webhook 经常配合使用,形成完整的准入控制链:
3.5 存储版本漂移场景下的选择建议
校准策略:在存储版本漂移校准场景中,建议将版本兼容性检查放在 Validating Webhook 中,将字段自动修正(如填充默认值、转换旧版本字段)放在 Mutating Webhook 中。这样既保证了修改的灵活性,又确保了最终对象的合规性。
| 漂移类型 | 推荐 Webhook 类型 | 处理方式 |
|---|---|---|
| 字段缺失(旧版本无新字段) | Mutating Webhook | 自动添加默认值 |
| 字段值不合法(新版本约束更严) | Validating Webhook | 拒绝并提示升级 |
| 字段结构变更(如 v1 与 v2 字段映射) | Mutating Webhook | 执行字段转换 JSON Patch |
| 版本兼容性校验 | Validating Webhook | 检查 apiVersion 是否在允许列表中 |