Pro Yearly is on sale from $80 to $50! »

Kubernetesのソースコードリーディング入門

 Kubernetesのソースコードリーディング入門

「APC勉強会#34 Kubernetesのソースコードリーディング入門」の発表資料です。

3fb238addd52d7b2460af8cc023b4cfb?s=128

ShinMatsuzaki

August 23, 2019
Tweet

Transcript

  1. Kubernetesのソースコードリーディング入門 2019.08.23 @shin_matsuzaki APC勉強会 #34

  2. 自己紹介 松崎 新 (まつざき しん) @株式会社エーピーコミュニケーションズ 趣味:野外コンサート、eSports観戦(LOL)

  3. 本日のアジェンダ 前半: k8sのソースコード入門 - ソースコードを読むと幸せになれますか? - レポジトリの紹介とゆるふわに入門するためのTIPS 後半: k8sぷちDeepdive -

    kube-schedulerを読もうとしてみる - CustomControllerを題材に学ぶ、k8sのイベント通知
  4. Disclaimer - 本発表に出てくるk8sのcodeは、v1.15準拠です - スライドの枠内に収めるためにエラーハンドラや コメント等を大幅に省略しています - 「ここは違うぞ」等ありましたら、懇親会の場でご指摘 頂けますと嬉しいです

  5. アジェンダ 前半: k8sのソースコード入門 - ソースコードを読むと幸せになれますか? - レポジトリの紹介とゆるふわに入門するためのTIPS 後半: k8sぷちDeepdive -

    kube-schedulerを読もうとしてみる - CustomControllerを題材に学ぶ、k8sのイベント通知
  6. 何らかのOSSのコードを読んだことある人? アンケート

  7. システムの仕組み/構造が 細かい粒度でわかるようになる

  8. (できれば)「細かい粒度」でシステムを理解したい 図:LinuxのIO Schedulerの動作とiostat(1)による可観測性

  9. コードが読めると.... • 仕様に強くなれる • トラブルシュート力が向上 • 試験設計に強くなれる

  10. コードが読めると.... • 仕様に強くなれる • トラブルシュート力が向上 • 試験設計に強くなれる • Deepな技術解説記事が書けるかも? •

    Operator*1 の開発者になれるかも? *1 CustomControllerを使って運用を自動化しよう という手法、開発されるCustomControllerのこと https://coreos.com/blog/introducing-operators.html
  11. あなたもLet's try!

  12. アジェンダ 前半: k8sのソースコード入門 - ソースコードを読むと幸せになれますか? - レポジトリの紹介とゆるふわに入門するためのTIPS 後半: k8sぷちDeepdive -

    kube-schedulerを読もうとしてみる - CustomControllerを題材に学ぶ、k8sのイベント通知
  13. Q. そもそもk8sのSRCって、どうやって 管理されているの? A. githubレポジトリで管理されています ⇒ https://github.com/kubernetes/kubernetes

  14. kubernetes / kubernetes • メインとなるレポジトリ • kube-apiserver, kube-controller-manager, kube-scheduler等主要なdaemonのソースコードが格納 主要なレポジトリ(1)

  15. daemonの本体と なる構造体 + メソッド等 エントリポイン トとなるmain() 関数, etc

  16. None
  17. kubernetes / apimachinery • APIオブジェクトのSchemaを定義するレポジトリ • k8s v1.8より、APIオブジェクトは kubernetes/apimachinery にて定義されるデータ構造とコード

    の自動生成機能(code generation)を使って、実装される仕様に変わった。[1] kubernetes / api • Kubernetes / apimachinery にて定義のSchemaを元に実際のAPIオブジェクトを定義 kubernetes / client-go • kube-apisererと通信を行うclient生成用の各種関数(i.e. ) + 構造体(i.e. struct Clientset) • イベント通知エンジンである informer framework を構成する関数, キュー, キャッシュ機構etc [1] Kubernetes Deep Dive: Code Generation for CustomResources https://blog.openshift.com/kubernetes-deep-dive-code-generation-customresources/ 主要なレポジトリ(2)
  18. Q. 入門してみたいのですが、 どういう観点で読むとGood? A. お勧めは…

  19. お勧め(1): まずはgit blameしてみる コード内の各行が、いつ誰によって コミットされたものなのか?が一望できる

  20. お勧め(1): まずはgit blameしてみる

  21. なにが嬉しいかというと ... ⇒開発者の存在を体感できる ⇒アクティブに活動している人なら followしてみるといいかも 読んでいるコードの各行更新が最後にいつ 実施されたのかがわかる ⇒ どの程度枯れた実装なのかの判断材料になる

  22. プルリクを見ることで、過去の変更の意図が確認できる。 コミット差分と照らし合わせてみるとよりGood なにが嬉しいかというと ... プルリク:コミットの設計意図が読み解ける コミット差分:コードの変更箇所が確認できる コミット差分が見られる プルリクエストが見られる コミットの詳細が見られる

  23. kube-controller-managerのメインルーチン (...から呼び出されているcobra command) https://github.com/kubernetes/kubernetes/blob/091a5dc53b1b961f95de225ca4cddf33193051cd/cmd/kube-controller-manager/app/controllermanager.go#L98-L107 ※割と初期(4 years ago)に書かれた、kube-controller-managerの概要を示したコメント。 当時はまだ、replicasetが存在しなかったために、“replication controller”との表記になっている 当時の設計意図や開発者の

    想いがわかってうれしい! お勧め(2): コメントを読んでみる
  24. お勧め(3): 構造体を読む https://godoc.org/k8s.io/kubernetes/pkg/controller/namespace

  25. Specification = DesiredStateを定義 CurrentState. Reconciliation Loopの評価に使用される Kind(str型)とAIPVersion(str型)をメンバに持つ構造体 Interface. kind情報生成用の関数 &

    APIオブジェクトの複製用の関数の実装を強制する https://github.com/kubernetes/api/blob/0772a1bdf941dcf775fef01dd13d667ea3031902/core/v1/types.go#L3488 お勧め(3): 構造体を読む Pod metav1.TypeMeta metav1.ObjectMeta PodSpec PodStatus
  26. Piyo Hoge M ( int型 ) Hoge N ( int型

    ) 参考: go言語の構造体の埋め込みパターン • 構造体メンバに別の構造体を追加できる ※ 構造体へのポインタ型としても埋め込みが可能 • 以下の場合、Piyo.Hoge.N でもアクセスできるし、埋め込まれた構造名を省略し、 Piyo.N でもアクセスできる ↑構造体名 ↑構造体メンバ
  27. APIオブジェクトの実装 https://github.com/kubernetes/apimachinery/blob/533d101be9a6450773bb2829bef282b6b7c4ff6d/pkg/apis/meta/v1/types.go#L41 metav1.TypeMeta metav1.ObjectMeta PodSpec PodStatus

  28. APIオブジェクトの実装 https://github.com/kubernetes/apimachinery/blob/533d101be9a6450773bb2829bef282b6b7c4ff6d/pkg/apis/meta/v1/types.go#L113 ※スペースの都合でコメントは削除(内容がすごく充実しているので、一読をお勧めします) metav1.TypeMeta metav1.ObjectMeta PodSpec PodStatus

  29. Podの場合のデータ構造 https://github.com/kubernetes/api/blob/0772a1bdf941dcf775fef01dd13d667ea3031902//core/v1/types.go#L2816:6 APIオブジェクトの実装 ※ 実際のkubectl get <podname> -oyaml の実行結果 metav1.TypeMeta

    metav1.ObjectMeta PodSpec PodStatus
  30. Podの場合のデータ構造 https://github.com/kubernetes/api/blob/0772a1bdf941dcf775fef01dd13d667ea3031902//core/v1/types.go#L3376:6 APIオブジェクトの実装 ※ 実際のkubectl get <podname> -oyaml の実行結果 metav1.TypeMeta

    metav1.ObjectMeta PodSpec PodStatus
  31. アジェンダ 前半: k8sのソースコード入門 - ソースコードを読むと幸せになれますか? - レポジトリの紹介とゆるふわに入門するためのTIPS 後半: k8sぷちDeepdive -

    kube-schedulerを読もうとしてみる - CustomControllerを題材に学ぶ、k8sのイベント通知
  32. 初期化処理 メインループ 終了処理 podのeventをwatchし、podの作成イベントを検知したら 以下のループを回す kube-schedulerのバイナリを起動 メインループとして無限ループを開始 Stopシグナルを受け付けると、ハンドラ実行し停止シーケンス開始 目標設定:アプリケーションの起動からメインルーチンまでを読む Processが終了

    読 む 範 囲 ※具体的には、以下のscheduling処理の実装内容と、 そこに至るまでの処理の流れをざっくり追いかけたい
  33. 読み進め方の指針 • エントリポイントから読み始め、処理の流れを関数単位追いかけていく ※コードを全て隅から隅まで全部読むということはしない/必要な所のみ読む • オブジェクトジャンプ/メソッドジャンプ = 構造体やメソッドの定義元に定義部分にジャンプする機能の総称 main() 関数

    1 関数 2
  34. 【参考】GithubをWebで見る場合の お勧めのchomeエクステンション 各種変数や関数のDefinitionを github上で左クリックで表示, 定義元 / 呼び出している関数 へ1クリックでジャンプできるの で、それを使ってタグジャンプ していく

    左クリックでポップアップ
  35. 実際にkube-schedulerのコードを読んでみる • エントリポイントは通常、cmdディレクトリにあるので、 ディレクトリ直下のファイルを開け、まずは main() を探す

  36. 実際にkube-schedulerのコードを読んでみる https://github.com/kubernetes/kubernetes/blob/2d3c76f9091b6bec110a5e63777c332469e0cba2/cmd/kube-scheduler/scheduler.go#L34

  37. 実際にkube-schedulerのコードを読んでみる https://github.com/kubernetes/kubernetes/blob/2d3c76f9091b6bec110a5e63777c332469e0cba2/cmd/kube-scheduler/app/server.go#L62

  38. 参考:cobra.Command.Execute() -> cobra.Command.Run() https://github.com/spf13/cobra

  39. struct Command Use string Long string 参考:cobra.Command.Execute() -> cobra.Command.Run() Run

    func(cmd *Command, args []string) Run (c *Command) Execute() error Run (c *Command) ExecuteC() (cmd *Command, err error) Run (c *Command) execute(a []string) (err error) (1)call ポインタ レシーバ (2)call (3)call
  40. 実際にkube-schedulerのコードを読んでみる https://github.com/kubernetes/kubernetes/blob/2d3c76f9091b6bec110a5e63777c332469e0cba2/cmd/kube-scheduler/app/server.go#L62

  41. 実際にkube-schedulerのコードを読んでみる https://github.com/kubernetes/kubernetes/blob/2d3c76f9091b6bec110a5e63777c332469e0cba2/cmd/kube-scheduler/app/server.go#L109 *completedConfig struct CompletedConfig //public *Config struct completedConfig //private

    // CustomControllerが必要とする諸々の // コンテキスト情報 - ComponentConfig - LoopbackClientConfig - InsecureServing - InsecureMetricsServing - Authentication - Authorization - SecureServing - Client - InformerFactory - PodInformer - EventClient - Recorder - Broadcaster - LeaderElection struct Config 埋込 埋込
  42. 実際にkube-schedulerのコードを読んでみる Scheduler構造体を初期化 https://github.com/kubernetes/kubernetes/blob/2d3c76f9091b6bec110a5e63777c332469e0cba2/cmd/kube-scheduler/app/server.go#L159 ※ scheduler構造体の定義

  43. 実際にkube-schedulerのコードを読んでみる https://github.com/kubernetes/kubernetes/blob/2d3c76f9091b6bec110a5e63777c332469e0cba2/pkg/scheduler/scheduler.go#L254 停止シグナルを受け付けるまで、 無限ループで、scheduleOne()を実行し続ける つまり、以降の処理がメインルーチンとなる 受信専用チャネルにエンキューされると、無限ループが止まる。 つまり、ストップシグナルの受付をキューがしている https://github.com/kubernetes/kubernetes/blob/2d3c76f9 091b6bec110a5e63777c332469e0cba2/pkg/scheduler/fact ory/factory.go#L118

    https://github.com/kubernetes/apimachinery/blob/f2f3a405f61d6c2cdc0d00687c1b5d90de91e9f0/pkg/util/wait/wait.go#L87
  44. 実際にkube-schedulerのコードを読んでみる https://github.com/kubernetes/kubernetes/blob/2d3c76f9091b6bec110a5e63777c332469e0cba2/pkg/scheduler/scheduler.go#L44 2 https://github.com/kubernetes/kubernetes/blob/2d3c76f9091b6bec110a5e63777c332469e0cba2/pkg/scheduler/scheduler.go#L283 ← workqueueからpod名+タイムスタンプをpop()

  45. sched.config.Argorithm.Scheduleすると、実際には何が実行されるのか? ※ sched.Config.Algorithm は interface型 なので、実際にどの構造体が入るかは不定(interfaceを満たせば何でも入る) ⇒Schedule() で何が実行されるのかも、その埋め込まれる構造体に依存する https://github.com/kubernetes/kubernetes/blob/2d3c76f9091b6bec110a5e63777c332469e0cba2/pkg/scheduler/factory/factory.go#L82 https://github.com/kubernetes/kubernetes/blob/2d3c76f9091b6bec110a5e63777c332469e0cba2/pkg/scheduler/core/generic_scheduler.go#L128

  46. Scheduler構造体を初期化 sched.config.Argorithm.Scheduleすると、実際には何が実行されるのか? config *Config struct Scheduler struct Config struct genericScheduler

    埋込 埋込 Algorithm: algo https://github.com/kubernetes/kubernetes/blob/2d3c76f9091b6bec110a5e63777c332469e0cba2/cmd/kube-scheduler/app/server.go#L159 func (g *genericScheduler) Schedule(pod *v1.Pod, nodeLister algorithm.NodeLister) (result ScheduleResult, err error) ポインタ レシーバ Scheduler構造体 生成時に、2種の 構造体が埋め込 まれている
  47. 各nodeがpodのデプロイ条件を満たすか判定する処理 条件を満たすノードが複数ある場合の優先度付け 実際にkube-schedulerのコードを読んでみる https://github.com/kubernetes/kubernetes/blob/2d3c76f9091b6bec110a5e63777c332469e0cba2/pkg/scheduler/core/generic_scheduler.go#L184

  48. findNodesThatFit() : perdicate判定 Predicate Rule #1 Predicate Rule #2 Predicate

    Rule #3 ✓ ✓ ✓ • findNodesThatFit() 及び podFitsOnNode() により 各ノードに対しpredicateルールに基づいたチェックが実行される。 • Nodeが全てのpredicateに適合する場合のみ、 ノードが filtered に追加され、次のprioritizeステージに進む filtered failedPredicateMap 全てのルールに適合? Yes No
  49. PrioritizeNodes : prioritize判定 • predicates判定を全てクリアしたノードは、次にprioritizeルールにより点数評価をされる ルール名 条件の合否 重み スコア ルール#1

    0 (不合格) 1 0 ルール#2 1 (合格) 2 2 ルール#3 1 (合格) 1 1 ルール#4 0 (不合格) 0 0 ルール#5 1 (合格) 3 3 合計点 6 ← のようなイメージで ノード毎の総合得点が採点される
  50. /pkg /cmd 以上の処理の流れをまとめると.. main() *エントリーポイント ↓ cobra.Command.Execute() ↓ cobra.Command.Run() ↓

    runCommand() ↓ Run ↓ func (sched *Scheduler) Run() ↓ (wait.Until) ↓ func (sched *Scheduler) scheduleOne() ※メインルーチン ↓ func (sched *Scheduler) schedule() ↓ func (g *genericScheduler) Schedule() ※実際のPredicate/Prioritize処理
  51. 構造体関係の情報をまとめると.. struct Scheduler struct Config Algorithm: algo struct genericScheduler func

    (g *genericScheduler) Schedule(pod *v1.Pod, nodeLister algorithm.NodeLister) (result ScheduleResult, err error) ポインタ レシーバ func (sched *Scheduler) Run() func (sched *Scheduler) scheduleOne() func (sched *Scheduler) schedule() ポインタ レシーバ call call call ・実際のスケジューリングを行うメソッド
  52. daemonの実装など、ソースコードを ガッツリ読むときのコツ

  53. よく出てくるパターン struct Config Hoge M ( int型 ) struct Hoge

    N ( int型 ) ① Daemonを生成するために必要な変数や関数を Config として構造体にまとめる ② それをDaemon生成用の関数(例:newDaemon())に引数として渡し、 Daemonを表すインスタンス(構造体)を初期化/生成 struct Config Hoge M ( int型 ) Hoge N ( int型 ) struct Daemon Config ③ Daemonを表すインスタンス(構造体)に付属のRun()メソッドを実行し、Linux上でProcessを起動 例: Daemon.Run()
  54. 関数を読む際 関数を読むときは、caller側とcallee側両方確認して、頭の中でマージする 呼び出し側(caller) 呼ばれている側(callee) sched に何が代入されるのかは、 callee側にて、戻り値を確認しな いとわからない 引数に渡される実際の値は、 呼び出し元を見ないとわからない

    (左) https://github.com/kubernetes/kubernetes/blob/2d3c76f9091b6bec110a5e63777c332469e0cba2/cmd/kube-scheduler/app/server.go#L159 (右) https://github.com/kubernetes/kubernetes/blob/2d3c76f9091b6bec110a5e63777c332469e0cba2/pkg/scheduler/scheduler.go#L121
  55. 複数の構造をイメージしながら読む 処理の流れ 構造体とメソッド main() ↓ cobra.Command.Execute() ↓ cobra.Command.Run() ↓ runCommand()

    ↓ Run ↓ func (sched *Scheduler) Run() ↓ (wait.Until) ↓ func (sched *Scheduler) scheduleOne() ↓ func (sched *Scheduler) schedule() ↓ func (g *genericScheduler) Schedule() struct Scheduler Algorithm: algo func (sched *Scheduler) Run() func (sched *Scheduler) scheduleOne() func (sched *Scheduler) schedule() ポインタ レシーバ call call struct Config
  56. その他TIPS これは、構造体.メソッド or パッケージ名.メソッドどっち? ※この場合は、optionsが未定義& NewSchedulerCommad()の引数にも 存在しないので、わかりやすいが、 関数が長くなると混乱しがち.. SourceGraphで確認すると、頭を使わずに答えが得られる

  57. kube-schedulerの処理を詳細に追いかけたい場合は、以下の記事がお勧めです! kube-schedulerのソースコードを読みながらPodがNodeにBindされるまでを理解する https://qiita.com/everpeace/items/601dc613a0f424fb5619 The Kubernetes Scheduler https://medium.com/@dominik.tornow/the-kubernetes-scheduler-cd429abac02f

  58. アジェンダ 前半: k8sのソースコード入門 - ソースコードを読むと幸せになれますか? - レポジトリの紹介とゆるふわに入門するためのTIPS 後半: k8sぷちDeepdive -

    kube-schedulerを読もうとしてみる - CustomControllerを題材に学ぶ、k8sのイベント通知
  59. Controllerとは何か? • kube-controller-managerにより起動される、各controllerは以下の機能を持つ (1) 管轄するAPIオブジェクト(Resource)の変更有無をWatchする (2) APIオブジェクト(Resource)に作成/更新/削除のイベントが発生したら、対応する処理を行う kube-apiserver controller watch

    作成/更新/削除を検知するたびに、 イベントハンドラに従い対応する処理を実行
  60. Controllerはイベントドリブンに動く • kube-controller-managerにより起動される、各controllerは以下の機能を持つ (1) 管轄するAPIオブジェクト(Resource)の変更有無をWatchする (2) APIオブジェクト(Resource)に作成/更新/削除のイベントが発生したら、対応する処理を行う kube-apiserver controller watch

    作成/更新/削除を検知するたびに、 イベントハンドラに従い対応する処理を実行
  61. custom controllerを構成する2つの実装 作成/更新/削除を検知するたびに、 イベントハンドラに従い対応する処理を実行 kube-apiserver custom controller watch ②APIオブジェクト の変更イベントが

    通知される方法 client set ①各種controllerが apiserverと通信を 行う方法
  62. custom controllerを構成する2つの実装 作成/更新/削除を検知するたびに、イベ ントハンドラに従い対応する処理を実行 kube-apiserver custom controller watch ②APIオブジェクト の変更イベントが

    通知される方法 client set ①各種controllerが apiserverと通信を 行う方法
  63. • client-goにて定義のClientset構造体を利用することで、kube-apiserverにAPIリクエスト を送信することができるので、controller等APIサーバと通信するdaemonを実装する際はこれを利用する APIサーバとの通信の実装方法 https://github.com/kubernetes/client-go/blob/637fc595d17acea6ce5f5b894b0a3ab301bf674e/kubernetes/clientset.go#L105 corev1 = apiVersion: v1 に相当する

    ※httpsエンドポイントとしては、/api/v1 ※API の階層構造については kubernetes.io の Kubernetes API Conceptsを 参照 https://bit.ly/2Z8mpxS
  64. • Clienset構造体は各APIオブジェクトに対応の構造体をメンバに持つ。 構造体に付属のメソッドを実行することで、RESTClientをメンバに持つ構造体が得られる (1) “apiVersion: v1” 用の構造体 (2) “kind: Nodes”

    用のメソッド Clientset構造体 (3) メソッドを実行すると、restClientをメンバ に持つnodes構造体が生成される [1] [1] c.restClientの中身はRESTClient構造体。 NewForConfigによりClientset生成時に、 RESTClientFor()-> NewRESTClient() により生成される https://github.com/kubernetes/client-go/blob/a240a565b073d748b78933afa3ea43fc922367b3/rest/client.go#L119-L127
  65. Client set構造体 • 前頁で得られた構造体に付属のメソッドを実行する事で、APIオブジェクトに対し 各種操作(Verb)が実行できる ←で、前ページで登場のRESTClient構造体が使われる 各種操作

  66. ※見やすくするために、各種エラーハンドラはばっさり削除しています ※コード全文は以下 https://gist.github.com/shinmatsuzaki/17f6ac8bb905a8e377d24f04d8e0cb7c 実際の実装例 / sample code kind: node のオブジェクトを

    全て取得 各オブジェクトに付属の メソッドを使って名前を表示
  67. 実行結果 • これを動かすと、Nodeの一覧が取得出力されます

  68. $HOME 配下の kubecofngを 元にconfigを生成 1. ~/.kube/config を元に Config構造体 を生成 NewForConfig()

    でclientset構造体 を生成 CoreV1().Nodes(). List()でAPIオブジェ クトを取得 -> GetName() メソッドで名前を 取得 参考: BuildConfigFromFlags() https://github.com/kubernetes/client-go/blob/a240a565b073d748b78933afa3ea43fc922367b3/tools/clientcmd/client_config.go#L539 ★
  69. $HOME 配下の kubecofngを 元にconfigを生成 2. Config構造体を元にClientset構造体を作る NewForConfig() でclientset構造体 を生成 CoreV1().Nodes().

    List()でAPIオブジェ クトを取得 -> GetName() メソッドで名前を 取得 参考: NewForConfig() https://github.com/kubernetes/client-go/blob/a240a565b073d748b78933afa3ea43fc922367b3/kubernetes/clientset.go#L346 ★
  70. $HOME 配下の kubecofngを 元にconfigを生成 3. Clientのメソッド経由でAPI情報を取得 NewForConfig() でclientsetを 生成 CoreV1().Nodes().

    List()でAPIオブジェ クトを取得 -> GetName() メソッドで名前を 取得 CoreV1上のKind: Nodeオブジェクトを全て取得 取得したAPIオブジェクトに具備の メソッドを実行し名前を取得
  71. custom controllerを構成する2つの実装 kube-apiserver custom controller watch 作成/更新/削除を検知するたびに、イベ ントハンドラに従い対応する処理を実行 ①各種controllerが apiserverと通信を

    行う方法 ②APIオブジェクト の変更イベントが 通知される方法 client set
  72. informer framework • k8sの各controllerは、APIオブジェクトに対する変更を watch と呼ばれる機能で監視し、 イベントが検知されると、イベントハンドラに従い処理を行う • イベント情報を流通させるパイプラインは、informer framework

    と呼ばれており、 client-goライブラリにより実装されている 画像の出展 https://github.com/kubernetes/sample-controller/blob/master/docs/controller-client-go.md APIオブジェクト 変更イベントの データフロー celint-goにて、 実装が提供されている 部分 個別の実装が必要な 部分 ※workqueue除く
  73. kube-apiserver CustomController

  74. ①Reflectorと呼ばれる機能が、 定期的にkube-apiserverに アクセスし、APIオブジェクトの変 更をチェックする 変更 イベント

  75. ②APIオブジェクトの変更が 検知されると、reflectorは DeltfaFIFO queueと 呼ばれるFIFO queueに 変更イベントをenqueueする 変更 イベント

  76. - string - Deltas - string - Deltas - string

    - Deltas - string - Deltas enqueue enqueue type Deltas []Delta Type Object DeltaFIFO.items Delta FIFO Queueの上は何が流れている? https://github.com/kubernetes/client-go/blob/master/tools/cache/delta_fifo.go Delta.Typeは、 DeltaType型(=string) 型であり、addition, deletion, etc が入る • k8sのAPIオブジェクトは、Delta FIFO と呼ばれるQueueを通じて流通される(※注1) • Delta = APIオブジェクトの変更イベントを指す • キュー内部にDeltas というスライスが用意されており、1つのキューで複数のイベント情報を流通できる Type Object Type Object 注1:実際は、struct DeltaFIFO のメンバのitemsというmapに格納される interface{} 型、 実際のAPIオブジェク トの情報が格納される
  77. ⑤Informerはdequeueした イベントをObjectのStateという形 式でcache storeに保存する。 この際、Indexerがインデックスを 付与する ③Informerと呼ばれる機能は DeltaFIFO Queueをsubscribeして おり、Refrectorがenqueueすると

    反対側でdequeue(Pop())する 変更 イベント ④Informerはdequeue(Pop())の 結果得られたオブジェクトを Indexerに渡す
  78. ⑥Informer側に、任意のCallBack 関数をイベントハンドラして登録す ると、イベントがDeltaFifoQueue からdequeueされる度に発火をさせ ることができる。 変更 イベント ※イベントハンドラのイメージ ⑦これを利用して、APIオブジェク トからkeyを抽出し、「APIの変更

    イベント」としてControllerが持つ 別のQueue(WorkQueue)への enqueueを行う。 ↑ APIオブジェクトから、 <namespace>/<object name> 形式のkeyを生成する ↑ workqueueにpush <namespace> / <object name> 形式
  79. ⑧Custom controllerの メインルーチーンは、 controller専用のQueueから イベントを取り出し、 処理を行う ※Pop() ⑨APIオブジェクトのStateの取得が 必要な場合、Indexer に対しkeyを使ってオブジェクトの

    取得要求を発行 変更 イベント <namespace> / <object name> 形式
  80. これらを組み合わせるとcustom controllerができる kube-apiserver custom controller watch 作成/更新/削除を検知するたびに、イベ ントハンドラに従い対応する処理を実行 ①各種controllerが apiserverと通信を

    行う方法 ②APIオブジェクト の変更イベントが 通知される方法 client set
  81. Workqueue example(pod event notifier) 以下に少し改造したコードを載せています https://gist.github.com/shinmatsuzaki/4b2b10fefb1f9fa18e18be109ee32784 • client-goのレポジトリにて提供されているリファレンス実装 https://github.com/kubernetes/client-go/blob/master/examples/workqueue/main.go •

    CRDは使わず、単にpodの何らかのevent(Sync/Add/Update)が発生したことのみを通知 • sig-api-machinery にて策定のcontrollerのデザインのサンプル実装でもある https://github.com/kubernetes/community/blob/master/contributors/devel/sig-api-machinery/controllers.md • 1 File, 約200行のみで動く! ⇒ 学習に最適
  82. main() の処理の流れ(1) • BuildConfigFromFlags() により、kubeconfigをインプットにConfig構造体を生成 • Config構造体をNewForConfig() の引数に渡し、Clientset構造体を生成 • 後段で生成されるreflectorが、kube-apiserverからAPIオブジェクトを取得するための関数を、

    ListWatch構造体として生成 • Controller用のWorkqueueを生成 ListWatch Clientset workqueue
  83. main() の処理の流れ(2) • indexerは、CacheStoreとkey funcを持つ cache構造体 として生成される https://github.com/kubernetes/client-go/blob/a240a565b073d748b78933afa3ea43fc922367b3///tools/cache/store.go#L239-L244 • informerは、reflectorをメンバに持つ、controller構造体として生成される。

    この際に、DeltaFIFOも併せて生成される https://github.com/kubernetes/client-go/blob/a240a565b073d748b78933afa3ea43fc922367b3///tools/cache/controller.go#L75-L126 https://github.com/kubernetes/client-go/blob/a240a565b073d748b78933afa3ea43fc922367b3///tools/cache/controller.go#L345 informer indexer DeltaFIFO
  84. main() の処理の流れ(3) ① workqueue, indexer, informer をNewController() に渡し、ControllerをController構造体として生成 ② Controllerをworkerスレッド数=1で、起動

    ① ②
  85. Run以降の処理(1) ① informer / reflectorを起動 ② 1秒毎に run.Worker() を実行し続ける ①

    ② reflector informer
  86. Run以降の処理(2) ① ② ① workqueueからkeyをpop ② 実際のビジネスロジックを実装するメソッドに key を渡す

  87. Run以降の処理(3) ① ② ① keyをキーにして、indexerからキャッシュされたAPIオブジェクトを取得 ② APIオブジェクトの GetName() メソッドを実行し、オブジェクト名を出力 podのAPIオブ

    ジェクトを fetch
  88. 以上を全て実装すると... • Podの更新系のイベントがCustomControllerに流入する用になります GetName()の結果得られた APIオブジェクト(Pod)の名前

  89. Workqueue example(pod event notifier) 以下に少し改造したコードを載せています https://gist.github.com/shinmatsuzaki/4b2b10fefb1f9fa18e18be109ee32784 • client-goのレポジトリにて提供されているリファレンス実装 https://github.com/kubernetes/client-go/blob/master/examples/workqueue/main.go •

    CRDは使わず、単にpodのevent(Sync/Add/Update)のみを通知 • sig-api-machinery にて策定のcontrollerのデザインのサンプル実装でもある https://github.com/kubernetes/community/blob/master/contributors/devel/sig-api-machinery/controllers.md • 1 File, 約200行のみで動く! ⇒ 学習に最適
  90. 参考:k8sの標準のControllerのArchitecture 出展:https://www.slideshare.net/harryzhang735/kubernetes-beyond-a-black-box-part-1 P28 Reflector ThreadSafeStore EventHandler 各Controllerが 持つ独自の WorkQueue shared

    infromerは、 各APIリソースの変更を検知するた めのkube-controller-managerによ り起動される共用Infomer, 複数のControllerで別個にinformer を持つことが無駄のだめ、共用I/F として提供されている
  91. kube-schedulerも同様の仕組みを採用している pop() event handler informer Delta FIFO Scheduling Queue *

    1 スケジューリング処理 • informerでpodをwatch ⇒ add eventが発生の場合のみ、Pod Queueにenqueueし、schedulingを実行 pop() Shedulerのメインルーチン =無限ループ *1 pod priorityが有効な場合は、 PriorityQueue
  92. 参考書籍 • Operator Patternを主題にした本 • Chapter 3 Basics of clien-go

    にて、後半で解説の Client-go, Clientset, Informer等の解説がされています。
  93. 宣伝 • Rancherのスゴ本!

  94. ご清聴ありがとうございました