
こんにちは。SRE課のtaku_76です!
今回はKubernetesマニフェスト内の非推奨API / 削除済みAPIを継続的に検知する仕組みについて紹介します。
PlutoとGitHub Actionsを使い、定期実行から検出結果の更新まで自動で行うようにしました。
他チームにも使ってもらうことを想定していたため、Plutoを実行するだけでなく導入方法や検知結果の確認方法まで含めて運用に乗せる形にしています。
はじめに
仕組みを作成した目的
これまではKubernetesマニフェスト内の非推奨API / 削除済みAPIを定期的に確認する仕組みがありませんでした。
そのため、Kubernetesのバージョンアップ時に対象リポジトリを都度確認する必要があり、確認漏れがあるとアップデート後にリソースが適用できなくなる可能性があります。
このリスクを減らすために非推奨API / 削除済みAPIの利用状況を継続的に検知・追跡できる仕組みを作成しました。
また、対象リポジトリは複数ありそれぞれマニフェストの構成も少しずつ異なります。
そのため継続的に検知できるだけでなく利用者ができるだけ少ない手間で導入・確認できる形にすることも重視しました。
全体像
今回作成した仕組みでは、Kubernetesマニフェストを管理しているリポジトリを対象に非推奨API / 削除済みAPIが含まれていないかを定期的にチェックします。
検知にはPlutoを利用しました。PlutoはKubernetesマニフェストやHelm Chartなどに含まれる非推奨API / 削除済みAPIを検出できるツールです。
詳細は割愛しますが、対象のKubernetesバージョンを指定して実行することでそのバージョンで問題になるAPIを確認できます。
今回のworkflowでは、チェック対象のKubernetesバージョンとして実行時点のstableバージョンを取得してPlutoに渡しています。
そのため、Kubernetesのstableバージョンが更新された場合も次回実行時には新しいバージョンを基準に検知できます。
運用の流れは以下のようになります。
この記事では、リポジトリごとの検知結果を更新するIssueを管理用Issueと呼びます。
利用者側で必要な作業は、基本的に管理用Issueを作成することだけです。

利用者の負担を減らすために工夫したこと
Issueを作るだけで管理対象に追加できるようにした
チェック対象のリポジトリはJSONファイルで管理しています。
JSONを直接編集してもらうこともできますが、利用者側に余計な作業を増やしたくありませんでした。
また、記載ミスや手順のばらつきも起きやすくなります。
そのため管理対象への追加はIssueを起点にすることにしました。
利用者はIssueテンプレートに沿って、以下の情報を入力します。
- チェック対象リポジトリ
- チェック対象ブランチ
values/配下で利用するvaluesファイル

Issueが作成されるとGitHub Actionsが起動し、入力内容をもとにJSONファイルを更新するPull Requestを自動作成します。 最終的な反映は管理者がPull Requestを確認してから行うため、利用者の作業を減らしつつ追加内容も確認できる形にしています。
結果確認をIssueに集約した
Plutoの検出結果は対象リポジトリごとに紐づいたIssueに更新しています。 以下のような運用は利用者の手間になるので避けました。
- Actionsのログで結果を確認する
- 日次チェックの結果ごとに新しいIssueを作成する
リポジトリごとに管理用Issueを用意し、チェック結果でIssue本文を上書き更新する形にしました。
Issueのイメージは以下です。

検出結果がない場合は「検出なし」として更新します。 これによりチェックが実行されていないのか、問題が検出されなかったのかを区別できます。
READMEを自動生成して対象一覧を確認しやすくした
管理対象の一覧はJSONをもとにREADMEへ自動反映しています。
対象が増えてくると、どのIssueでどのリポジトリをチェックしているのか追いづらくなるためREADMEで一覧を可視化しました。
表示内容は対象リポジトリ・ブランチ・valuesファイル・管理用Issueへのリンクです。
これによりチェック対象と確認先のIssueをすぐ確認できます。
↓イメージ

