一条规则为何覆盖七种控制器,以及策略会删除什么
一句话总结
针对 Pod 编写的规则,Kyverno 会为 Deployment、StatefulSet、CronJob 等 Pod 控制器自动生成(autogen)规则,并附加到策略的 status.autogen 中。而删除资源这件事,则由与 validate、mutate 分开的另一种策略类型 CleanupPolicy 和 TTL 标签负责。这两项功能都发生在规则正文之外,所以需要知道它们在什么条件下开启、什么条件下关闭。
为什么需要它
“镜像只能来自公司内部注册表”这类验证,归根结底是对 Pod 的验证。但几乎没有人直接创建 Pod,创建 Pod 的是 Deployment、DaemonSet、StatefulSet、Job、CronJob。每种控制器的 Pod 模板位置不同——Deployment 是 spec.template.spec,CronJob 是 spec.jobTemplate.spec.template.spec。如果把同一条规则按控制器的数量复制一份,修改其中一个时就会漏掉其他的。所以 autogen 文档说明:“从只针对 Pod 编写的规则自动生成面向上层控制器的规则”。
清理则是另一个问题。实验用命名空间里残留的 Deployment、几天前的 Job 的 Pod 这类“创建时需要,但没有人决定何时删除”的资源会不断堆积。准入控制器只看进来的请求,所以无法删除已有的东西。因此需要 cleanup 文档中介绍的独立控制器和调度。
工作原理
autogen 生成的内容
如果创建了 match.any[].resources.kinds 只有 Pod 的 validate 规则,Kyverno 会在策略的 status.autogen.rules 下再加入两条规则。一条是 autogen-<규칙이름>(占位符为规则名称),面向 DaemonSet、Deployment、Job、StatefulSet、ReplicaSet、ReplicationController,并把模式移到 spec.template.spec 下;另一条是 autogen-cronjob-<규칙이름>(占位符为规则名称),面向 CronJob,并把模式移到 spec.jobTemplate.spec.template.spec 下。其中也包含 ReplicaSet 和 ReplicationController,但默认的资源过滤器把这两者排除在外,所以文档特别提醒:要真正应用,就得调整 Kyverno ConfigMap 中的 resourceFilters。
移动的不只是模式。preconditions 中 request.object.metadata.* 这样的变量,也会按控制器被转换为 request.object.spec.template.metadata.*。如果这不是想要的行为——比如想查看 Deployment 自身的注解——就像 request."object".metadata... 那样,用双引号把 object 括起来,以阻止转换。
开启与关闭的条件
行为通过策略注解 pod-policies.kyverno.io/autogen-controllers 来调节。值中像 Deployment,Job 这样列出控制器,就只生成这些控制器的规则,值为 none 则完全不生成。像 OpenKruise 的 CloneSet 这样内含 Pod 模板的自定义资源,只要把名称写进这个注解,也会成为对象。
也有自动关闭的情况。如果 match 或 exclude 中有 names、selector、annotations,就会跳过(因为控制器未必适用这些过滤条件)。种类里在 Pod 之外还同时写了其他 kind 时同样不生成,使用 JSON patch 的 mutate 规则也被排除。这里要注意的是,即使 autogen 被关闭,控制器创建的 Pod 仍然会命中 Pod 规则。文档举例说,想排除 Job 创建的 Pod,就在 preconditions 中用 AnyNotIn 来比较 request.object.metadata.ownerReferences[].kind。
CleanupPolicy 与 ClusterCleanupPolicy
清理策略有两种:命名空间范围的 CleanupPolicy 和集群范围的 ClusterCleanupPolicy,API 版本是 kyverno.io/v2。结构并不陌生——用 match/exclude 选择,用可选的 conditions 缩小范围(此时目标资源的值通过 target.* 引用),用 context 获取外部数据,并在 schedule 中以 cron 格式写下执行时间。
apiVersion: kyverno.io/v2
kind: ClusterCleanupPolicy
metadata:
name: cleandeploy
spec:
match:
any:
- resources:
kinds: [Deployment]
selector:
matchLabels:
canremove: "true"
conditions:
any:
- key: "{{ target.spec.replicas }}"
operator: LessThan
value: 2
schedule: "*/5 * * * *"
deletionPropagationPolicy: Foreground
清理策略的对象始终是已经存在的资源,所以只有在准入时才能知道的 subjects、Roles、ClusterRoles 不能写在 match/exclude 中,operations[] 虽然可以写,但会被忽略。执行删除的是 cleanup 控制器,按照最小权限原则,可能需要为每一种要删除的资源另外授予 ClusterRole。文档给出了带有 delete 动词的 ClusterRole 示例,并写明权限不足时,Kyverno 会在安装策略时验证并告知。
deletionPropagationPolicy 决定如何处理从属资源。Foreground 先删除从属资源再删除主体,Background 先删除主体,从属资源异步删除,Orphan 则保留从属资源。不指定时,遵循 API 服务器的默认行为。
TTL 标签
即使不写策略,只要给单个资源加上 cleanup.kyverno.io/ttl 标签,它就会被删除。值有两种格式:ISO 8601 绝对时间(2023-10-04 或 2023-10-04T003000Z),或从观察到标签的时刻起计算的剩余时间(5m、4h、1d)。无法识别的格式会给出警告。Kyverno 会监视带标签的资源,但实际的删除精度由 cleanup 控制器的 ttlReconciliationInterval 标志(默认 1m)决定。用 TTL 删除时的传播策略通过注解 cleanup.kyverno.io/propagation-policy 指定。
因为它是标签,所以能与其他功能衔接。可以用 mutate 规则给特定资源自动加上 TTL 标签,也可以用 validate 规则阻止特定的组在特定命名空间中加这个标签。
文档标注的弃用预告
与考试范围无关,还有一点需要了解。截至 2026-09,kyverno.io 文档把 CleanupPolicy、ClusterCleanupPolicy 从 v1.19 起标记为 deprecated,并在 v1.20 中移除,同时写明基于 CEL 的 DeletingPolicy 提供相同功能。升级文档指出 ClusterPolicy、Policy(kyverno.io/v1)本身也在同一时间点被弃用。概念不变,所以本文内容依然有效,但如果是新写的策略,就需要确认该用哪种类型。
在现场相遇的样子
某个平台团队加入了“Pod 必须设置 requests/limits”的策略之后,想用 exclude 把带有特定注解的 Pod 排除掉。就在那一刻 autogen 悄悄关闭了,出现了不一致:由 Deployment 创建的 Pod 会被拦住,而创建 Deployment 本身的请求却能通过。按文档给出的做法,不用 exclude,改为在 preconditions 中检查 request."object".metadata.annotations,autogen 又恢复了。
在清理方面,创建了 ClusterCleanupPolicy 却什么都没被删除的情况很常见。通常是 cleanup 控制器没有该资源的 delete 权限,或者把 conditions 中的 target.* 误写成了 request.object.*。
下一项测验要确认什么
测验会考查 autogen 生成的规则名称和目标种类、注解值 none 的含义、存在 names、selector、annotations 时的行为,以及 CleanupPolicy 的 schedule、target.*、TTL 标签格式和 ttlReconciliationInterval 的默认值。