webhook必须用https且证书san需包含service dns,否则kube-apiserver拒绝调用;须正确配置mutating/validatingwebhookconfiguration的rules、使用unstructured.unstructured解析admissionreview,并通过+kubebuilder:webhook标记生成配置。

Webhook 必须用 HTTPS,证书 SAN 要包含 Service DNS
不配对的证书是本地调试时 90% 的失败原因。kube-apiserver 拒绝任何 TLS 握手失败的调用,错误日志里常见 x509: certificate is valid for ... not my-webhook.my-ns.svc。
生成证书时,subjectAltName 至少得覆盖:
- DNS:
my-webhook.my-ns.svc - DNS:
my-webhook.my-ns.svc.cluster.local - IP:
<service-cluster-ip></service-cluster-ip>(从kubectl get svc my-webhook -o jsonpath='{.spec.clusterIP}'获取)
私钥必须挂进 Pod 作为 Secret,路径别硬写死;服务启动时监听必须是 tls.Listen("tcp", ":443", tlsConfig),不能监听 :8080 再套 nginx —— apiserver 不走代理。
AdmissionReview 解析不能直接反序列化到固定 struct
你无法提前知道 request.object 是 Pod 还是 Deployment,更别说不同 K8s 版本字段名可能漂移(比如 v1.22+ 的 status.phase 在旧版叫 phase)。直接定义 type Pod struct { ... } 然后 json.Unmarshal 会 panic 或漏字段。
正确做法是用 unstructured.Unstructured 中转:
var obj unstructured.Unstructured
if err := json.Unmarshal(req.Object.Raw, &obj); err != nil {
return admission.Errored(http.StatusBadRequest, err)
}
// 再按需取值:obj.GetKind(), obj.GetAPIVersion(), obj.Object["spec"]
同时注意:req.Operation 可能是 CREATE、UPDATE、DELETE 或 CONNECT;DELETE 时 req.Object.Raw 为空,别假设它一定有内容。
Rules 配置错一个字母,Webhook 就收不到请求
MutatingWebhookConfiguration 和 ValidatingWebhookConfiguration 的 rules 字段不是“写了就生效”,而是严格匹配逻辑。最常踩的坑:
-
apiGroups填[""]表示 core group(如Pods),填["apps"]表示Deployments;不能写成["apiextensions.k8s.io/v1"]—— 这是 API path,不是 group 名 -
resources必须是小写复数:["pods"]、["deployments"],不是Pod或deployment -
scope设为"*"才匹配所有命名空间;想限制在特定 ns,得用namespaceSelector.matchLabels,没有namespaces字段
验证是否生效:改完配置后,手动 kubectl patch pod xxx -p '{"metadata":{"annotations":{"x":"y"}}}' 触发一次变更 —— Kubernetes 不主动重载 webhook 配置,必须靠资源事件触发 TLS 重连。
Kubebuilder 的 +kubebuilder:webhook 标记不是可选,是强制约定
不用标记,controller-gen 就不会生成 MutatingWebhookConfiguration 或 ValidatingWebhookConfiguration 清单。标记必须写在 Go 文件顶部注释里,例如:
// +kubebuilder:webhook:path=/mutate-meta-github-com-v1-metawebhook,mutating=true,failurePolicy=fail,groups=meta.github.com,resources=metawebhooks,versions=v1,name=mmetawebhook.kb.io,sideEffects=None
关键点:
-
path必须和你 HTTP handler 注册的路径完全一致(比如"/mutate") -
groups和resources必须和 CRD 的spec.group/spec.names.plural对齐 -
name是全局唯一标识,不能重复,否则多个 webhook 会互相覆盖
生成后记得跑 make manifests,再 kubectl apply -f config/webhook/ —— 这一步漏掉,Webhook 就只是个没注册的 HTTP 服务。
golang免费学习笔记(深入):立即使用
在学习笔记中,你将探索golang的核心概念和高级技巧!











