admission webhook 必须使用 https 且证书 subjectaltname 至少包含 service dns、集群域名及 clusterip,私钥权限需为 0600,监听必须用 listenandservetls,证书通过 secret 挂载,处理函数须正确解析 admissionreview 并设置 response.uid 和 patchtype。

必须用 HTTPS 且证书包含 Service DNS 和 ClusterIP 的 subjectAltName,否则 kube-apiserver 根本不会发请求过去——连日志都不会有,不是 500,是“完全静默失败”。
证书和 TLS 监听不能凑合
本地测试时用 HTTP 或只监听 :8080 再套反向代理,kube-apiserver 会直接跳过你的 webhook。它只走 TLS,并严格校验证书的 subjectAltName。
-
subjectAltName至少得包含:DNS:my-webhook.my-namespace.svc、DNS:my-webhook.my-namespace.svc.cluster.local、IP:<service-cluster-ip></service-cluster-ip> - 私钥文件权限必须是
0600,否则 Go 的tls.LoadX509KeyPair会静默失败(Linux 下尤其敏感) - 启动监听必须用
http.ListenAndServeTLS(":"+port, certPath, keyPath, nil),不能先http.ListenAndServe再加 TLS 层 - 证书和密钥要通过
Secret挂载进 Pod,路径固定为/certs/tls.crt和/certs/tls.key(或你自定义但需同步改代码)
AdmissionReview 解析不能硬解结构体
直接 json.Unmarshal 到 Pod 或 Deployment 这类固定 struct,K8s 版本一升级就 panic。因为 request.object 的实际类型取决于被操作资源和 API 版本(比如 apps/v1 vs batch/v1),字段名也可能漂移(如 status.phase 在 v1.22+ 才稳定)。
- 先用
runtime.DefaultUnstructuredConverter.FromUnstructured转成unstructured.Unstructured - 再根据
review.Request.Kind.Group和.Version分支处理逻辑 -
review.Request.Operation是"CREATE"、"UPDATE"、"DELETE"或"CONNECT";DELETE时request.Object为空,别假设它一定有内容 - 别漏掉
review.Request.UID—— 它是响应里Response.UID的唯一合法来源,不设会导致500 Internal Error
MutatingWebhook 必须返回 Patch 和 PatchType
只改了对象内容但没生成 JSON Patch,kube-apiserver 会认为你什么都没做,继续往下走。它不关心你内部怎么改的,只认标准 patch 格式。
- 用
json.Marshal把修改后的unstructured.Unstructured和原始对象 diff 出 RFC 6902 格式的 patch(推荐用k8s.io/apimachinery/pkg/util/jsonmergepatch) -
PatchType必须设为"JSONPatch"(字符串字面量,不是常量),且Patch字段是[]byte -
Response.Allowed是*bool类型,不能直接赋true,得写allowed := true; Response.Allowed = &allowed - 如果想跳过某些 namespace(比如
kube-system),在 handler 开头检查review.Request.Namespace,匹配就直接返回允许 + 空 patch
rules 配置错一个字母就收不到请求
ValidatingWebhookConfiguration 或 MutatingWebhookConfiguration 的 rules 字段不是“写了就行”,而是决定流量是否抵达你的服务。配错最典型的现象是:日志空空如也,kubectl get events 也没相关记录。
-
apiGroups填[""]表示 core group(Pods,Services),填["apps"]表示Deployments,不能写["apps/v1"](那是版本路径,不是 group 名) -
resources必须是小写复数:["pods"]、["deployments"],不是Pod或deployment -
scope设为"*"表示集群级生效;若只作用于特定 ns,得用namespaceSelector.matchLabels,不是靠不存在的namespaces字段 - 改完配置后,
kube-apiserver不会自动重载——必须手动触发一次资源变更(比如kubectl apply -f pod.yaml),它才会重建 TLS 连接并校验证书
最容易被忽略的是:caBundle 必须是 base64 编码的 PEM 格式 CA 证书(不是服务端证书本身),且和你 Webhook 服务实际使用的证书链完全一致;差一个字节,连接就在 TLS 握手阶段断开,HTTP 层都进不去。
golang免费学习笔记(深入):立即使用
在学习笔记中,你将探索golang的核心概念和高级技巧!











