第 8
篇 梳理了 Admission
链整体顺序与内置插件边界;本篇专写外部 Webhook
的生产配置与失败模式。最常见的误判是:创建 Pod 花了 12
秒,排查方向转向 etcd——但
etcd_request_duration_seconds
显示写入正常。慢 Webhook 加在 Admission 轴,不在
Storage 轴;两者证据包完全不同。
本篇在系列中的位置
篇目 核心内容 第 8 篇 · Admission 链概览 准入顺序、内置插件边界 第 9 篇 · Webhook timeout、failurePolicy、可用性门、CEL 替代路径 第 10 篇 · Authentication SA、Bearer、OIDC 边界 系列目录 五轴、阅读路径
版本锚定:Kubernetes v1.30.3(源码 tag
v1.30.3)。类型定义对齐staging/src/k8s.io/api/admissionregistration/v1/types.go;分发逻辑对齐staging/src/k8s.io/apiserver/pkg/admission/plugin/webhook/。无真实集群则不粘贴伪造kubectl输出或 webhook 调用日志。
一、MutatingWebhookConfiguration 与 ValidatingWebhookConfiguration v1
两种配置对象都属于
admissionregistration.k8s.io/v1 API
组,Cluster-scoped,写法对称。核心区别在调用阶段:
flowchart TD
req["Create / Update / Delete Request"] --> mutating["Mutating Webhooks(MUTATION 阶段)"]
mutating --> convert["schema 转换 + 内置校验"]
convert --> validating["Validating Webhooks(VALIDATION 阶段,并行)"]
validating --> persist["storage.Interface → etcd"]
mutating -- "timeout + failurePolicy=Fail" --> rej503["503 拒绝"]
validating -- "timeout + failurePolicy=Fail" --> rej503
- Mutating Webhooks 可修改对象,串行执行;每个 webhook 得到的是上一个 webhook 变更后的对象。
- Validating Webhooks 不能修改对象,并行调用;任一返回拒绝即拒绝整个请求。
reinvocationPolicy(Mutating 专属):若后续 webhook 再次修改对象,IfNeeded允许 apiserver 重新调用该 webhook;默认Never,不重调用。
staging/src/k8s.io/api/admissionregistration/v1/types.go
中对两种 configuration 的 Webhooks
数组成员定义了以下关键字段:
| 字段 | 类型 | 默认值 | 说明 |
|---|---|---|---|
timeoutSeconds |
*int32 |
10 | 最大 30;超时后按 failurePolicy 决定 |
failurePolicy |
FailurePolicyType |
Fail |
Fail:拒绝请求;Ignore:放行 |
sideEffects |
*SideEffectClass |
无默认(必填) | None / NoneOnDryRun /
Some / Unknown |
reinvocationPolicy |
*ReinvocationPolicyType |
Never |
Mutating 专属;IfNeeded 允许重调用 |
admissionReviewVersions |
[]string |
无默认(必填) | ["v1", "v1beta1"] 推荐 |
sideEffects 必须声明。None 或
NoneOnDryRun 才能在 dry-run 请求时跳过 webhook
调用(避免副作用);Some / Unknown
表示 webhook 有外部副作用,dry-run
时也会被调用。生产配置缺失 sideEffects: None
是常见问题。
二、timeout 与 failurePolicy:写路径延迟的根源
Webhook 调用是同步 HTTPS POST,从
apiserver 向 ClientConfig 指向的 Service 或 URL
发送 AdmissionReview 对象。调用发生在
staging/src/k8s.io/apiserver/pkg/admission/plugin/webhook/generic/webhook.go
的 Dispatch 方法中,超时由
timeoutSeconds 控制。
延迟叠加机制:
- Mutating 阶段的 webhook 是串行的:\(n\) 个 webhook 各自最多等 \(t\) 秒,最坏叠加为 \(n \times t\) 秒。
- Validating 阶段并行,但等最慢的那个。
- 每次 webhook 调用开销包含:DNS 解析(首次)、连接建立(若无长连接复用)、TLS 握手、handler 执行时间、网络 RTT。
failurePolicy 决定超时后的行为:
| failurePolicy | webhook 超时或 5xx | 网络不可达 |
|---|---|---|
Fail(默认) |
拒绝请求,返回 500/503 | 拒绝 |
Ignore |
放行 | 放行 |
生产中 Fail + 慢 webhook = 创建 P99
延迟由 webhook SLA 决定,而非 etcd。排障口令:
etcd_request_duration_seconds正常 → Storage 轴无问题。apiserver_request_duration_seconds{verb="CREATE"}高 → 需看 Admission 轴。apiserver_admission_webhook_latency_seconds{name=<webhook-name>}→ 定位具体 webhook。(metric 由staging/src/k8s.io/apiserver/pkg/admission/metrics/metrics.go注册,需从实际 Prometheus scrape 确认命名)
三、生产可用性门
failurePolicy: Fail 保证安全性,但 webhook
不可用时会阻塞所有命中的创建/更新请求,对生产准入有高可用要求。常见可用性门:
1. 副本与反亲和性
Webhook Service 至少 2 副本,配合
PodAntiAffinity 分散到不同节点。apiserver 与
webhook Pod
同属控制面节点时,节点故障会同时影响两者——webhook
不应绑死在控制面节点。
2. namespaceSelector 与 objectSelector
用 namespaceSelector 排除 webhook 自身所在
namespace(例如 kube-system)。若 webhook
发生故障且 failurePolicy: Fail,apiserver
无法在 kube-system 创建任何资源(包括 webhook
Pod 的重建),形成自锁。
namespaceSelector:
matchExpressions:
- key: kubernetes.io/metadata.name
operator: NotIn
values:
- kube-system
- cert-manager3. timeoutSeconds 调优
timeoutSeconds: 10(默认)已是最常见配置,但
webhook handler 有冷启动时会接近超时。建议监控
apiserver_admission_webhook_latency_seconds
P99,使其 < \(\frac{1}{2}\)
timeoutSeconds 留有余量。超时上限 30 秒;超过后
apiserver 不再等待,按 failurePolicy 处理。
4. reinvocationPolicy 幂等性
IfNeeded 使 webhook 可能被调用多次;webhook
handler 必须幂等:对同一对象多次 mutate
结果相同。注入 sidecar 的 webhook
尤需检查”已注入则跳过”逻辑,否则同一 Pod 可能被注入多个
sidecar container。
四、CEL ValidatingAdmissionPolicy:内置替代路径
K8s v1.30 将 ValidatingAdmissionPolicy
提升为 stable(v1)(类型定义见
staging/src/k8s.io/api/admissionregistration/v1/types.go,插件实现见
staging/src/k8s.io/apiserver/pkg/admission/plugin/policy/validating/)。
CEL VAP 的边界:
| 维度 | ValidatingAdmissionPolicy(CEL) | ValidatingWebhook |
|---|---|---|
| 调用路径 | apiserver 进程内,CEL 解释器 | 外部 HTTPS 调用 |
| 可用性依赖 | 无外部依赖 | webhook Service 可用 |
| 延迟 | 进程内执行,微秒级 | 依赖网络 RTT + handler |
| 可修改对象 | 否(纯校验) | 否(Validating 类) |
| 自定义逻辑 | 受 CEL 表达式限制 | 任意 Go/任意语言 |
| 外部状态访问 | 仅对象本身与 CRD params | 可访问外部 API/DB |
边界结论:CEL VAP
适合纯校验、无外部依赖的规则(例如标签约束、字段范围检查、owner
一致性)。需要访问外部数据源(OPA policy bundle、证书颁发
CA、数据库查询)或需要 mutate 的场景,仍需 Webhook。不写 CEL
引擎内核(go.cel.dev/cel
版本演进不在本篇范围)。
五、排障证据包
Webhook 相关故障快速落格:
| 症状 | 更可能落格 | 不像 |
|---|---|---|
| Create 返回 500 / 503,etcd metrics 正常 | failurePolicy=Fail + webhook 不可用 | etcd quota |
| Create P99 高,P50 正常 | webhook 冷启动或慢 handler | Raft apply lag |
| dry-run 操作调用了本不该有副作用的 webhook | sideEffects 配置为 Some/Unknown | CEL VAP bug |
| reinvocation 导致 sidecar 重复注入 | reinvocationPolicy=IfNeeded + handler 非幂等 | Admission 插件顺序 |
| 命名空间自锁(webhook 故障后无法重建其自身 Pod) | namespaceSelector 未排除 webhook 自身 ns | RBAC 权限 |
从 apiserver 日志(--v=4 以上)可看到
webhook 调用的 http 状态码与耗时;Prometheus 端的
apiserver_admission_webhook_latency_seconds
histogram 可按 webhook name 拆分 P50/P99。两者对不上时,注意
apiserver → webhook Service 之间的 kube-proxy 或 CNI
层延迟是独立变量,不在 webhook handler 耗时内。
六、谱系与开放问题
K8s v1.9:Webhook Admission 进入 stable
→ 可用性风险面扩大(Fail+慢 webhook = 全局阻塞)
→ v1.25:CEL ValidatingAdmissionPolicy alpha
→ v1.30:ValidatingAdmissionPolicy stable(进程内,无外部依赖)
→ 仍开放:Mutating CEL(无外部状态访问的突变)尚未 stable
开放问题(工程判断):reinvocationPolicy: IfNeeded
的调用上限未在 v1.30 API spec
中公开约定为固定值;幂等性验证依赖 webhook
自身逻辑,apiserver 无法代为检测。Mutating 阶段的
CEL(MutatingAdmissionPolicy)在 v1.30
尚处于早期讨论阶段,不写成 v1.30.3 已有事实。
本篇不写什么:未测 webhook
QPS/延迟数字;CEL 语法全书;OPA / Gatekeeper / Kyverno
实现细节;伪造 kubectl create 超时截图。
参考资料
规范 / 源码(A)
- Kubernetes v1.30.3(tag
v1.30.3):staging/src/k8s.io/api/admissionregistration/v1/types.go staging/src/k8s.io/apiserver/pkg/admission/plugin/webhook/(mutating/、validating/、generic/)staging/src/k8s.io/apiserver/pkg/admission/plugin/policy/validating/(CEL VAP)staging/src/k8s.io/apiserver/pkg/admission/metrics/metrics.go(webhook metrics 注册)- Kubernetes · Dynamic Admission Control(v1.30)
站内对照
实验台账
- 无集群实测;无伪造 webhook 调用日志或 metrics 截图。
上一篇:Admission 链概览
下一篇:Authentication:SA、Bearer、OIDC 边界
读完这篇,下一步读什么
优先读同系列或同问题的下一篇,把单篇消费变成主题集群。
【kube-apiserver】Admission 链概览:内置插件顺序与 webhook 边界
钉 Kubernetes v1.30.3 Admission 链的阶段位置、Mutating 与 Validating 两阶段顺序、内置插件注册路径与典型示例、webhook 边界与 timeout 语义,以及 fail-open vs fail-closed 的工程争议。
【kube-apiserver】控制面全景:缺口、五轴坐标系与 16 篇路线
相对 etcd/13、distributed/50、k8s-network 补齐 kube-apiserver 生产内核缺口;以 Storage/Watch/Admission/Auth/APF 五轴为坐标系定义 16 篇阅读路线;版本锚定 Kubernetes v1.30.3。
【kube-apiserver】CRD / aggregation / 扩展边界:API 扩展停损线
厘清 CRD v1 与 Aggregated API 两条扩展路径在 kube-apiserver 中的存储与请求分界:CRD 对象存 etcd、conversion webhook 失败如何体现在 Storage 轴,APIService 则把请求转发到外部 Extension Server 可引发 503。明确 scheduler/controller/kubelet 为扩展停损线之外的数据面与控制循环。
【kube-apiserver】排障五轴:Storage、Watch、Admission、Auth、APF
按 Storage/Watch/Admission/Auth/APF 五轴做症状否证;给出完整五轴命令表与症状→轴映射(504、410、401、403、webhook 超时、List 风暴、OOM);说明 apiserver_request_duration_seconds 等核心 metrics 语义;并提供决策树:何时穿透到 etcd/15,何时留在 apiserver 轴。