Kubebuilder で Core Resource の Admission Webhook を作る

hitsumabushi845Posted by

この記事は GRIPHONE Advent Calendar 2021 12日目の記事です。

こんにちは。SREの島田です。最近は美味しい曖昧の楽曲がお気に入りです。

Kubebuilder は Kubernetes のカスタムコントローラの作成を支援するツールです。Kubebuilder では、カスタムコントローラだけでなく、作成されたカスタムリソースや Core Resource への Webhook も併せて作成することができます。

本記事では、controller-runtime v0.10.2 で新たに導入された CustomDefaulter, CustomValidator を利用した、Core Resource への Webhook を作る方法について説明します。

TL;DR

本記事で実装した Webhook は以下のリポジトリで公開しています。

https://github.com/hitsumabushi845/pod-webhook-sample-for-advent-calendar

作成する Admission Webhook

本記事では、Pod resource に対して以下の Webhook を作成します。

  • Validating Webhook
    • 指定のアノテーションが付与されていなかった場合、Pod の作成を拒否する Validation
  • Mutating Webhook(Defaulting Webhook)
    • 指定のアノテーションの値をコンテナの環境変数に挿入する Defaulting

Webhook の作成

0. Kubebuilder のインストール

公式の Quick Start を見ながらインストールしていきます。

https://book.kubebuilder.io/quick-start.html

1. Kubebuilder プロジェクトの作成

まずはプロジェクトのディレクトリを作成します。

次に、api と webhook のひな形を作成します。

今回は webhook のみを作成するため、カスタムコントローラは作成しません。
そのため、create api の引数では --resource=false --controller=false を指定しておきます。

create webhook では、group, version, kind は api と同様に Pod resource の値を指定します。
加えて --defaulting --programmatic-validation を指定して Defaulting(Mutation), Validating それぞれの webhook のひな形を作成します。

ここまでで以下のファイルが生成されます。
本記事ではテストコードの実装は行いませんので、api/v1/webhook_suite_test.go ファイルは消しておきます。

加えて、カスタムコントローラの作成を行わないため、プロジェクト直下の Dockerfile を編集して、COPY controllers/ controllers/ の記述を削除またはコメントアウトします。

2. CustomValidator/CustomDefaulter を利用できるようにする

冒頭でも述べたとおり、CustomValidator/CustomDefaulter は controller-runtime v0.10.2 から導入された機構です。しかし、Kubebuilder v3.2.0 時点では controller-runtime v0.10.0 ベースでプロジェクトが作成されるため、手直しが必要となります。

go.mod の編集

controller-runtime v0.10.2 を利用するため、プロジェクト配下の go.mod を以下の通り変更します。
本記事ではテストコードの実装は行わないため、テスト用のモジュールの読み込みも消しておきます。

pod_webhook.go を編集する

api/v1/pod_webhook.go を以下のように編集します。

具体的には、CustomDefaulter, CustomValidator を実装する構造体を作成します。以下の例では、PodWebhook という名称で構造体を作成しています。

そのほか、以下の変更を行っています。

  • //+kubebuilder:webhook マーカーコメントの path/mutate--v1-pod, /validate--v1-pod にそれぞれ変更
    • webhook の path は /mutate-$GROUP-$VERSION-$KIND, /validate-$GROUP-$VERSION-$KIND になるため(implementation
  • //+kubebuilder:webhook マーカーコメントの name を変更

以降は Default/ValidateCreate/ValidateUpdate 関数を実装することで Webhook を作成していきます。

3. Webhook を実装する

Default の実装

素朴に Annotation の有無を確認し、Annotation が存在する場合は指定された値を Env に追加します。
ここではコードを簡潔にするため Multi-container の考慮は除いています。考慮する場合は range pod.Spec.Containers で回します。

ValidateCreate, ValidateUpdate の実装

main.go の実装

作成した Webhook を登録していきます。
main.goSetupWebhookWithManager の部分を以下の通り置き換えます。

4. Webhook を単体動作させるために生成されたマニフェストを編集する

config/ 以下に kubebuilder コマンドで生成されたマニフェストファイルが配置されていますが、生成されたままではカスタムコントローラ用の記述が残っているため、Webhook 単体で動作させるためいくつか手を加えます。

config/default/kustomization.yaml

以下の変更を加えます。

  • bases 以下
    • コメントアウト(もしくは行ごと削除)する
      • ../crd
    • コメントアウトを外す
      • ../webhook
      • ../certmanager
  • patchesStrategicMerge 以下
    • コメントアウトを外す
      • manager_webhok_patch.yaml
      • webhookcainjection_patch.yaml
  • vars 以下のコメントアウトを全て外す

config/rbac/kustomization.yaml

本記事の例では Webhook が Role の付与を必要としないため、make manifestrole.yaml が生成されません。そのため、role.yaml の参照をコメントアウトします。

作成した Webhook の動作確認

Kind 上で動作を確認します。Kind での動作確認は以下で説明されている通りに実施します。

カスタムコントローラーの動作確認 · つくって学ぶKubebuilder

Kind クラスタの準備

上記ドキュメントに従って、Kind クラスタの作成、cert-manager のインストール、コンテナイメージのビルドと Kind 環境へのロードを実施します。
コンテナイメージは controller:latest として作成・利用されますが、$IMG を設定することで名称の変更が可能です。本記事では hitsumabushi845/advent-calendar-webhook:latest としています。

Webhook をクラスタに適用する

上記ドキュメントに従って作成した Webhook をクラスタに適用します。
今回 CRD は作成していないので、make install は実行せず、make deploy から実行します。

Validating Webhook の動作確認

アノテーションを付与していない Pod の適用を試みて、Pod が作成できないことを確認します。

Mutation Webhook の動作確認

アノテーションを付与した Pod の適用を試みて、Pod が作成できること、環境変数が挿入されていることを確認します。

Pod が作成でき、作成された Pod にアノテーションで指定された値の環境変数が挿入されていることが確認できました。やったー!

おわりに

Kubebuilder を使った Core Resource への Webhook の実装方法について紹介しました。
Kubebuilder(というか controller-runtime)は機能追加や変更が活発に行われています。そのため、この実装方法がいつまで有効なのかも正直定かではないですが、たぶんこのやりかたがシンプルだとおもいます()

ではでは。

参考文献