SlideShare a Scribd company logo
Shingo Omura (@everpeace), Preferred Networks, Inc.
Kubernetes Meetup Tokyo #18 2019-04-22
Kubebuilder/controller-runtime入門
大村伸吾 (おおむらしんご)
• エンジニア, Preferred Networks, Inc.
• 社内向けGPUクラスタの開発運用
• kubeflow contributor
• everpeace/kube-throttler
– scheduler extender として 動作
実行中Podの利用リソース量をthrottle
• @everpeace
2
We’re Hiring!!
• CRD ベース の controller を作るためのフレームワーク
• kubebuilder 単体は コードテンプレ/manifest 群を生成してくれるCLIツール
• book.kubebuilder.io がとても良く書かれていてるのでちゃんと読み進めれば
特に詰まることなく使えます
Kubebulider (v1.0.8が最新) kubernetes-sigs/kubebuilder
Kubebuilder
Icons made by Icongeek26 from www.flaticon.com is licensed by CC 3.0 BY
*.go *.yaml
controller-runtime
controller-tools
● CRD, controller(deploy用), controller用のRBAC用
manifest を生成してくれる
● //+ annotation による冪等 な manifest 生成が可能
● controller-manager, controller, webhook 用のコード生成(テスト有)
− controller 部分 は CRD 単位で後から追加できる
● controllerを書くには結局controller-runtimeを勉強する必要がある
● kubebuilderアップグレード時に依存(vendor) 管理もしてくれる
生成
生成
依存
3
Kubebuilder の作る Project の 構造
cmd/…,docs/…,Makefile,Dockerfile
pkg/apis/.../*_types.go,*_types_test.go
pkg/controllers/.../*-controller.go,*-controller_test.go
config/{crds,rbac,rbac_proxy,manager,default,sample}/*.yaml
Icons made by Icongeek26 from www.flaticon.com is licensed by CC 3.0 BY
− API resource の定義. kind毎に生成される
− 生成されるテンプレートを元に定義したい spec, status とそのテストを書く
その他もろもろ
− Controller の実装. kind毎に生成される
− 生成されるテンプレートを元に controller-runtime を使って実装/テストを書く
− 各種 manifest ファイル, kustomize の app が生成される
− ソースに書いたアノテーションを元に controller-tools が生成してくれる
最初大変
4
Kubebuilder の 嬉しみ と 辛み
Icons made by Roundicons from www.flaticon.com is licensed by CC 3.0 BY
● 使い始めるのが簡単
● コピペしなくて済む (大事!)
● kubebuilder/make による標準的な開発
フローにで toil を最小化
○ kubebuilder create api
○ make manifests/test/install/deploy
● 標準的な Controller 実装 に乗れるので
コアロジック(Reconcileループ)に集中
● controller-runtimeによる抽象度の高い
ライブラリが使える
● controller の integration test もついてくる
● code 生成は 初回生成のみを想定
○ 書換NGな場所をfencingしてくれている訳じゃ
ないので基本 1 度生成したらおしまい
● CRD の Webhook Conversion は未対応
なので理解して使うべき (#275)
● probe のサポートがない (#297)
● Admission系が大規模にrefactoringされて
いるのでもし使うなら将来影響あり
● controller-runtime は godoc くらいしかな
いので 学習コストがそこそこある
5
controller-runtime 入門
実際にController 書く時に
理解しておいたほうが良い
ことを解説していきます!
controller-runtime(v0.1.10が最新) kubernetes-sigs/controller-runtime
• Kubebuilderのサブプロジェクトとして開発されている
• Kubebuilder v1.0.8 は controller-runtime v0.1.1 に依存 (古め)
– 最新版にupdateするPR (kubebuilder#657) はある
cache by SBTS from the Noun Project
Icons made by Vincent Le Moign from https://icon-icons.com/ licensed by CC 3.0 BY
Icons made by Gregor Cresnar, Pause08, Freepik, Those Icons, Monkik from www.flaticon.com is licensed by CC 3.0 BY
Controller
Admission
Webhook
envtest metrics
その他
client, cache, logging,
leader election (resource lock)
Manager
controller-runtimeの主な機能
: 本日は時間都合で省略する部分
7
Manager (a.k.a controller manager)
• Runnable の lifecycle管理 (Add / Start)
– Manager 経由で Start しないと
ダメなので注意!! (共通依存の処理が色々必要)
• 共通依存を保持: client, cache, scheme 等
– getterが提供されている(GetClient()とか)
– 簡易DIの仕組みもある(runtime/inject)
• Leader Election にも対応
– optionで指定するだけでOK (default false)
• Graceful shutdown用のsignal handlerも完備
Controller
Admission
Webhook
Manager
Runnable
*
依存を注入
8
runtime/inject による依存の注入
• 特定のinterfaceを実装しておくとmanagerへの追加時/controller生成時
に注入してくれる
package runtime/inject
// 下記の依存に対応
type Cache interface { InjectCache(cache cache.Cache) error }
type Client interface { InjectClient(client.Client) error }
type Decoder interface { InjectDecoder(types.Decoder) error }
type Scheme interface { InjectScheme(scheme *runtime.Scheme) error }
type Stoppable interface { InjectStopChannel(<-chan struct{}) error } // graceful shutdown用
type Injector interface { InjectFunc(f Func) error } // injector そのもの
type Logger interface { InjectLogger(l logr.Logger) error } // v0.1.1には無い
// 利用例
type myReconciler struct { client.Client }
func (*r myReconciler) InjectClient(c client.Client) error { r.Client = c }
9
Manager の 作り方
import "sigs.k8s.io/controller-runtime/pkg/manager"
import "sigs.k8s.io/controller-runtime/pkg/client/config"
import "sigs.k8s.io/controller-runtime/pkg/runtime/signals" // v0.1.10ではmanager/signals
mgr := manager.New( // manager.New で作る
config.GetConfigOrDie(), // --kubecongig, KUBECONFIG, incluster, .kube/config 探して自動で読込
manager.Options{}, // Manager初期化用オプション(LeaderElection, SyncPeriod 色々設定可)
)
mgr.Add(controller) // controllerを追加. 初期化方法は後述.
mgr.Start(signals.SetupSignalHandler()) // signal handling 用の channel を渡して起動
注: kubebuilderを使う限りはこの辺はあまり触らなくても大丈夫なはず
10
controller.New(name, controller.Option{ Reconciler, MaxConcurrentReconciles })
Controller (controller-runtimeにおけるcontrollerのアーキテクチャ)
controller.Watch()
Source Predicate EventHandler
controller.Watch()
Source Predicate EventHandler
controller.Watch()
Source Predicate EventHandler
workqueue with RateLimiting
...
reconcile.Request
Reconciler
Reconciler
Reconciler
Reconciler
reconcile.Result
(resultで指定されていたら)
delay付きでrequeue
並列数は
MaxConcurrentReconciles
で指定できる(default = 1)
• 構造的にはこれまでのベストプラクティスと同じ
• Watch部分, Reconciler 部分が綺麗に整理されている
11
controller.Watch(source, predicates, eventEandler)
Source Predicate EventHandler
Watchの基本構造
package controller
type Controller interface {
// Sourceから流れてくる event を predicateでfilter して
// handlerで reconcile.Request(複数可) に変換して workqueue に enqueue
Watch(source.Source, handler.EventHandler, ...predicate.Predicate) error
}
CreateEvent
UpdateEvent
DeleteEvent
GenericEvent
CreateEvent
UpdateEvent
DeleteEvent
GenericEvent reconcile.Request
12
Source は 4 種類
package source
type Source interface {
// Sourceは predicateとEventHandlerとqueueを渡すと開始できる
// controller.Watch() は内部でこれを呼んで Watch を開始する
Start(handler.EventHandler, workqueue.RateLimitingInterface, ...predicate.Predicate) error
}
Source
Kind
Channel
Informer
Func
Kubernetes Resource用: &source.Kind{ Type: &corev1.Pod{} }
外部event用: &source.Channel{ Source: make(chan GenericEvent) }
Informer直接: &source.Informer{ Informer: sharedIndexInformer }
Func直接: interfaceと同じsignatureの関数はSourceとして振る舞える
13
Predicate
package predicate
// 各EventType毎 に EventHandler に渡すかどうかを決める
type Predicate interface {
Create( event.CreateEvent) bool
Delete( event.DeleteEvent) bool
Update( event.UpdateEvent) bool
Generic(event.GenericEvent) bool // Channel用
}
Predicate
Func
ResourceVersionChangedPredicate
カスタムしたい関数だけ渡して Predicateを生成
(登録していない関数は _ => true になる)
UpdateEvent: Old!=nil && New!=nil で ResourceVersion が異なる時のみ true
それ以外 : true
14
EventHandler
package reconcile
type Request struct { types.NamespaecedName } // Namespace, Nameしか入れられないことに注意 !
package handler
// 各EventType毎 に reconcile.Request(複数可) に変換して workqueue に enqueue する
type EventHandler interface {
Create( event.CreateEvent, workqueue.RateLimitingInterface)
Update( event.UpdateEvent, workqueue.RateLimitingInterface)
Delete( event.DeleteEvent, workqueue.RateLimitingInterface)
Generic(event.GenericEvent, workqueue.RateLimitingInterface) // Channel用 }
Event
Handler
Func
EnqueueRequestForObject
必要な関数だけを渡して EventHandler を生成
Event に入っている NamespacedName に変換
EnqueueRequestForOwner OwnerReferences に入っている NamespacedNames に変換
EnqueueRequestsFromMapFunc Mapper{ Map(MapObject) []reconcile.Request } で変換
15
Watchの例
ctr := controller.New(...)
// MyKind を watch してそのNamespace/Name を reconcile.Request に
ctr.Watch(
&source.Kind{Type: &myKind{}},
&handler.EnqueueRequestForObject{},
)
// MyKind を Owner にもつ Pod を Watch して変化があれば、
// Owner である MyKind の Namespace/Name を reconcile.Request に
ctr.Watch(
&source.Kind{ Type: corev1.Pod{} },
&handler.EnqueueRequestForOwner{ OwnerType: &myKind{}, IsController: true },
)
16
Reconciler (Reconcileループ本体)
package reconcile
// 本丸。基本これを作る。
// controller 内で MaxConcurrentReconciles 個分の reconcile ループが回る
type Reconciler interface { Reconcile(Request) (Result, error) }
// Request は Namespace, Name しか入れられない
// → Reconciler は特定の Kind の reconcile を責務とするように設計されている
type Request struct { types.NamespaecedName }
// Requestを再処理したい時(API erorr, race condition, preodic)とかに requeue with delay を要求可
// 成功時は reconcile.Result{} で OK
type Result struct { Requeue bool, RequeueAfter time.Duration }
17
Controller の 作り方
type MyKindReconciler struct { client.Client /* その他自分のほしい依存 */ }
func (r *MyKindReconciler) InjectClient(c client.Client) error { r.Client = c }
func (r *MyKindReconciler) Reconcile(o reconcile.Request) (reconcile.Result, error) {
return reconcile.Result{}, nil
}
// reconciler を渡して controller インスタンスを作る
myreconciler := &MyKindRecociler{ }
ctr := controller.New( "MyKindController" , controller.Option{
Reconciler: myreconciler, MaxConcurrentReconciles: 1,
})
// Watchを設定(省略)してmanagerにcontrollerを追加
mgr.Add(ctr)
18
Controller の 作り方 (builderもある)
import "sigs.k8s.io/controller-runtime/pkg/builder"
builder.
ControllerManagedBy(mgr). // この Manager に Add する
For(&MyKind{}). // MyKind用のcontroller (自動watch)
Owns(&corev1.Pod{}). // MyKindはPodをOwnする (自動watch)
Complete(&myreconciler{}) // reconcilerを渡してcontrollerを作成してmanagerに登録
// 他にも色々なメソッドがある
// builder.Watches(...): カスタム Watch
// builder.WithEventFilter(...): 全体に適用する predicates
// builder.Build(...): 登録せずに controller を返す
19
Reconcile ループでよく使うもの (controllerutil)
package controller/controllerutil
// object に owner を OwnerReference (isController: true) で セットする
// これをつけると Watchの時に EnqueueRequestForOwner で親Resourceのreconcile.Requstにできる
// 何らかの事故で子リソースが orphanedになるとkubernetesのgarbage collection対象になる
func SetControllerReference(owner, object v1.Object, scheme *runtime.Scheme) error
// CreateOrUpdate そのまま 存在する時の Update は 関数で渡す
// OperationResultNone OperationResult = "unchanged"
// OperationResultCreated OperationResult = "created"
// OperationResultUpdated OperationResult = "updated"
func CreateOrUpdate(
ctx context.Context, c client.Client, obj runtime.Object, f MutateFn
) (OperationResult, error)
20
Reconcile ループでよく使うもの (client)
package client
// reflection を使って obj の型を検出してapiを呼んでくれる. types.NamespacedNameをkeyとして使う
type ObjectKey = types.NamespacedName
// Client 3 種類 の interface に分離されている
type Client interface { Reader, Writer, StatusClient }
type Reader interface {
// key,obj を渡して obj が update される. obj struct pointer (例:&Pod{}) でないとダメ.
Get(ctx context.Context, key ObjectKey, obj runtime.Object) error
List(ctx context.Context, list runtime.Object, opts ...ListOptionFunc) error
}
type Writer interface {
Create(ctx context.Context, obj runtime.Object) error
Delete(ctx context.Context, obj runtime.Object, opts ...DeleteOptionFunc) error
Update(ctx context.Context, obj runtime.Object) error
}
type StatusClient interface { Status() StatusWriter }
// status subresource のみを update
type StatusWriter interface { Update(ctx context.Context, obj runtime.Object) error }
21
例を見てみましょう kubernetes-sigs/controller-runtime/examples/crd
// 同じ namespace/name が居なければ Pod を作る(status.lastRunもセット)
// 時刻がnextStopを超えたらPodを止めて再度作る
kind: ChaosPod
spec:
template: // pod template
nextStop: "2019-04-01T01:00:10Z000:00"
status:
lastRun: "2019-04-00T01:00:00Z00:00"
Reconciler loop実装:
kubernetes-sigs/controller-runtime/examples/crd/main.go#L40
Manager/Controller初期化:
kubernetes-sigs/controller-runtime/examples/crd/main.go#L108-L138
22
Metrics
// controller, admission webhook のメトリクスは自動で取られるようになっているので
// manager.Options に MetricsBindAddress をセットするだけでよい
// Kubebuilderでは自動で入ります
manager.New(... , manager.Options{
MetricsBindAddress: ":8080", // http://localhost:8080/metrics
…,
}
• 取れるメトリクス
– controller: reconcilation error, reconcilation queue length, reconcile latency
– webhook: total requests, latency
– system metrics, client-go metrics
• Kubebuiler の生成する manifest だと metrics endpoint は rbac-proxy で保護されている
ので注意
– prometheus SA に 'GET /metrics' が RBAC で許可必要(基本許可されていると思う )
23
envtest - test 用の controll plane(api-server, etcd) Start/Stop
import "sigs.k8s.io/controller-runtime/pkg/envtest"
te := &envtest.Environment{
CRDDirectoryPaths : []string{filepath.Join("..", "config", "crd" },
UseExistingCluster: false, // 既存クラスタも利用可
ControlPlaneStartTimeout: 20 * time.Seconds, // (default 20sec), 環境変数でも設定可
ControlPlaneStopTimeout : 20 * time.Seconds,
KubeAPIServerFlags: []string{}, // api server flags もセット可能
}
// KUBEBUILDER_ASSETS(defualt=/usr/local/kubebuilder/bin) のバイナリを使って
// api-server, etcd を起動して CRD をinstall して rest.Config を返してくれる
config, err := te.Start()
注: kubebuilderを使う限りはこの辺は生成してくれます
24
// SetupTestReconcile() で probe 可能な channel 付きの reconciler を作ってくれる
recFn, requests := SetupTestReconcile(newReconciler(mgr))
g.Expect(add(mgr, recFn)).Should(gomega.Succeed())
stopMgr, mgrStopped := StartTestManager(mgr, g)
// myKind を作れて
g.Expect(c.Create(context.TODO(), myKind)).Should(gomega.Succeed())
// するとそれに対する reconcile.Request を受け取って
// ハマリポイント: 作られる probe channel の capacity が 0 なので、すべて Receive してあげないと先に進まないので注意!!
g.Eventually(requests).Should(gomega.Receive(gomega.Equal(expectedReconcileRequest)))
// そのうち pod が出来る
g.Eventually(func() error {
return c.Get(context.TODO(), podNamespacedName, expectedPod)
}).Should(gomega.Succeed())
envtest をつかったテスト例 (Kubebuilderの場合)
25
Controller を 作る際 の Tips
● 大切: Reconcile Loop は 常に 滑らかに早く 回しましょう
● 理由: 複数 resource の reconcile を担うので block するとすぐ応答が悪くなります
● Tips:
- Reconcile Loop は 小さくつくりましょう
O(N) の loop を 1 回 ( N 個のリソースを更新 )
O(1) の loop を N 回 ( 1 個のリソースを更新 )
- State 遷移は モデル化 しておきましょう
- ありとあらゆる状態を想定すると良いです
- 分散システムでは「こういう状態にはならないはず」という前提を安易に設けるのは危険
- 不要な reconcile を避けましょう (event は multiplexing しましょう)
- 100個の子Podが短時間死んでも1 回 reconcile を kick すれば済むはず
- 親 resource を指す reconcile.Request に変換している限りworkqueueが
rate limiting & dedupしてくれるのでcontroller-runtimeを使いましょう
Icons made by Roundicons from www.flaticon.com is licensed by CC 3.0 BY
26
PFNでは効率的で柔軟な機械学習クラスタの構築
を一緒に挑戦してみたい人を募集しています
https://www.preferred-networks.jp/ja/jobs/engineer
(該当職種: Infrastructure (Software) , Middleware for ML Cluster )
We’re Hiring!!
27
Icons made by Vincent Le Moign from https://icon-icons.com/ licensed by CC 3.0 BY
Thank you for Listening!!
Any Questions?

More Related Content

PDF
ストリーム処理を支えるキューイングシステムの選び方
PDF
ヤフー社内でやってるMySQLチューニングセミナー大公開
PDF
Docker Compose 徹底解説
PDF
Linux女子部 systemd徹底入門
PDF
オンプレML基盤on Kubernetes 〜Yahoo! JAPAN AIPF〜
PPTX
BuildKitによる高速でセキュアなイメージビルド
PDF
Docker入門-基礎編 いまから始めるDocker管理【2nd Edition】
PDF
Kubernetes ControllerをScale-Outさせる方法 / Kubernetes Meetup Tokyo #55
ストリーム処理を支えるキューイングシステムの選び方
ヤフー社内でやってるMySQLチューニングセミナー大公開
Docker Compose 徹底解説
Linux女子部 systemd徹底入門
オンプレML基盤on Kubernetes 〜Yahoo! JAPAN AIPF〜
BuildKitによる高速でセキュアなイメージビルド
Docker入門-基礎編 いまから始めるDocker管理【2nd Edition】
Kubernetes ControllerをScale-Outさせる方法 / Kubernetes Meetup Tokyo #55

What's hot (20)

PDF
マイクロサービス 4つの分割アプローチ
PDF
わかる!metadata.managedFields / Kubernetes Meetup Tokyo 48
PPTX
え、まって。その並列分散処理、Kafkaのしくみでもできるの? Apache Kafkaの機能を利用した大規模ストリームデータの並列分散処理
PDF
Apache Airflow 概要(Airflowの基礎を学ぶハンズオンワークショップ 発表資料)
PDF
BuildKitの概要と最近の機能
PDF
Consistent hash
PPTX
Kubernetesでの性能解析 ~なんとなく遅いからの脱却~(Kubernetes Meetup Tokyo #33 発表資料)
PDF
PFNのML/DL基盤を支えるKubernetesにおける自動化 / DevOpsDays Tokyo 2021
PDF
実運用して分かったRabbit MQの良いところ・気をつけること #jjug
PPTX
Apache BigtopによるHadoopエコシステムのパッケージング(Open Source Conference 2021 Online/Osaka...
PDF
GPU仮想化最前線 - KVMGTとvirtio-gpu -
PDF
DockerとPodmanの比較
PDF
例外設計における大罪
PDF
SQLアンチパターン 幻の第26章「とりあえず削除フラグ」
PDF
WebAssemblyのWeb以外のことぜんぶ話す
PDF
Google Cloud Game Servers 徹底入門 | 第 10 回 Google Cloud INSIDE Games & Apps Online
PPTX
DockerコンテナでGitを使う
PDF
Dockerからcontainerdへの移行
PDF
Where狙いのキー、order by狙いのキー
PDF
DBスキーマもバージョン管理したい!
マイクロサービス 4つの分割アプローチ
わかる!metadata.managedFields / Kubernetes Meetup Tokyo 48
え、まって。その並列分散処理、Kafkaのしくみでもできるの? Apache Kafkaの機能を利用した大規模ストリームデータの並列分散処理
Apache Airflow 概要(Airflowの基礎を学ぶハンズオンワークショップ 発表資料)
BuildKitの概要と最近の機能
Consistent hash
Kubernetesでの性能解析 ~なんとなく遅いからの脱却~(Kubernetes Meetup Tokyo #33 発表資料)
PFNのML/DL基盤を支えるKubernetesにおける自動化 / DevOpsDays Tokyo 2021
実運用して分かったRabbit MQの良いところ・気をつけること #jjug
Apache BigtopによるHadoopエコシステムのパッケージング(Open Source Conference 2021 Online/Osaka...
GPU仮想化最前線 - KVMGTとvirtio-gpu -
DockerとPodmanの比較
例外設計における大罪
SQLアンチパターン 幻の第26章「とりあえず削除フラグ」
WebAssemblyのWeb以外のことぜんぶ話す
Google Cloud Game Servers 徹底入門 | 第 10 回 Google Cloud INSIDE Games & Apps Online
DockerコンテナでGitを使う
Dockerからcontainerdへの移行
Where狙いのキー、order by狙いのキー
DBスキーマもバージョン管理したい!
Ad

Similar to Kubernete Meetup Tokyo #18 - Kubebuilder/controller-runtime 入門 (20)

ODP
130329 04
ODP
20130329 rtm4
PPTX
Operator reading and writing ( Operator SDK 編 )
PDF
Kubernetes Operator for vSphere VM
PPTX
T93 com入門
PDF
Docker+CoreOS+GCEで自動スケール分散レイトレ
PPTX
WebRTC on Native App
PDF
Kubernetes meetup-tokyo-13-customizing-kubernetes-for-ml-cluster
PDF
The potential of Kubernetes as more than just an infrastructure to deploy
PDF
20220427-k8s-meetup-tokyo.pdf
PDF
Circle ci and docker+serverspec
PPTX
Docker超入門
PDF
Tekton 入門
PDF
AWSとGCPを使用したインフラ環境
PDF
VSCodeで始めるAzure Static Web Apps開発
PDF
Go 製リアルタイムサーバーの Kubernetes での運用について
PDF
CI/CD Pipeline を考える 〜KubeCon 2017 + CyberAgent の最大公倍数〜
PDF
Tottoruby 20110903
PDF
Container Storage Interface のすべて
PDF
Clrh 20140906 lt
130329 04
20130329 rtm4
Operator reading and writing ( Operator SDK 編 )
Kubernetes Operator for vSphere VM
T93 com入門
Docker+CoreOS+GCEで自動スケール分散レイトレ
WebRTC on Native App
Kubernetes meetup-tokyo-13-customizing-kubernetes-for-ml-cluster
The potential of Kubernetes as more than just an infrastructure to deploy
20220427-k8s-meetup-tokyo.pdf
Circle ci and docker+serverspec
Docker超入門
Tekton 入門
AWSとGCPを使用したインフラ環境
VSCodeで始めるAzure Static Web Apps開発
Go 製リアルタイムサーバーの Kubernetes での運用について
CI/CD Pipeline を考える 〜KubeCon 2017 + CyberAgent の最大公倍数〜
Tottoruby 20110903
Container Storage Interface のすべて
Clrh 20140906 lt
Ad

More from Preferred Networks (20)

PDF
PodSecurityPolicy からGatekeeper に移行しました / Kubernetes Meetup Tokyo #57
PDF
Optunaを使ったHuman-in-the-loop最適化の紹介 - 2023/04/27 W&B 東京ミートアップ #3
PDF
Kubernetes + containerd で cgroup v2 に移行したら "failed to create fsnotify watcher...
PDF
深層学習の新しい応用と、 それを支える計算機の進化 - Preferred Networks CEO 西川徹 (SEMICON Japan 2022 Ke...
PDF
Kaggle Happywhaleコンペ優勝解法でのOptuna使用事例 - 2022/12/10 Optuna Meetup #2
PDF
最新リリース:Optuna V3の全て - 2022/12/10 Optuna Meetup #2
PDF
Optuna Dashboardの紹介と設計解説 - 2022/12/10 Optuna Meetup #2
PDF
スタートアップが提案する2030年の材料開発 - 2022/11/11 QPARC講演
PPTX
Deep Learningのための専用プロセッサ「MN-Core」の開発と活用(2022/10/19東大大学院「 融合情報学特別講義Ⅲ」)
PPTX
PFNにおける研究開発(2022/10/19 東大大学院「融合情報学特別講義Ⅲ」)
PDF
自然言語処理を 役立てるのはなぜ難しいのか(2022/10/25東大大学院「自然言語処理応用」)
PDF
Kubernetes にこれから入るかもしれない注目機能!(2022年11月版) / TechFeed Experts Night #7 〜 コンテナ技術を語る
PDF
Matlantis™のニューラルネットワークポテンシャルPFPの適用範囲拡張
PDF
PFNのオンプレ計算機クラスタの取り組み_第55回情報科学若手の会
PDF
続・PFN のオンプレML基盤の取り組み / オンプレML基盤 on Kubernetes 〜PFN、ヤフー〜 #2
PDF
Kubernetes Service Account As Multi-Cloud Identity / Cloud Native Security Co...
PDF
KubeCon + CloudNativeCon Europe 2022 Recap / Kubernetes Meetup Tokyo #51 / #k...
PDF
KubeCon + CloudNativeCon Europe 2022 Recap - Batch/HPCの潮流とScheduler拡張事例 / Kub...
PDF
独断と偏見で選んだ Kubernetes 1.24 の注目機能と今後! / Kubernetes Meetup Tokyo 50
PDF
Topology Managerについて / Kubernetes Meetup Tokyo 50
PodSecurityPolicy からGatekeeper に移行しました / Kubernetes Meetup Tokyo #57
Optunaを使ったHuman-in-the-loop最適化の紹介 - 2023/04/27 W&B 東京ミートアップ #3
Kubernetes + containerd で cgroup v2 に移行したら "failed to create fsnotify watcher...
深層学習の新しい応用と、 それを支える計算機の進化 - Preferred Networks CEO 西川徹 (SEMICON Japan 2022 Ke...
Kaggle Happywhaleコンペ優勝解法でのOptuna使用事例 - 2022/12/10 Optuna Meetup #2
最新リリース:Optuna V3の全て - 2022/12/10 Optuna Meetup #2
Optuna Dashboardの紹介と設計解説 - 2022/12/10 Optuna Meetup #2
スタートアップが提案する2030年の材料開発 - 2022/11/11 QPARC講演
Deep Learningのための専用プロセッサ「MN-Core」の開発と活用(2022/10/19東大大学院「 融合情報学特別講義Ⅲ」)
PFNにおける研究開発(2022/10/19 東大大学院「融合情報学特別講義Ⅲ」)
自然言語処理を 役立てるのはなぜ難しいのか(2022/10/25東大大学院「自然言語処理応用」)
Kubernetes にこれから入るかもしれない注目機能!(2022年11月版) / TechFeed Experts Night #7 〜 コンテナ技術を語る
Matlantis™のニューラルネットワークポテンシャルPFPの適用範囲拡張
PFNのオンプレ計算機クラスタの取り組み_第55回情報科学若手の会
続・PFN のオンプレML基盤の取り組み / オンプレML基盤 on Kubernetes 〜PFN、ヤフー〜 #2
Kubernetes Service Account As Multi-Cloud Identity / Cloud Native Security Co...
KubeCon + CloudNativeCon Europe 2022 Recap / Kubernetes Meetup Tokyo #51 / #k...
KubeCon + CloudNativeCon Europe 2022 Recap - Batch/HPCの潮流とScheduler拡張事例 / Kub...
独断と偏見で選んだ Kubernetes 1.24 の注目機能と今後! / Kubernetes Meetup Tokyo 50
Topology Managerについて / Kubernetes Meetup Tokyo 50

Kubernete Meetup Tokyo #18 - Kubebuilder/controller-runtime 入門

  • 1. Shingo Omura (@everpeace), Preferred Networks, Inc. Kubernetes Meetup Tokyo #18 2019-04-22 Kubebuilder/controller-runtime入門
  • 2. 大村伸吾 (おおむらしんご) • エンジニア, Preferred Networks, Inc. • 社内向けGPUクラスタの開発運用 • kubeflow contributor • everpeace/kube-throttler – scheduler extender として 動作 実行中Podの利用リソース量をthrottle • @everpeace 2 We’re Hiring!!
  • 3. • CRD ベース の controller を作るためのフレームワーク • kubebuilder 単体は コードテンプレ/manifest 群を生成してくれるCLIツール • book.kubebuilder.io がとても良く書かれていてるのでちゃんと読み進めれば 特に詰まることなく使えます Kubebulider (v1.0.8が最新) kubernetes-sigs/kubebuilder Kubebuilder Icons made by Icongeek26 from www.flaticon.com is licensed by CC 3.0 BY *.go *.yaml controller-runtime controller-tools ● CRD, controller(deploy用), controller用のRBAC用 manifest を生成してくれる ● //+ annotation による冪等 な manifest 生成が可能 ● controller-manager, controller, webhook 用のコード生成(テスト有) − controller 部分 は CRD 単位で後から追加できる ● controllerを書くには結局controller-runtimeを勉強する必要がある ● kubebuilderアップグレード時に依存(vendor) 管理もしてくれる 生成 生成 依存 3
  • 4. Kubebuilder の作る Project の 構造 cmd/…,docs/…,Makefile,Dockerfile pkg/apis/.../*_types.go,*_types_test.go pkg/controllers/.../*-controller.go,*-controller_test.go config/{crds,rbac,rbac_proxy,manager,default,sample}/*.yaml Icons made by Icongeek26 from www.flaticon.com is licensed by CC 3.0 BY − API resource の定義. kind毎に生成される − 生成されるテンプレートを元に定義したい spec, status とそのテストを書く その他もろもろ − Controller の実装. kind毎に生成される − 生成されるテンプレートを元に controller-runtime を使って実装/テストを書く − 各種 manifest ファイル, kustomize の app が生成される − ソースに書いたアノテーションを元に controller-tools が生成してくれる 最初大変 4
  • 5. Kubebuilder の 嬉しみ と 辛み Icons made by Roundicons from www.flaticon.com is licensed by CC 3.0 BY ● 使い始めるのが簡単 ● コピペしなくて済む (大事!) ● kubebuilder/make による標準的な開発 フローにで toil を最小化 ○ kubebuilder create api ○ make manifests/test/install/deploy ● 標準的な Controller 実装 に乗れるので コアロジック(Reconcileループ)に集中 ● controller-runtimeによる抽象度の高い ライブラリが使える ● controller の integration test もついてくる ● code 生成は 初回生成のみを想定 ○ 書換NGな場所をfencingしてくれている訳じゃ ないので基本 1 度生成したらおしまい ● CRD の Webhook Conversion は未対応 なので理解して使うべき (#275) ● probe のサポートがない (#297) ● Admission系が大規模にrefactoringされて いるのでもし使うなら将来影響あり ● controller-runtime は godoc くらいしかな いので 学習コストがそこそこある 5
  • 7. controller-runtime(v0.1.10が最新) kubernetes-sigs/controller-runtime • Kubebuilderのサブプロジェクトとして開発されている • Kubebuilder v1.0.8 は controller-runtime v0.1.1 に依存 (古め) – 最新版にupdateするPR (kubebuilder#657) はある cache by SBTS from the Noun Project Icons made by Vincent Le Moign from https://icon-icons.com/ licensed by CC 3.0 BY Icons made by Gregor Cresnar, Pause08, Freepik, Those Icons, Monkik from www.flaticon.com is licensed by CC 3.0 BY Controller Admission Webhook envtest metrics その他 client, cache, logging, leader election (resource lock) Manager controller-runtimeの主な機能 : 本日は時間都合で省略する部分 7
  • 8. Manager (a.k.a controller manager) • Runnable の lifecycle管理 (Add / Start) – Manager 経由で Start しないと ダメなので注意!! (共通依存の処理が色々必要) • 共通依存を保持: client, cache, scheme 等 – getterが提供されている(GetClient()とか) – 簡易DIの仕組みもある(runtime/inject) • Leader Election にも対応 – optionで指定するだけでOK (default false) • Graceful shutdown用のsignal handlerも完備 Controller Admission Webhook Manager Runnable * 依存を注入 8
  • 9. runtime/inject による依存の注入 • 特定のinterfaceを実装しておくとmanagerへの追加時/controller生成時 に注入してくれる package runtime/inject // 下記の依存に対応 type Cache interface { InjectCache(cache cache.Cache) error } type Client interface { InjectClient(client.Client) error } type Decoder interface { InjectDecoder(types.Decoder) error } type Scheme interface { InjectScheme(scheme *runtime.Scheme) error } type Stoppable interface { InjectStopChannel(<-chan struct{}) error } // graceful shutdown用 type Injector interface { InjectFunc(f Func) error } // injector そのもの type Logger interface { InjectLogger(l logr.Logger) error } // v0.1.1には無い // 利用例 type myReconciler struct { client.Client } func (*r myReconciler) InjectClient(c client.Client) error { r.Client = c } 9
  • 10. Manager の 作り方 import "sigs.k8s.io/controller-runtime/pkg/manager" import "sigs.k8s.io/controller-runtime/pkg/client/config" import "sigs.k8s.io/controller-runtime/pkg/runtime/signals" // v0.1.10ではmanager/signals mgr := manager.New( // manager.New で作る config.GetConfigOrDie(), // --kubecongig, KUBECONFIG, incluster, .kube/config 探して自動で読込 manager.Options{}, // Manager初期化用オプション(LeaderElection, SyncPeriod 色々設定可) ) mgr.Add(controller) // controllerを追加. 初期化方法は後述. mgr.Start(signals.SetupSignalHandler()) // signal handling 用の channel を渡して起動 注: kubebuilderを使う限りはこの辺はあまり触らなくても大丈夫なはず 10
  • 11. controller.New(name, controller.Option{ Reconciler, MaxConcurrentReconciles }) Controller (controller-runtimeにおけるcontrollerのアーキテクチャ) controller.Watch() Source Predicate EventHandler controller.Watch() Source Predicate EventHandler controller.Watch() Source Predicate EventHandler workqueue with RateLimiting ... reconcile.Request Reconciler Reconciler Reconciler Reconciler reconcile.Result (resultで指定されていたら) delay付きでrequeue 並列数は MaxConcurrentReconciles で指定できる(default = 1) • 構造的にはこれまでのベストプラクティスと同じ • Watch部分, Reconciler 部分が綺麗に整理されている 11
  • 12. controller.Watch(source, predicates, eventEandler) Source Predicate EventHandler Watchの基本構造 package controller type Controller interface { // Sourceから流れてくる event を predicateでfilter して // handlerで reconcile.Request(複数可) に変換して workqueue に enqueue Watch(source.Source, handler.EventHandler, ...predicate.Predicate) error } CreateEvent UpdateEvent DeleteEvent GenericEvent CreateEvent UpdateEvent DeleteEvent GenericEvent reconcile.Request 12
  • 13. Source は 4 種類 package source type Source interface { // Sourceは predicateとEventHandlerとqueueを渡すと開始できる // controller.Watch() は内部でこれを呼んで Watch を開始する Start(handler.EventHandler, workqueue.RateLimitingInterface, ...predicate.Predicate) error } Source Kind Channel Informer Func Kubernetes Resource用: &source.Kind{ Type: &corev1.Pod{} } 外部event用: &source.Channel{ Source: make(chan GenericEvent) } Informer直接: &source.Informer{ Informer: sharedIndexInformer } Func直接: interfaceと同じsignatureの関数はSourceとして振る舞える 13
  • 14. Predicate package predicate // 各EventType毎 に EventHandler に渡すかどうかを決める type Predicate interface { Create( event.CreateEvent) bool Delete( event.DeleteEvent) bool Update( event.UpdateEvent) bool Generic(event.GenericEvent) bool // Channel用 } Predicate Func ResourceVersionChangedPredicate カスタムしたい関数だけ渡して Predicateを生成 (登録していない関数は _ => true になる) UpdateEvent: Old!=nil && New!=nil で ResourceVersion が異なる時のみ true それ以外 : true 14
  • 15. EventHandler package reconcile type Request struct { types.NamespaecedName } // Namespace, Nameしか入れられないことに注意 ! package handler // 各EventType毎 に reconcile.Request(複数可) に変換して workqueue に enqueue する type EventHandler interface { Create( event.CreateEvent, workqueue.RateLimitingInterface) Update( event.UpdateEvent, workqueue.RateLimitingInterface) Delete( event.DeleteEvent, workqueue.RateLimitingInterface) Generic(event.GenericEvent, workqueue.RateLimitingInterface) // Channel用 } Event Handler Func EnqueueRequestForObject 必要な関数だけを渡して EventHandler を生成 Event に入っている NamespacedName に変換 EnqueueRequestForOwner OwnerReferences に入っている NamespacedNames に変換 EnqueueRequestsFromMapFunc Mapper{ Map(MapObject) []reconcile.Request } で変換 15
  • 16. Watchの例 ctr := controller.New(...) // MyKind を watch してそのNamespace/Name を reconcile.Request に ctr.Watch( &source.Kind{Type: &myKind{}}, &handler.EnqueueRequestForObject{}, ) // MyKind を Owner にもつ Pod を Watch して変化があれば、 // Owner である MyKind の Namespace/Name を reconcile.Request に ctr.Watch( &source.Kind{ Type: corev1.Pod{} }, &handler.EnqueueRequestForOwner{ OwnerType: &myKind{}, IsController: true }, ) 16
  • 17. Reconciler (Reconcileループ本体) package reconcile // 本丸。基本これを作る。 // controller 内で MaxConcurrentReconciles 個分の reconcile ループが回る type Reconciler interface { Reconcile(Request) (Result, error) } // Request は Namespace, Name しか入れられない // → Reconciler は特定の Kind の reconcile を責務とするように設計されている type Request struct { types.NamespaecedName } // Requestを再処理したい時(API erorr, race condition, preodic)とかに requeue with delay を要求可 // 成功時は reconcile.Result{} で OK type Result struct { Requeue bool, RequeueAfter time.Duration } 17
  • 18. Controller の 作り方 type MyKindReconciler struct { client.Client /* その他自分のほしい依存 */ } func (r *MyKindReconciler) InjectClient(c client.Client) error { r.Client = c } func (r *MyKindReconciler) Reconcile(o reconcile.Request) (reconcile.Result, error) { return reconcile.Result{}, nil } // reconciler を渡して controller インスタンスを作る myreconciler := &MyKindRecociler{ } ctr := controller.New( "MyKindController" , controller.Option{ Reconciler: myreconciler, MaxConcurrentReconciles: 1, }) // Watchを設定(省略)してmanagerにcontrollerを追加 mgr.Add(ctr) 18
  • 19. Controller の 作り方 (builderもある) import "sigs.k8s.io/controller-runtime/pkg/builder" builder. ControllerManagedBy(mgr). // この Manager に Add する For(&MyKind{}). // MyKind用のcontroller (自動watch) Owns(&corev1.Pod{}). // MyKindはPodをOwnする (自動watch) Complete(&myreconciler{}) // reconcilerを渡してcontrollerを作成してmanagerに登録 // 他にも色々なメソッドがある // builder.Watches(...): カスタム Watch // builder.WithEventFilter(...): 全体に適用する predicates // builder.Build(...): 登録せずに controller を返す 19
  • 20. Reconcile ループでよく使うもの (controllerutil) package controller/controllerutil // object に owner を OwnerReference (isController: true) で セットする // これをつけると Watchの時に EnqueueRequestForOwner で親Resourceのreconcile.Requstにできる // 何らかの事故で子リソースが orphanedになるとkubernetesのgarbage collection対象になる func SetControllerReference(owner, object v1.Object, scheme *runtime.Scheme) error // CreateOrUpdate そのまま 存在する時の Update は 関数で渡す // OperationResultNone OperationResult = "unchanged" // OperationResultCreated OperationResult = "created" // OperationResultUpdated OperationResult = "updated" func CreateOrUpdate( ctx context.Context, c client.Client, obj runtime.Object, f MutateFn ) (OperationResult, error) 20
  • 21. Reconcile ループでよく使うもの (client) package client // reflection を使って obj の型を検出してapiを呼んでくれる. types.NamespacedNameをkeyとして使う type ObjectKey = types.NamespacedName // Client 3 種類 の interface に分離されている type Client interface { Reader, Writer, StatusClient } type Reader interface { // key,obj を渡して obj が update される. obj struct pointer (例:&Pod{}) でないとダメ. Get(ctx context.Context, key ObjectKey, obj runtime.Object) error List(ctx context.Context, list runtime.Object, opts ...ListOptionFunc) error } type Writer interface { Create(ctx context.Context, obj runtime.Object) error Delete(ctx context.Context, obj runtime.Object, opts ...DeleteOptionFunc) error Update(ctx context.Context, obj runtime.Object) error } type StatusClient interface { Status() StatusWriter } // status subresource のみを update type StatusWriter interface { Update(ctx context.Context, obj runtime.Object) error } 21
  • 22. 例を見てみましょう kubernetes-sigs/controller-runtime/examples/crd // 同じ namespace/name が居なければ Pod を作る(status.lastRunもセット) // 時刻がnextStopを超えたらPodを止めて再度作る kind: ChaosPod spec: template: // pod template nextStop: "2019-04-01T01:00:10Z000:00" status: lastRun: "2019-04-00T01:00:00Z00:00" Reconciler loop実装: kubernetes-sigs/controller-runtime/examples/crd/main.go#L40 Manager/Controller初期化: kubernetes-sigs/controller-runtime/examples/crd/main.go#L108-L138 22
  • 23. Metrics // controller, admission webhook のメトリクスは自動で取られるようになっているので // manager.Options に MetricsBindAddress をセットするだけでよい // Kubebuilderでは自動で入ります manager.New(... , manager.Options{ MetricsBindAddress: ":8080", // http://localhost:8080/metrics …, } • 取れるメトリクス – controller: reconcilation error, reconcilation queue length, reconcile latency – webhook: total requests, latency – system metrics, client-go metrics • Kubebuiler の生成する manifest だと metrics endpoint は rbac-proxy で保護されている ので注意 – prometheus SA に 'GET /metrics' が RBAC で許可必要(基本許可されていると思う ) 23
  • 24. envtest - test 用の controll plane(api-server, etcd) Start/Stop import "sigs.k8s.io/controller-runtime/pkg/envtest" te := &envtest.Environment{ CRDDirectoryPaths : []string{filepath.Join("..", "config", "crd" }, UseExistingCluster: false, // 既存クラスタも利用可 ControlPlaneStartTimeout: 20 * time.Seconds, // (default 20sec), 環境変数でも設定可 ControlPlaneStopTimeout : 20 * time.Seconds, KubeAPIServerFlags: []string{}, // api server flags もセット可能 } // KUBEBUILDER_ASSETS(defualt=/usr/local/kubebuilder/bin) のバイナリを使って // api-server, etcd を起動して CRD をinstall して rest.Config を返してくれる config, err := te.Start() 注: kubebuilderを使う限りはこの辺は生成してくれます 24
  • 25. // SetupTestReconcile() で probe 可能な channel 付きの reconciler を作ってくれる recFn, requests := SetupTestReconcile(newReconciler(mgr)) g.Expect(add(mgr, recFn)).Should(gomega.Succeed()) stopMgr, mgrStopped := StartTestManager(mgr, g) // myKind を作れて g.Expect(c.Create(context.TODO(), myKind)).Should(gomega.Succeed()) // するとそれに対する reconcile.Request を受け取って // ハマリポイント: 作られる probe channel の capacity が 0 なので、すべて Receive してあげないと先に進まないので注意!! g.Eventually(requests).Should(gomega.Receive(gomega.Equal(expectedReconcileRequest))) // そのうち pod が出来る g.Eventually(func() error { return c.Get(context.TODO(), podNamespacedName, expectedPod) }).Should(gomega.Succeed()) envtest をつかったテスト例 (Kubebuilderの場合) 25
  • 26. Controller を 作る際 の Tips ● 大切: Reconcile Loop は 常に 滑らかに早く 回しましょう ● 理由: 複数 resource の reconcile を担うので block するとすぐ応答が悪くなります ● Tips: - Reconcile Loop は 小さくつくりましょう O(N) の loop を 1 回 ( N 個のリソースを更新 ) O(1) の loop を N 回 ( 1 個のリソースを更新 ) - State 遷移は モデル化 しておきましょう - ありとあらゆる状態を想定すると良いです - 分散システムでは「こういう状態にはならないはず」という前提を安易に設けるのは危険 - 不要な reconcile を避けましょう (event は multiplexing しましょう) - 100個の子Podが短時間死んでも1 回 reconcile を kick すれば済むはず - 親 resource を指す reconcile.Request に変換している限りworkqueueが rate limiting & dedupしてくれるのでcontroller-runtimeを使いましょう Icons made by Roundicons from www.flaticon.com is licensed by CC 3.0 BY 26
  • 28. Icons made by Vincent Le Moign from https://icon-icons.com/ licensed by CC 3.0 BY Thank you for Listening!! Any Questions?