3. Admission Webhook 分类:MutatingAdmissionWebhook 与 ValidatingAdmissionWebhook 的区别与适用场景
在 Kubernetes 准入控制链中,Admission Webhook 是动态扩展准入逻辑的核心机制。根据对请求资源的修改权限,官方将其明确划分为两类:MutatingAdmissionWebhook(变更型)与 ValidatingAdmissionWebhook(验证型)。理解两者的本质区别与适用场景,是正确设计 Webhook 控制器的基础。
3.1 核心区别:变更 vs. 验证
两类 Webhook 在 API 请求处理流程中的位置不同,职责边界清晰:
| 对比维度 | MutatingAdmissionWebhook | ValidatingAdmissionWebhook |
|---|---|---|
| 核心职责 | 修改(Patch)传入的请求对象 | 校验(Validate)请求对象是否合规 |
| 执行顺序 | 先执行(在 API 对象持久化之前) | 后执行(在 Mutating 完成后) |
| 响应类型 | 返回 JSON Patch 或 JSON Merge Patch | 返回 allowed: true/false + 拒绝原因 |
| 副作用 | 可修改资源字段,可触发 sidecar 注入 | 只读检查,不修改资源 |
| 幂等性要求 | 必须幂等(同一请求多次调用结果一致) | 无强制幂等要求 |
| 典型失败模式 | Patch 冲突、字段覆盖、循环注入 | 校验规则过严导致合法请求被拒 |
关键原则:Mutating Webhook 永远先于 Validating Webhook 执行。这意味着 Validating Webhook 看到的是经过所有 Mutating Webhook 修改后的最终对象,而非用户原始提交的对象。
3.2 执行流程与顺序
下图展示了两类 Webhook 在 Kubernetes API 请求准入阶段中的完整执行顺序:
重要提示:如果多个 Mutating Webhook 注册在同一资源上,Kubernetes 会按
webhooks[].rules.operations 匹配顺序依次调用,且每个 Webhook 的响应会作为下一个 Webhook 的输入。因此,Mutating Webhook 的调用顺序直接影响最终对象状态。
3.3 适用场景对比
根据两类 Webhook 的特性,以下列出典型适用场景:
MutatingAdmissionWebhook 适用场景
- Sidecar 自动注入:如 Istio/Linkerd 的 Envoy 代理注入,在 Pod 创建时自动添加 initContainer 和 sidecar 容器。
- 默认值填充:为未指定字段设置合理的默认值,例如资源限制(resources.limits)、调度策略(nodeSelector)。
- 标签/注解注入:自动添加审计标签、成本分摊标签、环境标识注解。
- 存储类默认设置:为未指定 storageClassName 的 PVC 注入默认存储类。
- 安全上下文加固:自动设置 runAsNonRoot、readOnlyRootFilesystem 等安全策略。
ValidatingAdmissionWebhook 适用场景
- 合规策略检查:禁止使用特权容器、禁止挂载宿主机敏感路径、禁止使用 latest 镜像标签。
- 资源配额校验:确保 Deployment 副本数不超过集群上限,确保容器请求/限制比例合理。
- 命名空间隔离规则:禁止跨命名空间引用 Secret/ConfigMap,禁止非授权命名空间创建特定资源。
- 自定义业务规则:如数据库实例名称必须符合命名规范、Ingress 域名必须属于已备案域名列表。
- 变更审计与告警:记录所有违反策略的请求,但不一定拒绝(可通过 allowed: true 配合审计日志实现)。
3.4 配置示例对比
以下展示两类 Webhook 在 YAML 配置中的关键差异:
# MutatingAdmissionWebhook 示例(sidecar 注入)
apiVersion: admissionregistration.k8s.io/v1
kind: MutatingWebhookConfiguration
metadata:
name: sidecar-injector.example.com
webhooks:
- name: sidecar-injector.example.com
clientConfig:
service:
name: sidecar-injector
namespace: istio-system
path: /inject
caBundle: <base64-ca-cert>
rules:
- operations: ["CREATE"]
apiGroups: [""]
apiVersions: ["v1"]
resources: ["pods"]
admissionReviewVersions: ["v1"]
sideEffects: None
timeoutSeconds: 10
reinvocationPolicy: IfNeeded # 支持重新调用
---
# ValidatingAdmissionWebhook 示例(策略检查)
apiVersion: admissionregistration.k8s.io/v1
kind: ValidatingWebhookConfiguration
metadata:
name: policy-checker.example.com
webhooks:
- name: policy-checker.example.com
clientConfig:
service:
name: policy-checker
namespace: policy-system
path: /validate
caBundle: <base64-ca-cert>
rules:
- operations: ["CREATE", "UPDATE"]
apiGroups: ["apps"]
apiVersions: ["v1"]
resources: ["deployments"]
admissionReviewVersions: ["v1"]
sideEffects: None
timeoutSeconds: 5
failurePolicy: Fail # 校验失败时拒绝请求
配置陷阱:Mutating Webhook 的
reinvocationPolicy 字段(v1.15+)控制是否允许在后续 Mutating Webhook 执行后再次调用当前 Webhook。如果设置为 IfNeeded,必须确保 Webhook 逻辑是幂等的,否则可能导致无限循环或对象状态不一致。
3.5 选择决策树
在实际开发中,可通过以下决策树快速判断应使用哪类 Webhook:
3.6 混合使用的最佳实践
在生产环境中,Mutating 和 Validating Webhook 经常配合使用,形成完整的准入控制链:
- 先注入默认值:使用 Mutating Webhook 为资源填充缺失字段(如资源限制、标签、sidecar)。
- 再校验最终状态:使用 Validating Webhook 检查经过注入后的完整对象是否符合策略。
- 避免重复校验:Validating Webhook 不应重复检查 Mutating Webhook 已经保证的字段(如默认值是否存在),而应关注业务语义层面的合规性。
- 日志与监控:两类 Webhook 都应输出结构化日志,记录 admissionReview 的 UID、操作类型、资源标识以及决策结果,便于调试和审计。
调试建议:在开发阶段,可以在 Validating Webhook 中临时添加
allowed: true 并记录拒绝原因到日志,避免因规则错误导致集群不可用。待规则验证通过后再改为 allowed: false 正式生效。