ルール一つが七つのコントローラを覆う理由、そしてポリシーが消すもの
一言でいうと
Podについて書いたルールは、KyvernoがDeployment・StatefulSet・CronJobなどのPodコントローラー用のルールとして自動生成(autogen)し、ポリシーのstatus.autogenに付けます。反対に、リソースを削除する仕事は、validate・mutateとは別のポリシーの種類であるCleanupPolicyと、TTLラベルが担当します。どちらの機能もルール本体の外で起きるので、どんな条件でオンになりオフになるのかを知っておく必要があります。
なぜ必要なのか
「イメージは社内レジストリからだけ」のような検証は、結局Podに対する検証です。ところが、Podを直接作ることはほとんどなく、Deployment・DaemonSet・StatefulSet・Job・CronJobがPodを作ります。コントローラーごとに、Podテンプレートの場所が違います。Deploymentはspec.template.spec、CronJobはspec.jobTemplate.spec.template.specです。同じルールをコントローラーの数だけコピーしておくと、1つを直すときに残りを直し忘れます。そのためautogenのドキュメントは、「Podに対してだけ書いたルールから、上位のコントローラー用のルールを自動生成する」と説明しています。
整理は、別の問題です。実験用のネームスペースに残ったDeployment、数日前のJobのPodのように、「作るときには必要だったが、いつ削除するのか誰も決めていない」リソースが溜まります。アドミッションコントローラーは、入ってくるリクエストしか見ないので、すでにあるものを削除できません。そのため、cleanupのドキュメントが説明する、別のコントローラーとスケジュールが必要です。
どう動くのか
autogenが作るもの
match.any[].resources.kindsがPodだけのvalidateルールを作ると、Kyvernoは、ポリシーのstatus.autogen.rulesの下に、ルールを2つ追加します。1つはautogen-<규칙이름>(プレースホルダーはルール名です)で、DaemonSet・Deployment・Job・StatefulSet・ReplicaSet・ReplicationControllerを対象とし、パターンをspec.template.specの下に移したもの、もう1つはautogen-cronjob-<규칙이름>(プレースホルダーはルール名です)で、CronJobを対象にspec.jobTemplate.spec.template.specの下に移したものです。ReplicaSetとReplicationControllerも含まれますが、デフォルトのリソースフィルターがこの2つを除外しているので、実際に適用するには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でrequest.object.metadata.ownerReferences[].kindをAnyNotInで比べるように、とドキュメントが例を挙げています。
CleanupPolicyとClusterCleanupPolicy
整理のポリシーは、ネームスペース範囲のCleanupPolicyと、クラスター範囲のClusterCleanupPolicyの2つで、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ラベル
ポリシーを書かなくても、リソース1つにcleanup.kyverno.io/ttlラベルを付ければ削除されます。値は2つの形式です。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年9月時点の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のデフォルト値を問います。