Kpackのイメージ作成完了をGithubに通知するKubernetes Controllerを実装してみた

ソースコードのコミットしたあとに Kpackでのイメージが作成完了したのかわかりにくい!と思ったので、通知機能をKubernetesのControllerを使って実施しました。

ソースコード

出来上がったものはここにあるよ。

https://github.com/mhoshi-vm/kpack-gh-status-updater

まずは用語の説明から

以下この記事で登場する用語です。

  • kpack:
    Cloud Native Buildpacks を使い、ソースコードからイメージ作成およびStack/StoreやビルドパックをKubernetesのCustom Resource Definition(CRD)経由で管理するツールです。
  • Kubernetes Controller:
    KubernetesでCRDに対して何かイベントが発生したときに、特定の操作をおこなうことができるものです。今回はこれをJavaのSpring Bootで実装しました。
  • Github Commit Status:
    Githubのコミットごとに何かのチェックが発生させ、そのステータスをみることができます。通常はCIパイプラインの成功可否を表示するものですが、RestAPI経由で直接アップデートできます。詳細は、こちら

この中で、Kubernetes Controller、特にそれをJavaのフレームワーク、Springで実装するのが理解の難易度が高いと思います。

以下のSpringOneのコンテンツからかなり流用しているので、時間があればみていただくこととより理解ができます。

https://www.youtube.com/watch?v=5IROOj7sLKg

何を解決したかったか?

以下がkpackで今回の成果物なしのイメージ図です。kpack自体は素晴らしいツールなのですが、ソースコードのコミットをしたときに、イメージが作成が問題なくできたかどうかは、いちいち、Kubernetesのリソースのステータスを確認しにいく、というオペレーションが必要でした。

ちなみに、ビルドの状態は以下の感じです。

ほしい情報も詳細な情報ではなく、成功したか、否か程度でした。 何かポーリングするようなスクリプトをつくってもいいのですが、もっとイベント駆動型、可能な限りリアルタイムがほしく、これをKubernetes Controllerとして実装してみようと考えてみました。

以下の図のイメージへの更新です。Githubだけみていれば、イメージが完了したかいなかをみれるようにしてみました。

完成したもの

特定のコミットでkpackのビルドが開始すると、以下のイメージでビルド中なのがわかります。

特定のコミットでkpackのイメージが完了すると、この感じで反映されます。

失敗すると、以下のようになって、「あー、失敗したな、みにいかなきゃ」となる感じです。

ソースコード開発風景

「Spring BootでKubernetes Controller!?」な人もいると思うので開発方法を紹介します。

1. pom.xml にKubernetes Clientの登録

mavenでビルドしていますが、pom.xml は start.spring.ioで作るようなシンプルなものです。Kuberetes Clientの依存関係だけ手動で追加します。

2. CRDのYAMLファイルを作成する

Kubernetes Controllerを作る上で最初に開発するのが、KubernetesのCRDの定義YAMLファイルを作成します。 今回は以下のように開発しています。

https://github.com/mhoshi-vm/kpack-gh-status-updater/blob/main/k8s/crd/build.yaml

ちなみに、kpackそのもののCRD定義は以下です。

https://github.com/pivotal/kpack/blob/main/config/build.yaml

比べるとわかるのですが、だいぶ違います。元のkpackがスキーマにあまり値を定義していないのですが、このままだと後続の手順で、困るので必要な箇所は自分で定義しています。

3. CRDからCodeGenしてModelを生成する

CRDを定義後以下のようなGithub Actionsを使って構成します。オフィシャルガイドはこちらに。

私はGithub Actionsの方式でやっており、以下のように定義しています。

https://github.com/mhoshi-vm/kpack-gh-status-updater/blob/main/.github/workflows/generate-crd.yaml

この状態で先ほどのCRDをインプットに定義するとModelが含まれたZipファイルが生成されます。 それをほぼそのまま状態で展開したのが以下です。

https://github.com/mhoshi-vm/kpack-gh-status-updater/tree/main/src/main/java/jp/co/vmware/tanzu/kpackghstatusupdater/models

このディレクトリのこれらのファイルです。

4. Controllerの定義

このフェーズはほぼ「呪文」です。言われた通りにつくったものが以下です。

https://github.com/mhoshi-vm/kpack-gh-status-updater/blob/main/src/main/java/jp/co/vmware/tanzu/kpackghstatusupdater/configuration/BuildControllerConfiguration.java

細かいところで、手順3. で作成したModelに一部向く必要がありますが、それ以外はここで大差になることは少ないようです。

5. Reconcilerの定義

Reconciler の定義です。

https://github.com/mhoshi-vm/kpack-gh-status-updater/blob/main/src/main/java/jp/co/vmware/tanzu/kpackghstatusupdater/reconciler/BuildReconciler.java

基本的には @Override 部にビジネスロジックを書き加えます。注意が必要なところが以下であり、

  • 最終的な実行結果は、正常終了の場合、new Result(false)という結果を返し、処理がかんりょうしたことを通知します。Result(true)を返すとイベントがキューされ直されてしまいます。
  • イベントに通知されたリソースが存在しない場合は、「削除された」と解釈します。なのでその処理をいれます。
  • 何かのリソースをgetするたびに、存在するかしないかのチェックを入れるように。

6. ビジネスロジック(Github通知)をうめる

ここまでくれば、ただのJavaのコードです。この行からGithubのステータス更新の処理をかきます。

7. Kubernetes環境にデプロイする

出来上がったコードをコンテナ化したら(ここでまさにkpackを利用)これをKubernetes環境にデプロイします。YAMLファイルはここにあります。

Role権限でCRDに正しくアクセスできるように設定が必要なので注意が必要です。私の場合は、2.で定義したBuild Resourceにアクセスします。

結論

簡単ですが、Kubernetes Controller をつかってGithubの通知方法を紹介しました。Kubernetes Controllerが手慣れたSpringで開発できたことでグッと導入難易度が下がった印象です。

コード自体はまだまだアップデートするつもりですし、その他の応用にも使っていきます。