服务端dry-run的准入链预检价值
我一直觉得,改生产环境里的安全字段,最吓人的不是改错,而是你以为自己改对了。
比如把某个工作负载的 securityContext 补齐,顺手摘掉多出来的 hostPath 卷,YAML 看着干干净净,一 apply,没报错,事就过了。可它究竟有没有真的按你想的那样落地,其实没人知道。
这中间隔着一整条准入链。API 校验、RBAC、还有各种 mutating webhook,都可能在你没察觉时改动对象。客户端 dry-run 只在本地把对象拼一遍,压根不进这条链,所以它只能告诉你“YAML 语法没问题”,别的什么都保证不了。
服务端 dry-run 就不一样了。请求会被完整送进准入链,该走的校验走完、该拦的 webhook 拦掉、该注入的默认值注入,唯一区别是最后不写进 etcd。这一步很便宜,信息量却不小:字段校验过不过、权限够不够、会不会被 webhook 拒绝,当场就能看清楚。
我习惯把它和 kubectl diff 搭配用。diff 给我一份人能读懂的差异,服务端 dry-run 的输出则用来确认准入链没把修复后的对象又改回原样。两个一起看,心里才踏实。
审批环节我主要盯三件事
- diff 是不是只碰了目标字段,有没有顺手带上别的改动
- 有没有 mutating webhook 往对象里塞了意料之外的字段
- 修复后的对象,是否仍然满足命名空间上 Pod Security 标签的要求
这三条不过,我基本不会放行。毕竟审批记录和 diff 一起归档,以后复盘还能还原“当时批的到底是什么”。
不过话说回来,dry-run 通过也不等于万事大吉。它证明的是“这次提交能被集群接受”,不是“运行时一定没问题”。涉及 hostPath 和 hostNetwork 的修复,对象重建之后,卷挂载和网络命名空间还得实际看一眼,有些字段在准入阶段过得去,运行时表现却受节点配置影响。
所以我的习惯是:先拿服务端 dry-run 把明显的坑挡在前面,再小范围灰度,把当前 YAML 存一份带时间戳的快照当回滚兜底。真出事,重新 apply 那份快照就好,比事后翻记录找“原来长什么样”靠谱多了。
服务端 dry-run 不是万能的,但它几乎是零成本的一次预检。改安全配置之前多跑这一下,很多时候能省掉后面一长串解释。

参与讨论
本地 dry-run 只能防语法坑