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を開始してハンドルするコントローラーとなっています。
また、コントローラーを作成する際のガイドラインがあるので、カスタムコントローラーを作成する場合は一度目を通しておく必要があります。