admission webhook 必须使用 http.listenandservetls 启动 https 服务,证书需含指定 san、cabundle 为 base64 编码 ca,且须用 admissionv1 解析 admissionreview;mutationrequired 应避免硬编码 annotation key,rules 需严格匹配 apigroups/apiversions/resources。

Webhook 服务必须用 http.ListenAndServeTLS,不能只 listen :8080
Admission Webhook 是 Kubernetes API Server 主动发起的 HTTPS 请求,kube-apiserver 强制要求通信走 TLS,且证书需被集群 CA 信任。哪怕本地调试,用 http.ListenAndServe(":8080", mux) 启动 HTTP 服务,API Server 根本不会发请求——你连日志都看不到。
正确做法是:用 http.ListenAndServeTLS,并确保传入的证书和私钥路径与挂载进 Pod 的 Secret 路径一致(如 /etc/webhook/certs/tls.crt 和 /etc/webhook/certs/tls.key)。
- 证书 subjectAltName 必须包含至少三项:
DNS:my-webhook.my-namespace.svc、DNS:my-webhook.my-namespace.svc.cluster.local、IP:<service-cluster-ip></service-cluster-ip> -
clientConfig.caBundle字段填的是 Base64 编码后的 CA 证书内容(不是文件路径,也不是 PEM 原文) - 不要在 handler 里做
http.Redirect或忽略 TLS —— 这会导致准入链路静默失败,现象是“配置写了但没生效”
serveMutate 函数要校验 Content-Type 并一次性读取 r.Body
serveMutate 是 MutatingWebhook 的入口函数,它收到的是 admissionv1.AdmissionReview JSON payload。Kubernetes API Server 发送时固定用 Content-Type: application/json,大小写敏感,且 body 不可重复读取。
常见错误是直接 json.NewDecoder(r.Body).Decode(),结果后续再想读原始字节(比如验签或打日志)就失败了——r.Body 已 EOF。
使用 uber-go/dig 在 Golang 中实现依赖注入——基于反射容器,提供 Provide/Invoke、dig.In/dig.Out 参数与结果对象,支持命名依赖等
- 必须先用
io.ReadAll(r.Body)一次性读出全部字节,再用bytes.NewReader(body)构造新 reader 供多次解码 - 显式校验
r.Header.Get("Content-Type") == "application/json",不接受application/JSON或带 charset 的变体 - 建议加
io.LimitReader(r.Body, 1024*1024)防止恶意大包耗尽内存
解析 AdmissionReview 必须用 v1 版本,别碰 v1beta1
从 Kubernetes 1.26 起,admissionregistration.k8s.io/v1beta1 已彻底移除。如果你还 import admissionv1beta1 "k8s.io/api/admission/v1beta1",服务启动可能不报错,但收到请求后会 panic:json: cannot unmarshal object into Go struct field AdmissionReview.request of type admissionv1beta1.AdmissionRequest,或者 response body 为空。
正确导入和使用方式:
- 导入
admissionv1 "k8s.io/api/admission/v1" - 定义结构体字段为
*admissionv1.AdmissionReview,不是v1beta1版本 - 解析前先检查
review.Request.Kind.Group和.Version,避免对未知资源类型 panic - 响应必须返回
admissionv1.AdmissionResponse,且Allowed和Result字段不可同时为空
mutationRequired 判断逻辑容易漏掉 annotation key 变更
MutatingWebhook 是否触发注入,往往依赖 Pod metadata 中的 annotations 或 labels。典型实现是写一个 mutationRequired 函数,用 switch 或 if 判断特定 key 是否存在且值为 true。
最隐蔽的坑是:这个判断逻辑写死在代码里,而业务方改了 chart 模板里的 annotation key 名(比如从 sidecar.istio.io/inject 改成 inject.sidecar),webhook 日志完全安静,Pod 看似正常创建,但 sidecar 就是不出现。
- 别把 annotation key 写死在
if pod.Annotations["xxx"] == "true"里,应抽成配置项(如 ConfigMap 挂载 + fsnotify 热重载) - default 分支不要直接
return false,至少打一条 warn 日志说明 “no matching inject annotation found” - 测试时用
curl -k -X POST https://<svc>/mutate --data-binary @test-pod.json -H "Content-Type: application/json"</svc>手动触发,比等 kubectl apply 更快定位是否进到 handler
ValidatingWebhookConfiguration 和 MutatingWebhookConfiguration 的 rules 字段匹配逻辑——它不是“写了就生效”,而是按 apiGroups、apiVersions、resources 三者 AND 匹配。少写一个 apps/v1,Deployment 就永远不会打进来。golang免费学习笔记(深入):立即使用
在学习笔记中,你将探索golang的核心概念和高级技巧!










