Whitebox Controller で作るカスタムコントローラー
Kubernetes のカスタムコントローラーを色々作って試したいことが増えてきたので、Whitebox Controller という動作を動的に変更できるコントローラーを開発している。
Whitebox Controller はコントローラーの内部処理を任意のコマンドや HTTP エンドポイントで置き換えることができる。コマンドや HTTP エンドポイントとは JSON 形式のデータをやりとりする。カスタムコントローラーを実装したい人は、Whitebox Controller から送信される JSON の内容に基づいて任意の処理を実行し、必要に応じて JSON の内容を更新して返すコマンドまたは HTTP エンドポイントを用意するだけで、お好みのカスタムコントローラーを実装できる。自由に中身の組み合わせを変えられることが Whitebox Switch に似ていることから、この名前をつけてみた。
Whitebox Controller を使うと、Kubernetes のカスタムコントローラーの実装に必要な Informer や Workqueue といった多くの仕組みや、deepcopy-gen といったツールの理解がなくてもコントローラーを手軽に実装して試せるようになるのがポイントだ。
インストール
GitHub のリリースページからバイナリーをダウンロードできる。実際はコンテナイメージで使うことが多いかもしれない。コンテナイメージは次のように取得できる。
$ docker pull summerwind/whitebox-controller:latest
使い方
Whitebox Controller は次のような内容の設定ファイルを指定して起動する。起動すると一般的な Kubernetes コントローラーと同じように設定ファイルで指定されたリソースの変更を監視する。この設定例では Hello というリソースを監視する。
# config.yaml
resources:
- group: whitebox.summerwind.dev
version: v1alpha1
kind: Hello
reconciler:
exec:
command: reconciler.sh
debug: true
$ whitebox-controller -c config.yaml
リソースの変更を検知すると、Whitebox Controller はそのリソースの状態を JSON 形式に変換して、設定ファイルで指定されたコマンドの標準入力または、指定の URL に HTTP リクエストを送信する。上の例では reconciler.sh
というシェルスクリプトの標準入力に、次のような JSON データが送られてくる。
{
"object": {
"apiVersion": "whitebox.summerwind.dev/v1alpha1",
"kind": "Hello",
"metadata": {
"creationTimestamp": "2019-07-21T11:20:01Z",
"generation": 2,
"name": "hello",
"namespace": "default",
"resourceVersion": "12326299",
"selfLink": "/apis/whitebox.summerwind.dev/v1alpha1/namespaces/default/hello/hello",
"uid": "27c313de-a560-11e9-ac7d-42010af00248"
},
"spec": {
"message": "Hello World"
}
}
}
ここでは、変更されたリソースの .object.spec.message
の内容を標準エラーに出力して、.object.status.phase
に completed
という文字列を設定するだけのコントローラーを実装するとしよう。この場合の reconciler.sh
は以下のようになる。ここではシェルスクリプトで実装しているが、Python や Ruby などお好みの言語でコマンドを実装するのももちろん OK だ。
#!/bin/bash
# JSON 形式のリソースの状態を標準入力から読み込む
STATE=`cat -`
# Phase を抽出
PHASE=`echo "${STATE}" | jq -r '.object.status.phase'`
# Phase が "completed" でなければ表示処理を実行
if [ "${PHASE}" != "completed" ]; then
# 標準エラー出力にメッセージを出力
NOW=`date "+%Y/%m/%d %H:%M:%S"`
echo -n "${NOW} message: " >&2
echo "${STATE}" | jq -r '.object.spec.message' >&2
# Phase を "completed" に更新
STATE=`echo "${STATE}" | jq -r '.object.status.phase = "completed"'`
fi
# 更新したリソースの状態を標準出力に書き出す
echo "${STATE}"
コントローラーが実装できたら、次のような設定ファイルやらシェルスクリプトを追加する Dockefile を書いてコンテナイメージをビルドすれば、カスタムコントローラーの出来上がり。
# Dockerfile
FROM summerwind/whitebox-controller:latest AS base
FROM ubuntu:18.04
RUN apt update \
&& apt install -y jq \
&& rm -rf /var/lib/apt/lists/\*
COPY --from=base /bin/whitebox-controller /bin/whitebox-controller
COPY reconciler.sh /reconciler.sh
COPY config.yaml /config.yaml
ENTRYPOINT ["/bin/whitebox-controller"]
$ docker build -t summerwind/hello-controller:latest .
$ docker push summerwind/hello-controller:latest
デプロイ
実装したカスタムコントローラーをいざ Kubernetes にデプロイしようとすると、様々なリソースを定義したマニフェストファイルが必要になってくる。Whitebox Controller に付属する whitebox-gen
コマンドを実行すれば、先ほどの設定ファイルからマニフェストファイルを生成できる。次の例は先ほどビルドしたコンテナイメージを hello-controller
という名前で kube-system
namespace に起動するためのマニフェストファイルを生成している。
$ whitebox-gen manifest -c config.yaml \
--name hello-controller \
--namespace kube-system \
--image summerwind/hello-controller:latest \
> hello-controller.yaml
生成したマニフェストファイルは必要に応じて細かい設定を追加するなどして、Kubernetes にデプロイしよう。なお、whitebox-gen
が出力するマニフェストは TLS 証明書の管理に cert-manager のカスタムリソースを使用しているので、事前に cert-manager をインストールしておく必要があることに注意してほしい。
$ kubectl apply -f hello-controller.yaml
もうちょっと詳しく知りたい場合はチュートリアルを参照してみてほしい。
その他の機能
ここまでに紹介したカスタムコントローラーを作る仕組みであれば、実は Metacontroller でも同じようなことができる。Whitebox Controller はカスタムコントローラーだけでなく、Admission Webhook も同じように実装できる。また外部サービスからの Webhook を受けてリソースを作る Injection Webhook という独自の機能も用意している。このあたりの機能はドキュメントの整備が追いついていないので、実装サンプルを見てもらえると雰囲気が掴めるかもしれない。
今後は Whitebox Controller の設定自体を Kubernetes のカスタムリソースとして定義できるようになると面白いかなと考えたりしている。なお、Whitebox Controller を使って本格的なカスタムコントローラーを実装しようとすると、物足りないと感じる部分が増えてくるかもしれない。そんな時は controller-runtime や kubebuilder を使って、より本格的なカスタムコントローラーの開発にぜひチャレンジしてみてほしい。