Red HatでOpenShiftのサポートをしているid:nekopです。OpenShift 全部俺 Advent Calendar 2018 - Qiitaの15日目のエントリです。
前回はコントローラーのビルドの方法を解説しましたが、今回はもう少し実際の形のコントローラーがどのように構成されているかを見ていきます。
前回利用したサンプルコードexamples/out-of-cluster-client-configuration/main.goでは以下のようにシンプルにPodの一覧を取得するものでした。
clientset.CoreV1().Pods("").List(metav1.ListOptions{})
しかし、実際のコントローラーでは、最初にリストを取得し、以降は更新を検知して、それらをあるべき姿に更新する、current state -> desired stateという処理を行うループとなります。
この処理のサンプルがexamples/workqueue/main.goです。
ソースツリーのセットアップとビルド方法は前回と一緒なので省略します。今回はソースコードを見て行きますが、もしGo言語のソースコードを見る環境がない、という場合などはVSCodeを入れて該当ソースコードを開いて宣言部でF12キーを押せばジャンプできるので見やすいと思います。
初見だと結構読み解くのがつらい感じですが、sample-controllerのcontroller-client-go.mdというドキュメントにclient-goの動作の図解があります。
Informer
というコンポーネントがclient-goサイドでリストの取得と更新検知を行ってくれます。
カスタムコントローラーを記述する側ではInformerにResourceEventHandlerFuncsを登録しておくことで、AddFunc
, UpdateFunc
, DeleteFunc
がそれぞれコールバックされます。コールバックを受けたら一旦workqueueに置いて、カスタムコントローラー側はこのworkqueueを処理していく、というのがカスタムコントローラーの処理の基本形となります。
workquerueサンプルのコールスタックを簡略化すると以下のようになります。Controller.syncToStdout
がビジネスロジック部分となります。
- main - cache.NewIndexerInformer - Controller.Run - go informer.run - Controller.runWorker - Controller.processNextItem - workqueue.Get - Controller.syncToStdout - indexer.GetByKey(key) - workqueue.Done - (go informer.run) - IndexerInformer - ResourceEventHandler - workqueue.Add
ビジネスロジック部分ではindexer.GetByKey(key)
のようにIndexerを通してk8s objectを取得します。client-goのcache.NewIndexerInformer
がこのInformerとIndexerを作成してくれます。
sample-controllerにもうちょっと応用的なコードがあり、こちらはcache.NewIndexerInformer
ではなくInformerFactoryを利用して複数のobjectのinformerを開始してハンドルするコントローラーとなっています。
また、コントローラーを作成する際のガイドラインがあるので、カスタムコントローラーを作成する場合は一度目を通しておく必要があります。