土法炼钢 · 系统与基础设施

【kube-apiserver】Mutating / Validating Webhook:timeout、failurePolicy 与可用性门

文章导航

分类入口
kubernetesdistributed
标签入口
#kubernetes#apiserver#webhook#admission#mutating#validating#cel#v1.30.3

目录

第 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

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 必须声明。NoneNoneOnDryRun 才能在 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.goDispatch 方法中,超时由 timeoutSeconds 控制。

延迟叠加机制

failurePolicy 决定超时后的行为:

failurePolicy webhook 超时或 5xx 网络不可达
Fail(默认) 拒绝请求,返回 500/503 拒绝
Ignore 放行 放行

生产中 Fail + 慢 webhook = 创建 P99 延迟由 webhook SLA 决定,而非 etcd。排障口令:


三、生产可用性门

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-manager

3. 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)

站内对照

实验台账


上一篇Admission 链概览

下一篇Authentication:SA、Bearer、OIDC 边界

读完这篇,下一步读什么

优先读同系列或同问题的下一篇,把单篇消费变成主题集群。

2026-08-28 · kubernetes / distributed

【kube-apiserver】CRD / aggregation / 扩展边界:API 扩展停损线

厘清 CRD v1 与 Aggregated API 两条扩展路径在 kube-apiserver 中的存储与请求分界:CRD 对象存 etcd、conversion webhook 失败如何体现在 Storage 轴,APIService 则把请求转发到外部 Extension Server 可引发 503。明确 scheduler/controller/kubelet 为扩展停损线之外的数据面与控制循环。

2026-08-28 · kubernetes / distributed

【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 轴。


By .