🦉

k8sのコントローラはどのようにリソースを更新しているのか

2023/05/08に公開

はじめに

Kubernetesは各種リソース(Pod, Deploymentなど)を各リソース専用のコントローラが管理している。これらコントローラは、さまざまなコンポーネントを連携させる事により、リソース管理を実現している。

今回、興味本位でコントローラの実装を読んだので、忘れているであろう将来の自分のためにも実装の解説を記事にしておく。

これから本記事も含め、下記3パートに分けてKubernetesのコントローラについて解説していく。

  1. 各コントローラはどのようにリソースを更新しているのか
  2. どのようにリソースの変更を検知しているのか
  3. どのようにリソースの変更を各コントローラに送信しているのか

本記事では、まず始めに「各コントローラはどのようにリソースを更新しているのか」について解説していく。

なお、本記事ではDeployment用のコントローラを利用して解説していく。

※解説している処理・コードはKubernetes v1.27.0のものとなる。

コントローラの生成

まず始めにコントローラの生成箇所から見ていこう。
Deployment用のコントローラは下記関数で生成・起動される。

https://github.com/kubernetes/kubernetes/blob/1b4df30b3cdfeaba6024e81e559a6cd09a089d65/cmd/kube-controller-manager/app/apps.go#L76-L89

ここでコントローラを生成・起動する。ほかのコントローラも同一ファイル内で同様の方法により起動されている。
コントローラの生成はNewDeploymentController()で実施されており、内部でさまざまなリソースを生成し、コントローラ構造体に埋め込んでいる。一連の処理の中でイベントハンドラも登録している。

https://github.com/kubernetes/kubernetes/blob/1b4df30b3cdfeaba6024e81e559a6cd09a089d65/pkg/controller/deployment/deployment_controller.go#L115-L142

DeploymentはReplicaSetやPodなどのリソースと関連性があるので、それらのイベントを検知した場合のハンドラも登録されている。

コントローラの起動

New関数で構造体が生成されたあと、startDeploymentController()DeploymentController.Run()を実行し、コントローラを起動する。

https://github.com/kubernetes/kubernetes/blob/1b4df30b3cdfeaba6024e81e559a6cd09a089d65/pkg/controller/deployment/deployment_controller.go#L157-L180

これが実行されるとContextがキャンセルされるまで、DeploymentController.processNextWorkItem() が定期的(1秒毎)に実行される。

https://github.com/kubernetes/kubernetes/blob/1b4df30b3cdfeaba6024e81e559a6cd09a089d65/pkg/controller/deployment/deployment_controller.go#L478-L489

このメソッドが最新のリソース状態をキューから取得しリソースの状態を正しい状態に変更する。
なお、最新状態はイベントハンドラから伝搬される。下記はDeploymentが更新された場合のイベントハンドラ。

https://github.com/kubernetes/kubernetes/blob/1b4df30b3cdfeaba6024e81e559a6cd09a089d65/pkg/controller/deployment/deployment_controller.go#L188-L193

このハンドラはイベント発生時に最新のリソース状態を受け取り DeploymentController.enqueue() を用いてキューに格納している。

リソース更新処理

イベントが発生後、最新状態がキューから取得されると状態同期のためのメソッドが呼び出される。このメソッドの実態はNewDeploymentController()で設定されている。

https://github.com/kubernetes/kubernetes/blob/1b4df30b3cdfeaba6024e81e559a6cd09a089d65/pkg/controller/deployment/deployment_controller.go#L144

なので処理はDeploymentController.syncDeployment()で定義されている。

このメソッドは対象のDeploymentリソースの最新の状態を確認し、適した更新処理を行う。実際には下記流れで状態を確認し、更新処理を実行している。

  1. すでに対象のリソースが削除されていれば、何もせずに終了する
  2. 対象のリソースが削除予定であれば、ステータス情報だけ更新する
  3. 対象のリソースがポーズ状態なら、スケール数の調整する
  4. ロールバックが要求されていれば、ロールバック処理を実行する
  5. スケーリングが要求されていれば、スケール数を調整する
  6. ロールアウトが要求されていれば、ロールアウト処理を実行する

各処理に対応する実際のコード

  1. すでに対象のリソースは削除されているか
    更新対象のリソースはすでにいないので終了。

https://github.com/kubernetes/kubernetes/blob/1b4df30b3cdfeaba6024e81e559a6cd09a089d65/pkg/controller/deployment/deployment_controller.go#L595-L599

  1. 対象のリソースは削除予定か
    削除されるのでステータス情報だけ更新して終了。

https://github.com/kubernetes/kubernetes/blob/1b4df30b3cdfeaba6024e81e559a6cd09a089d65/pkg/controller/deployment/deployment_controller.go#L634-L636

  1. 対象のリソースはポーズ状態か
    ロールアウトが停止されているのでスケール数の更新だけ行い終了。

https://github.com/kubernetes/kubernetes/blob/1b4df30b3cdfeaba6024e81e559a6cd09a089d65/pkg/controller/deployment/deployment_controller.go#L645-L647

  1. ロールバックが要求されているか
    ロールバック処理を実行し終了。

https://github.com/kubernetes/kubernetes/blob/1b4df30b3cdfeaba6024e81e559a6cd09a089d65/pkg/controller/deployment/deployment_controller.go#L652-L654

  1. スケーリングが要求されているか
    スケール数を調整し終了。

https://github.com/kubernetes/kubernetes/blob/1b4df30b3cdfeaba6024e81e559a6cd09a089d65/pkg/controller/deployment/deployment_controller.go#L656-L662

  1. ロールアウトが要求されているか
    デプロイ戦略に応じたロールアウト処理を行い終了。

https://github.com/kubernetes/kubernetes/blob/1b4df30b3cdfeaba6024e81e559a6cd09a089d65/pkg/controller/deployment/deployment_controller.go#L664-L669

各処理は更新対象となるReplicaSetやPodなどを取得し、KubernetesのAPIを叩いて更新処理を行っている。実際にこの更新が反映されるのはReplicaSetなどのコントローラがDeploymentコントローラと同様に状態更新イベント取得した時となる。

各更新処理の詳細は、下記ディレクトリ下で実装されている。ファイル名が更新処理と対応しているのでどこに実装があるかはわかりやすいはず。
https://github.com/kubernetes/kubernetes/tree/v1.27.0/pkg/controller/deployment

おわりに

本記事では、コントローラによるリソースの更新処理について解説した。解説対象として、Deployment用のコントローラを用いたが、ほかのコントローラも同様の流れでリソースを更新している。

次回の記事では、「どのようにリソースの変更を検知しているのか」について解説する。

Discussion