LabHub
学习 学习路径 课程

KCA — Kyverno 认证助理

generate 为什么会静默失败

在 LabHub 中继续学习

一句话总结

mutate 会在 admission 阶段修改对象并将其返回。generate 不会在 admission 阶段创建任何内容,而是留下 UpdateRequest,再由 background 控制器实际创建资源。正因如此,generate 的失败最难察觉:admission 成功了,只有资源没有生成。

概念图: 一句话总结 · 为什么需要它 · 它如何工作 · 实际现场中的表现

为什么需要它

mutate 存在的原因,是只做检查会让人疲惫。如果只用 validate 强制“为每个 Pod 添加团队标签”,就必须在数百份清单里重复加入同一行,遗漏的团队还会被阻止部署。如果某个值要无例外地应用于整个组织,与其让人手工填写,不如由系统自动添加。

generate 解决的是另一个问题。有些事实只有在命名空间创建时才能得知。若要为新命名空间添加 default-deny NetworkPolicy,就必须响应命名空间创建事件。GitOps 很难表达“命名空间创建之后”这一时点,交给人处理则很容易遗忘。

它如何工作

mutate 有两种语法。patchStrategicMerge 是 Kubernetes 的战略合并补丁,会按名称键合并数组,适合在保留现有内容的基础上追加内容,例如向容器列表增加一个 sidecar。patchesJson6902 是 RFC 6902 JSON Patch,通过 op/path/value 精确指定位置。路径采用斜杠表示法;如果键本身含有斜杠,就必须用 ~1 转义,这是实践中常见的陷阱。要添加 kca.io/owner 注解,路径应写为 /metadata/annotations/kca.io~1owner。foreach mutate 会对集合中的每个元素应用补丁。

generate 的语法分为 data(直接在策略中写入值)和 clone(复制另一个命名空间中的资源),二者不能同时使用。此外还有 synchronize。设置为 true 时,源对象发生变更,生成物也会随之更新;如果手工修改生成物,它还会将修改恢复。

但这种便利并非没有代价。synchronize 会按照目标命名空间的数量增加监视与写入。在只有五个命名空间的集群中几乎感觉不到,但在拥有数百个命名空间的集群中,它会成为 background 控制器的持续负载。而且该控制器安装时只拥有最小权限。一旦开始 generate 非标准资源,就必须由使用方添加对该资源的权限;如果没有权限,admission 仍会成功,只有资源悄无声息地无法生成。

因此,诊断顺序是明确的。看不到生成物时,不要先检查策略 YAML,而应先查看 UpdateRequest。若 kubectl -n kyverno get updaterequests 为空,说明没有匹配到对象;如果请求存在但资源不存在,则问题在 background 控制器的权限或运行状态。只靠这一次分流,就能把问题范围缩小一半。可以用 kubectl auth can-i <동사> <리소스> --as system:serviceaccount:kyverno:kyverno-background-controller 检查权限。还要记住,刚创建命名空间就立即检查生成物时,它可能尚未出现;这不是缺陷,而是设计使然。

最后,需要说明 mutate 在运维方面的代价。mutate 加入的值在 Git 中不可见。放在 Helm values 中的值可以接受评审,也可以按标签回滚;通过 mutate 注入的值则只存在于集群中。半年后可能没有人知道某个注解为何存在,而清单与实际对象不同的事实也会持续与 GitOps 工具的漂移检测发生冲突。原则是:只有必须在整个组织强制执行的值才放入 mutate;需要允许团队修改的值应保留在 chart 中。

实际现场中的表现

作者的家庭实验室使用 ArgoCD 运行 GitOps,地址为 10.0.0.201。在这里可以直接观察 mutate 与 GitOps 的冲突,因为协调循环会不断比较 Git 清单和集群实际状态。Kyverno 添加的标签或 sidecar 不存在于 Git 中,因此会出现在 diff 中;如果工具尝试删除它,Kyverno 又会重新添加。解决办法是从 diff 中排除该路径,或用 chart 默认值取代 mutate。如果迟迟不作决定,两个控制器就会长期互相撤销对方的变更。

该集群还反复验证了权限与观测之间的关系。无论 GPU Operator 事故还是 KubeVirt 事故,都表现为“状态显示正常,实际却无法工作”;generate 的静默失败也属于完全相同的类型。因此,部署使用 generate 的策略时,最好把检查 background 控制器权限的步骤放在检查策略本身之前。

下一项实验将做什么

我们会在 /root/kca-mutate/ 中编写用于注入标签和 sidecar 的 mutate 规则、JSON Patch 规则、创建 NetworkPolicy 的 generate 规则,以及复制 ConfigMap 的 clone 规则。随后实际创建 Role、RoleBinding 与服务账号,使 background 控制器能够读取复制源,并使用 auth can-i 进行验证。