准入控制器必须使用HTTPS且证书被API Server信任,caBundle需填Base64编码的CA根证书(不含换行),subjectAltName须含Service DNS名,端口必须为443,failurePolicy默认Fail但开发建议Ignore。

准入控制器必须用 HTTPS 且带合法证书
所有 Kubernetes 准入 Webhook(包括 ValidatingWebhookConfiguration 和 MutatingWebhookConfiguration)都强制要求后端服务暴露 HTTPS 端点,且证书必须被 API Server 信任。自签名证书不行,除非你手动把 CA 证书 Base64 编入 Webhook 配置的 caBundle 字段——但这个字段不是填证书文件路径,而是填 PEM 编码后的 CA 根证书内容(不含换行、无空格,纯一行 Base64)。
常见错误现象:admission webhook "xxx.example.com" does not support dry run 或 failed calling webhook "xxx.example.com": x509: certificate signed by unknown authority,基本都是证书没对上或没填 caBundle。
- 生成证书时,
subjectAltName必须包含 Service DNS 名(如my-admission.default.svc),不能只写 IP 或 localhost - Go 服务启动时需加载
tls.Certificate,且监听地址必须是0.0.0.0:443(K8s 默认只连 443) - 不要在本地用
localhost:8443测试;Service + TLS + caBundle 三者必须闭环才可能通过 API Server 调用
controller-runtime 的 Builder.Complete() 不适用于准入控制器
标准的 ctrl.NewControllerManagedBy(mgr) 是为资源控制器(Reconciler)设计的,它注册的是 Informer 监听和 Workqueue 调谐逻辑,跟准入 Webhook 完全无关。准入控制器本质是一个 HTTP 服务,响应 /validate 或 /mutate 路径的 POST 请求,不走 controller-runtime 的 Manager 生命周期管理。
正确做法是:用 sigs.k8s.io/controller-runtime/pkg/webhook/admission 包构建 Handler,并注册到独立的 HTTP Server 中(通常复用 mgr.GetWebhookServer())。
- 必须调用
mgr.GetWebhookServer().Register("/mutate-pods", &webhook.Admission{Handler: &PodMutator{}})才真正挂载路径 -
PodMutator需实现admission.DecoderInjector接口,否则req.Object解码失败,报no kind "Pod" is registered for version "v1" - 不要试图在
Reconcile方法里处理准入逻辑——那是两个完全不同的控制平面机制
mutate 和 validate 的 handler 必须显式设置 FailurePolicy 和 Rules
Webhook 配置对象(MutatingWebhookConfiguration / ValidatingWebhookConfiguration)里的 failurePolicy 和 rules 决定 API Server 在什么条件下跳过或阻断请求。默认值是 Fail,意味着一旦 Webhook 不可用(超时、5xx、连接拒绝),整个 API 请求就失败——这在生产环境极危险。
开发阶段建议设为 Ignore,上线前再切回 Fail 并确保高可用(比如至少 2 副本 + PodDisruptionBudget + 就绪探针检查证书有效期)。
-
rules中的apiGroups、apiVersions、resources必须与实际处理的请求严格匹配,大小写敏感,resources: ["pods"]≠resources: ["Pod"] - 若要拦截所有命名空间的 Pod 创建,
scope应为Cluster;若只处理某命名空间,得配Namespaced+ 对应namespaceSelector - mutating webhook 若修改了对象,必须返回 patched JSON(用
json.Marshal生成PatchTypeJSONPatch),不能只改req.Object后返回空 patch
本地调试时,caBundle 最容易漏掉或填错
很多人用 kubectl apply -f webhook.yaml 后发现日志里根本没进 handler,API Server 也无调用记录——八成是 caBundle 没生效。这个字段不是可选的,也不是填个占位符就行。
正确生成方式:cat ca.crt | base64 -w 0(Linux/macOS),Windows PowerShell 用 [Convert]::ToBase64String([IO.File]::ReadAllBytes("ca.crt")),结果必须是一整行、无换行符、无空格。
- 别用
openssl x509 -in ca.crt -text输出去 Base64——那是证书详情,不是 PEM 格式根证书 - 别把整个
tls.crt当作 caBundle——那是服务端证书,不是 CA 根证书 - 修改
caBundle后必须kubectl apply重新部署配置,旧对象不会自动更新
golang免费学习笔记(深入):立即使用
在学习笔记中,你将探索golang的核心概念和高级技巧!