管理対象からの除外もIssue Close起点にした
管理対象から外す場合も、JSONファイルを直接編集するのではなく対象の管理用IssueをCloseする運用にしました。
IssueがCloseされるとGitHub Actionsが起動し、対象のIssueに紐づく情報をJSONファイルから削除するPull Requestを作成します。
これにより利用者はIssueをCloseするだけで管理対象からの除外を依頼できます。
Actionsの設計
ここからはGitHub Actions側でどのように複数リポジトリをチェックしているかを紹介します。
この仕組みではチェック対象のリポジトリ情報を .github/repos.json で管理しています。
GitHub Actionsでは、このJSONに登録された情報をもとにリポジトリごとにチェックを実行しています。
repos.jsonをmatrixに展開して複数リポジトリをチェックする
チェック対象のリポジトリ情報は .github/repos.json にまとめています。
例えば1つの対象リポジトリは以下のような形式で管理しています。
{ "repo": "example-manifests", "branch": "main", "valuesFile": "prd-001.yaml", "issue": 123 }
各項目には、対象リポジトリ、ブランチ、valuesファイル、更新対象Issue番号を持たせています。
複数リポジトリを扱う前提だったため、workflowにリポジトリ情報を直接書くのではなくrepos.json でまとめることにしました。
日次チェック用のworkflowでは、この repos.json を jq -c で1行のJSONに変換し、GitHub Actionsの fromJSON を使ってmatrixに展開しています。
matrixに展開することで、登録されているリポジトリごとに同じチェック処理を実行できます。
対象を追加する場合もrepos.json にリポジトリ情報を追加すれば次回のチェックから対象に含まれるため、workflow本体を修正せずに済みます。
実際のチェック処理はreusable workflowにまとめており、以下の処理を行っています。

helm templateでレンダリングしてからPlutoに渡す
対象リポジトリではKubernetesマニフェストをHelm Chartとして管理しています。
そのためPlutoにChartのテンプレートファイルをそのまま渡すのではなく、まず helm template でvaluesを反映したKubernetesマニフェストを生成しています。
チェック処理では、対象リポジトリの manifests/* 配下を見てChart.yaml があるディレクトリをHelm Chartとして扱います。
処理としては以下の流れになります。

Plutoはレンダリング後のマニフェストを確認するため、実際に適用される内容に近い状態で非推奨API / 削除済みAPIを検知できます。
また、Helm Chartの crds/ 配下にあるCRDも出力に含めるため helm template では --include-crds を指定しています。
リポジトリごとのvalues差分を吸収する
基本的には、各Chartに対して以下のvaluesファイルを指定して helm template を実行しています。
values.yamlvalues/<valuesFile>
ただし、リポジトリによってはこれだけではレンダリングに必要な値が足りない場合があります。
例えばあるChartが別のChart用のvaluesを参照していたり、共通設定を別ファイルに分けていたりするケースです。
そのため、.github/repos.json には任意でChartごとの追加valuesファイルを指定できるようにしました。
以下イメージです。
{ "repo": "example-app-manifests", "branch": "main", "valuesFile": "test.yaml", "issue": 123, "valueFiles": { "app-a": [ "common/values.yaml", "database/values/prd.yaml" ] } }
workflow側にリポジトリごとの例外を増やしていくと管理がつらくなるため、差分は repos.json 側に寄せるようにしました。
これによりworkflow側は共通のままリポジトリごとのvalues構成に対応できます。
まとめ
今回は、PlutoとGitHub Actionsを使って、Kubernetesマニフェスト内の非推奨API / 削除済みAPIを継続的に検知する仕組みを作成しました。
Issueを起点に管理対象の追加や結果確認を行うことで、利用者の作業をできるだけ増やさずに継続的に確認できる形を意識しました。
今後は運用しながら課題が見つかれば改善していきたいと考えています。