Cloud Native Days Tokyo 2020(#CMDT2020)で発表したCloud Controller Managerに関するセッションです
https://event.cloudnativedays.jp/cndt2020/talks/32
Cloud Controller ManagerDeep DiveCloud Native Days 2020(2020/09/09)@bells17
View Slide
▶ Daiki Hayakawa / @bells17▶ Software Engineer▶ 主に Kubernetes 関連コンポーネントの開発など▶ Kubernetes #sig-docs-ja-reviews▶ CNBF実⾏委員▶ @bells17_
今⽇話すこと▶ Cloud Controller Managerの概要▶ Cloud Controller Managerの導⼊背景▶ Cloud Controller Managerの実装と動作するコントローラーについて▶ Cloud Providerの概要と実装⽅法について
注意点▶ 内容としてはCloud Controller ManagerのDeep Diveセッションを想定してます+ なのでKubernetesそのものの説明は、ある程度知っている前提で 話すと思います▶ コードべースはv1.17です(release-1.17タグ)+ ちょっと古いけど最新版もそんなにロジック変わらないはず(たぶん)
アジェンダ1. Cloud Controller Managerとは?2. Kubernetes アーキテクチャのおさらい3. Cloud Controller ManagerのDesign Proposal4. Cloud Controller Managerの実装の概要5. Kubernetes Componentの実装6. Cloud Controller Managerが起動するコントローラー群7. Cloud Provider8. まとめ
Cloud Controller Managerとは?
Cloud Controller Manager▶ Kube Controller ManagerなどKubernetesのコアコンポーネントから クラウドプラットフォームに関するロジックを分離させたコンポーネント+ クラウドプラットフォーム: AWSとかOpenStackみたいなk8sを動作 させてるIaaS環境というイメージが近い▶ 追加されたk8sノードの初期化処理や、Serviceのtype: LoadBalancerに対応したL4ロードバランサーの構築をしたりといった、k8sが利⽤している クラウド環境との連携を⾏うことができる▶ 対応するクラウド環境と連携させるためのCloud Provider実装を組み込んでビルドする必要がある+ 公式やクラウドプラットフォームがサポートしているCloud Provider実装があれば⾃前での実装は不要
Kubernetesアーキテクチャのおさらい
https://github.com/kubernetes/website/blob/fb6364da0afd19e8a9515aaae2de9bc74a0a6abd/static/images/docs/components-of-kubernetes.png
Cloud Controller Managerの Design Proposal
https://github.com/kubernetes/enhancements/blob/435a1c5c1468f363ecb6437d4a160551ee7a9d3c/keps/0001-kubernetes-enhancement-proposal-process.md
Design Proposalの要約(動機)▶ 当時各Cloud Providerの実装のアップデートがKubernetesのライフサイクルに依存しているという問題があった+ Kubernetesのリリースサイクルは3ヶ⽉に1度▶ そのためCloud Provider実装をKubernetesのコアから外部に移⾏したい+ Cloud Provider⾃⾝がリリースサイクルを管理できるようになる
Design Proposalの要約(変更内容)▶ 当時はKubernetesの複数のコンポーネントがCloud Providerの実装に 依存していた▶ 依存コンポーネントは+ kube-controller-manager+ kubelet+ kube-apiserver▶ これらのリファクタリングを⾏いつつ、Cloud Provider実装に依存する箇所をCloud Controller Managerに処理を切り出す
結果的に変化したこと▶ 外部化することで、Kubernetes公式のサポート外環境でもクラウドとの連携が可能になった+ Kubernetesが提供するインターフェイスに沿った実装を組み込めば、任意のクラウド環境向けのCloud Controller Managerが実装可能になったため▶ 各種コンポーネントのバイナリに含まれていたCloud Provider向けの実装が削減されたため、その分バイナリサイズが⼩さくなった
https://kubernetes.slack.com/archives/C718BPBQ8/p1566870958006200実際に約70MBほどサイズが減ったらしい
Cloud Controller Managerの実装の概要
アーキテクチャ▶ 4種類のコントローラー起動+ Node+ Node Lifecycle+ Service+ Route▶ 各コントローラーはそれぞれでイベントハンドリングを⾏い、必要に応じて組み込んだCloud Providerのメソッドを呼び出す▶ クラウドプラットフォームとの直接のやり取りはすべてCloud Providerを経由して⾏う▶ Cloud Providerはインターフェイスが定義されていて、独⾃実装する場合はインターフェイスを満たしたものを実装する
Kubernetes Componentの実装
基本パターン▶ Managerプロセス全体の中で1つ、または複数のコントローラーが実⾏される▶ コントローラーは1つにつき、1種類のKubernetesリソースのみに対する調整ループ(Reconciliation Loop)が実⾏される+ 調整ループ: リソースのあるべき状態(Desired State)と実際の状態(Actual State)を⽐較~あるべき状態になるように調整処理を⾏うもの+ なので、2種類のリソースに対しては、最低2コントローラー以上が あるのが基本
調整ループ▶ 主に以下の2種類の⽅法で実⾏される+ Event Handlers: 監視対象のKubernetes Resourceの更新といった、なんらかのイベントを元に実⾏される+ 無限ループによる定期実⾏: 設定値に基づいて数秒毎などの間隔で定期実⾏が⾏われる
https://github.com/kubernetes/sample-controller/blob/master/docs/images/client-go-controller-interaction.jpeg
▶ Kubernetesのコードリーディングをする上で知っておくと良さそうなことこういったKubernetes Componentの実装周りについてはコードリーディングについての記事の中で書いたので良ければ⾒てください
Cloud Controller Managerが起動するコントローラー群
ServiceController(1)▶ Serviceのtype: LoadBalancerの設定に基づきクラウド環境のL4ロードバランサーの構築・設定を⾏うコントローラー▶ 以下の2種類のメソッドによりL4ロードバランサーのDesired Stateを実現する+ worker: Kubernetes Component実装の基本パターンのEventHandlersパターンによるイベント駆動+ Serviceリソースのイベントをハンドリングして調整ループを実⾏+ LBの作成/更新/削除処理を⾏う+ nodeSyncLoop: 100秒毎に実⾏され、各Service type: LoadBalancerに対応する、クラウド側のロードバランサーに紐付けるノード⼀覧の 更新処理を⾏う
ServiceController(2)▶ LBに紐付けが⾏われるノードは以下の条件にマッチするもの+ Ready状態のノードであること+ unschedulableではないノードであること+ kubectl cordon コマンドを使うとunschedulableとなり、Podがスケジュールされなくなる+ "LegacyNodeRoleBehavior" feature gateがONの場合+ 以下のラベルが無いノードであること+ "node-role.kubernetes.io/master"+ "ServiceNodeExclusion" feature gateがONの場合+ 以下のラベルが無いノードであること+ “node.kubernetes.io/exclude-from-external-load-balancers"+ "alpha.service-controller.kubernetes.io/exclude-balancer"
ServiceController(3)▶ 個⼈的に気になっている点+ LBの作成/削除を⾏うのは基本的にworker側の調整ループで⾏う想定となっている+ nodeSyncLoopではCloud ProviderのLB設定をアップデートするメソッド(UpdateLoadBalancer)を呼び出すのみ+ そのため、クラウド側で該当のLBの削除などを⾏っても、該当LBに紐づくServiceリソースの変更イベントが無い限りはLBが⾃動で再構築されるといったことは⾏われない+ Cloud Provider側のUpdateLoadBalancerでLBの有無を確認し、無ければ再⽣成する処理を⾏えば対応可能ではあるが、そういった実装になっているCloud Providerは把握している範囲では存在しない
NodeController(1)▶ k8sの各ノードの初期化処理を⾏うコントローラー▶ NodeリソースのCreate/Updateイベントをハンドリングして調整ループを実⾏▶ `node.cloudprovider.kubernetes.io/uninitialized`というtaintが 付与されているノードを初期化処理が⾏われていないノードとみなして実⾏対象にする▶ `node.cloudprovider.kubernetes.io/uninitialized` taintはkubeletを`--cloud-provider=external`フラグ付きで起動すると付与される
NodeController(2)▶ 以下の処理を⾏う+ NodeオブジェクトにIPアドレス情報を設定+ NodeオブジェクトのラベルにNodeが動いているマシン情報 (e.g. インスタンスタイプ)やゾーン、リージョン情報の設定▶ 上記が完了すると`node.cloudprovider.kubernetes.io/uninitialized`taintの除去を⾏う
NodeLifeCycleController▶ k8sの各ノードの状態チェックを⾏うコントローラー▶ 設定値のNodeMonitorPeriod秒毎に調整ループを⾏う▶ 処理としては全ノードに対して以下のようなことを⾏う+ ノードのステータスが”Ready”かチェックを⾏う+ “Ready”ではない場合、ノードがシャットダウンしているかチェックを⾏い、シャットダウン状態であれば`node.cloudprovider.kubernetes.io/shutdown` taintを付与する+ シャットダウン状態のノードのステータスが”Ready”に復帰すればtaintを除去する+ “Ready”でもないし、シャットダウン状態でもないのであれば、インスタンスが存在するのかのチェックを⾏い、存在しなければノードの削除を⾏う
RouteController▶ k8sの各ノードのPodCIDRの経路情報の設定を⾏うコントローラー▶ 設定値のRouteReconciliationPeriod秒毎に調整ループを⾏う▶ 前提としてClusterCIDRが未設定のクラスターのとき動作するようになってるっぽい▶ 処理としては以下のようなことを⾏っているっぽい+ VPCなどの経路設定情報を取得+ 各ノードのPodCIDRの経路設定が⾏われているか確認を⾏い、まだ ⾏われていなければ経路情報の設定を⾏う+ すでに使われていない古い経路情報が残っていれば、それらの削除を⾏う+ もし経路設定に失敗しているノードがあれば、該当ノードのネットワークコンディションを失敗状態にする
▶ KubernetesのCloud Controller Managerについて▶ KubernetesのServiceControllerの実装Cloud Controller Managerのコントローラーに関する記事は以下の記事でも書いたので興味があればチェックしてみてください
Cloud Provider
Cloud Provider▶ Cloud Controller Managerに組み込んで実⾏される▶ Goで定義されたインターフェイスのメソッドを実装して組み込むことで、独⾃のCloud Provider実装をCloud Controller Managerから利⽤することができる▶ Goのインターフェイスであるcloudprovider.Intrefaceは https://github.com/kubernetes/cloud-provider/blob/release-1.17/cloud.go にある
独⾃のCloud Providerを実装する▶ 独⾃のCloud Providerを実装する場合に⾏うのは以下のようにする+ cloudprovider.Intrefaceを満たすCloud Providerを実装+ “k8s.io/kubernetes/cmd/cloud-controller-manager/app”.NewCloudControllerManagerCommand().Execute()を実⾏するコマンドを作成する+ 上記コマンドでメイン処理実⾏前に予め以下を⾏うようにする+ ⾃作したCloud Providerの登録処理+ 実⾏するCloud Providerの指定▶ PodとしてCloud Controller Managerを実⾏する際には適切なRBACやtolerationsなどの設定を⾏う必要あり
注意点▶ Cloud Controller ManagerはCSIなどのように、どの機能を実装するとこう動作する、といった仕様が明確ではない▶ そのため、Cloud Controller Managerの実装を直接読む、他のCloudProvider実装を参考に実装するといった対応が必要になってくる
Digitaloceanのコマンド例(コメントを削ったものです)
Cloud Providerの登録処理はinit()を使って⾃動で⾏うことが多い
メソッドの実装はこんな感じに⾃分たちに必要なものだけ⾏う
まとめ
まとめ▶ Cloud Controller Managerの動作とその実装について紹介しました▶ Kubernetesの裏側で動作するコンポーネントがどんなふうに動作しているのかの理解を深めるきっかけになればと思います▶ 実際にCloud Providerを組み込んだCloud Controller Managerを⾃作してみるとKubernetesに対する理解が深まって⾯⽩いかなと思います
参考資料▶ Kubernetes Components https://kubernetes.io/docs/concepts/overview/components/▶ Cloud Controller Manager https://kubernetes.io/docs/concepts/architecture/cloud-controller/▶ Developing Cloud Controller Manager https://kubernetes.io/docs/tasks/administer-cluster/developing-cloud-controller-manager/▶ Controllers https://kubernetes.io/docs/concepts/architecture/controller/▶ Nodes https://kubernetes.io/docs/concepts/architecture/nodes/▶ client-go under the hood https://github.com/kubernetes/sample-controller/blob/master/docs/controller-client-go.md▶ Kubernetes Source Code: https://github.com/kubernetes/kubernetes/blob/release-1.17▶ Cloudprovider.Interface https://github.com/kubernetes/cloud-provider/blob/release-1.17/cloud.go▶ Refactor Cloud Provider out of Kubernetes Core https://github.com/kubernetes/community/blob/1922998843eb61d13eb41d6303e36e5e206a1cee/contributors/design-proposals/cloud-provider/cloud-provider-refactoring.md▶ Kubernetes Enhancement Proposal Process https://github.com/kubernetes/enhancements/blob/435a1c5c1468f363ecb6437d4a160551ee7a9d3c/keps/0001-kubernetes-enhancement-proposal-process.md▶ KEP Template https://github.com/kubernetes/enhancements/tree/435a1c5c1468f363ecb6437d4a160551ee7a9d3c/keps/NNNN-kep-template▶ digitalocean-cloud-controller-manager: https://github.com/digitalocean/digitalocean-cloud-controller-manager▶ Kubernetesのコードリーディングをする上で知っておくと良さそうなこと https://bit.ly/2BY8FzM▶ KubernetesのCloud Controller Managerについて https://bit.ly/2DW1oBP▶ KubernetesのServiceControllerの実装 http://bit.ly/2SCjm0C
Thanks / Question?▶ Daiki Hayakawa, @bells17▶ Slide: https://speakerdeck.com/bells17▶ Blog: https://medium.com/@bells17▶ @bells17_