admissionreview解析失败导致webhook 500,因go结构体字段标签缺失、类型不匹配或未大写,致json.unmarshal panic;须用json:"xxx,omitempty"、首字母大写、正确嵌套metav1.objectmeta。

为什么 AdmissionReview 解析失败会导致 webhook 500?
Go 服务收到 K8s 请求后,如果没正确反序列化 AdmissionReview,就会 panic 或返回空响应,K8s 控制平面直接记为失败,日志里常见 invalid character '}' looking for beginning of value 或 json: cannot unmarshal string into Go struct field AdmissionRequest.uid。根本原因是 K8s 发来的 JSON 结构严格,而 Go struct 字段没对齐标签或类型不匹配。
- 必须用
json:"xxx,omitempty"标签,且字段名首字母大写(否则json.Unmarshal忽略) -
uid、operation、object这些字段不能设为指针或错误类型(比如把Operation string写成Operation *string) - 别自己定义
ObjectMeta,直接嵌套metav1.ObjectMeta(来自k8s.io/apimachinery/pkg/apis/meta/v1) - 示例关键结构:
type AdmissionReview struct { Request *AdmissionRequest `json:"request,omitempty"` Response *AdmissionResponse `json:"response,omitempty"` } type AdmissionRequest struct { UID types.UID `json:"uid"` Operation string `json:"operation"` Namespace string `json:"namespace"` Name string `json:"name"` Object runtime.RawExtension `json:"object"` }
如何安全地修改 Pod 的 spec.containers[*].image?
修改资源前必须确认 operation == "CREATE",且只处理目标资源类型(如 kind == "Pod"),否则可能误改 Deployment、DaemonSet 等控制器生成的资源,导致雪崩。修改不是“覆盖整个 object”,而是解包 Object.Raw 后局部 patch。
- 用
json.Unmarshal把req.Object.Raw解到v1.Pod类型,别用map[string]interface{}—— 类型安全能早暴露字段错误 - 遍历
pod.Spec.Containers,对每个container.Image做替换(比如加 registry 前缀),注意保留原始 tag 和 digest - 修改完再用
json.Marshal写回response.Patch,格式必须是 JSON Patch(RFC 6902),不是完整对象 - 示例 patch:
[{"op":"replace","path":"/spec/containers/0/image","value":"my-registry.example.com/nginx:1.24"}] - 务必设置
response.PatchType = &patchType,其中patchType = "JSONPatch"
证书和 TLS 配置为什么总被 K8s 拒绝?
K8s apiserver 要求 webhook server 必须提供合法 TLS 证书,且证书 Subject Alternative Name(SAN)必须包含 service DNS 名(如 my-webhook.my-ns.svc)或 cluster IP,自签名证书必须提前注入到 admissionConfiguration 的 caBundle 字段中,否则报错 x509: certificate signed by unknown authority。
- 生成证书时,
openssl req的-subj不够,必须用-addext subjectAltName=DNS:my-webhook.my-ns.svc(OpenSSL 1.1.1+)或配置文件方式指定 SAN -
caBundle是 base64 编码的 PEM 格式 CA 证书内容(不含注释行,只留-----BEGIN CERTIFICATE-----...-----END CERTIFICATE-----),不是私钥,也不是证书链 - Webhook server 的
ListenAndServeTLS第二个参数必须是证书文件路径,第一个是私钥;别把两者顺序搞反 - 检查证书是否生效:
openssl s_client -connect my-webhook.my-ns.svc:443 -showcerts
为什么 mutatingWebhookConfiguration 更新后不生效?
配置更新后,K8s 不会立即 reload,而是按缓存周期(默认 1 分钟)轮询;更常见的是规则匹配失败:比如 rules[].resources 写成 ["pods"] 却忘了加 ["pods/status"](status 子资源单独匹配),或 namespaceSelector 表达式语法错误导致全跳过。
立即学习“go语言免费学习笔记(深入)”;
- 检查
kubectl get mutatingwebhookconfigurations my-webhook -o yaml中的webhooks[0].clientConfig.service.namespace是否和实际 service 所在 namespace 一致 -
rules[].operations必须包含当前操作(如"CREATE"),大小写敏感,不能写成"create" - 用
kubectl describe mutatingwebhookconfiguration my-webhook查看 Events,有无Failed calling webhook或Timeout - 临时关闭
failurePolicy: Fail改为Ignore,先确认逻辑通路,再调策略










