Kubernetes Controllerの仕組み
次はKubernetesがどのようにControllerを利用しているのかを見ていこう。
先述したように、コントロールプレーンには「kube-controller-manager」と「cloud-controller-manager」がある。基本は前者でControllerを大量(大抵30〜40個)に実行している。後者はKubernetes実行基盤(クラウド)と何らかの連携するためのControllerになる。例えばクラスタに参加しているワーカーノードにノードのラベルを設定するとか、クラウド側のロードバランサーと連携するなどだ。
前者の「kube-controller-manager」では、実際にどのようなものがあるか見ていこう。Pod関連のControllerには下図のようなものがある。
例えばKubernetesでPodをデプロイする時なら、図の左上から下に向かって処理が流れていく。Deploymentというリソースが作られると、deployment-controllerがReplicaSetを作る。続いてReplicaSetのリソースを監視しているreplicaset-controllerがPodのリソースを作る。
実際はローリングアップデートなどで複雑になるものの、基本的にはこのような数珠つなぎでいろんな機能を実現している。他にもDaemonSetやStatefulSetのような他リソース管理でも対応するControllerがいて、Jobを実行するCronJobリソースに対しても対応するControllerがいる。なおControllerとリソースは必ずしも1対1ではなく、1つのリソースに対して複数のControllerが働くこともある。
今度はkube-proxy、ワーカーノードで動作するコアコンポーネントの1つ。主にServiceリソースとEndpointSliceリソースを基にネットワーク設定を行い、Serviceのエンドポイントにアクセスした際にPodにリクエストが届くようにする。動作モードは3種類あり、デフォルトはiptablesとなる。他にはipvsと、Windows用のkernelspaceがある。なおIPv4とIPv6のデュアルスタックもサポートされている。
kube-proxyは主にNATの設定を行う。外部ネットワークからパケットを受信すると、まずはNATのPREROUTINGが動き、KUBE-SERVICESというkube-proxyが設定するチェーンにジャンプし、CNI(Container Network Interface)プラグインによりPodに割り当てられる。
iptablesの設定の流れは下図のようになる。先述したEndpointSlice(画面上、右から2つ目のリソース)があり、これを監視しているendpointSliceConfigがサービスリソースの変更やエンドポイントサービスの変更を検知すると、それをトリガーにproxier.syncRunnerなどが次々に呼ばれてiptables設定が適切になるように調整される。
こうした仕組みがあるため、もし手動でiptablesの設定が書き換えられたとしても、たとえ壊されたとしても、さほど時間かからず自動的に修復される。Kubernetesにおけるあるべき状態を維持する「セルフヒーリング」と呼ばれるものは、このような形で成り立っている。