SlideShare a Scribd company logo
1 of 40
Download to read offline
K8s Controller Manager
& KubeBuilder Deep Dive
2022/4/27
富士通株式会社
石井伴旺
© 2022 Fujitsu Limited
Kubernetes Meetup Tokyo #50
本発表の目的
○ K8sオブジェクトの作成/更新/削除からK8sコントローラがReconcile処理を実行するまでの
間にkube-controller-manager内部でどのような処理が行われているのかを説明します
○ 本発表を通してkube-controller-managerの処理がイメージしやすくなります
○ kube-controller-managerとkubebuilderで作成したコントローラとの間の差異について説
明する kube-controller-managerの分量が多くなってしまったため、割愛させて頂きます
○ 前提知識
○ K8sのコンポーネント・K8sリソースの役割といった、K8sの知識がある程度ある方を対象としています
○ Goをある程度読める方を想定していますが、図を使っての説明が有るのでGoに不慣れな方でもkube-controller-
managerの内部処理の感触がつかめると思います
○ K8s v1.23のコードをベースにしています
© 2022 Fujitsu Limited
※スライド内に記載のソースコードのパスはK8sレポジトリrootからのrelative pathです
2
自己紹介
○名前
○石井伴旺
○経歴
○2016年
富士通株式会社に入社
○2016~2019年
OpenStack・Ceph製品のセールスエンジニア
○2019年~
OpenStack・K8sなどのOSSコミュニティでの開発活動に携わる
© 2022 Fujitsu Limited
3
K8sクラスタでのkube-controller-managerの役割と概要
○ Etcdに保存されたK8sオブジェクトの定義に従ってK8sクラスタ内の処理を行う
© 2022 Fujitsu Limited
kube-apiserver
Etcd
kube-controller-manager
K8sオブジェクト
作成・更新・削除
アプリ
ユーザ
sharedIndexInformer
(Deployment)
sharedIndexInformer
(ReplicaSet)
sharedIndexInformer
(Pod)
Deploymentコントローラ
Worker
Worker
Worker
処理
work
queue
Sync
Start
Sync
End
Loop
ReplicaSetコントローラ
YYYコントローラ
sharedIndexInformer
(XXX)
…
…
K8sオブジェクトの監視(Watch)
Dequeue
4
kube-controller-manager
sharedInformerFactory
kube-controller-managerの内部コンポーネント
© 2022 Fujitsu Limited
kube-
apiserver
Deployment
Controller
workqueue worker
worker
worker
…
ReplicaSet
Controller
workqueue worker
worker
worker
…
sharedIndexInformer (Deployment)
Reflector cache
sharedProcessor
DeltaFIFO
Handler
Handler
…
sharedIndexInformer (ReplicaSet)
Reflector cache
sharedProcessor
DeltaFIFO
Handler
Handler
…
…
…
processListener
ReplicaSetをWatch
DeploymentをWatch
controller
controller
※斜体はGoのType名
cacheからK8sオブジェクト取得
※2
※2
※2 コントローラ毎に内部処理の流れやHandler/
workerがcacheを参照するか等が異なる
5
kube-controller-manager
sharedInformerFactory
kube-controller-managerでのK8sオブジェクト処理フロー
© 2022 Fujitsu Limited
kube-
apiserver
Deployment
Controller
workqueue worker
worker
worker
…
sharedIndexInformer (Deployment)
Reflector cache
sharedProcessor
DeltaFIFO
Handler
Handler
…
…
processListener
controller
※斜体はGoのType名
Watch
cacheからK8sオブジェクト取得
※2
※2 コントローラ毎に内部処理の流れやHandler/
workerがcacheを参照するか等が異なる
…
6
kube-controller-manager
sharedInformerFactory
kube-controller-managerでのK8sオブジェクト処理フロー
© 2022 Fujitsu Limited
kube-
apiserver
Deployment
Controller
workqueue worker
worker
worker
…
sharedIndexInformer (Deployment)
Reflector cache
sharedProcessor
DeltaFIFO
Handler
Handler
…
processListener
controller
※斜体はGoのType名
API Serverから取得したK8sオブ
ジェクトの更新情報(Event)を、
DeltaFIFOにEnqueueする
Watch
…
cacheからK8sオブジェクト取得
※2
※2 コントローラ毎に内部処理の流れやHandler/
workerがcacheを参照するか等が異なる
…
7
kube-controller-manager
sharedInformerFactory
kube-controller-managerでのK8sオブジェクト処理フロー
© 2022 Fujitsu Limited
kube-
apiserver
Deployment
Controller
workqueue worker
worker
worker
…
sharedIndexInformer (Deployment)
Reflector cache
sharedProcessor
DeltaFIFO
Handler
Handler
…
processListener
controller
※斜体はGoのType名
同じK8sオブジェクトに関連する更
新情報(Event)を、可能な限りまと
めて処理できるようにする
Watch
…
cacheからK8sオブジェクト取得
※2
※2 コントローラ毎に内部処理の流れやHandler/
workerがcacheを参照するか等が異なる
…
8
kube-controller-manager
sharedInformerFactory
kube-controller-managerでのK8sオブジェクト処理フロー
© 2022 Fujitsu Limited
kube-
apiserver
Deployment
Controller
workqueue worker
worker
worker
…
sharedIndexInformer (Deployment)
Reflector cache
sharedProcessor
DeltaFIFO
Handler
Handler
…
processListener
controller
※斜体はGoのType名
Watch
…
cacheからK8sオブジェクト取得
※2
※2 コントローラ毎に内部処理の流れやHandler/
workerがcacheを参照するか等が異なる
…
1つのK8sオブジェクトに起きた各Eventに対し
①cacheへの反映
②次のコンポーネントへの受け渡し
の2つ処理を順番に行う
9
kube-controller-manager
sharedInformerFactory
kube-controller-managerでのK8sオブジェクト処理フロー
© 2022 Fujitsu Limited
kube-
apiserver
Deployment
Controller
workqueue worker
worker
worker
…
sharedIndexInformer (Deployment)
Reflector cache
sharedProcessor
DeltaFIFO
Handler
Handler
…
processListener
controller
※斜体はGoのType名
Watch
…
cacheからK8sオブジェクト取得
※2
※2 コントローラ毎に内部処理の流れやHandler/
workerがcacheを参照するか等が異なる
…
controllerから送られるK8sオブジェクトの
Eventのバッファリングと各コントローラの
workqueueへのEnqueue
10
kube-controller-manager
sharedInformerFactory
kube-controller-managerでのK8sオブジェクト処理フロー
© 2022 Fujitsu Limited
kube-
apiserver
Deployment
Controller
workqueue worker
worker
worker
…
sharedIndexInformer (Deployment)
Reflector cache
sharedProcessor
DeltaFIFO
Handler
Handler
…
processListener
controller
※斜体はGoのType名
Watch
…
cacheからK8sオブジェクト取得
※2
※2 コントローラ毎に内部処理の流れやHandler/
workerがcacheを参照するか等が異なる
…
workqueueからK8sオブジェクトの名前を受け取り、
metadata, spec, statusの内容に従い処理
11
kube-controller-manager
sharedInformerFactory
kube-controller-managerでのK8sオブジェクト処理フロー
© 2022 Fujitsu Limited
kube-
apiserver
Deployment
Controller
workqueue worker
worker
worker
…
sharedIndexInformer (Deployment)
Reflector cache
sharedProcessor
DeltaFIFO
Handler
Handler
…
processListener
controller
※斜体はGoのType名
独立したgoroutine
Watch
…
cacheからK8sオブジェクト取得
※2
※2 コントローラ毎に内部処理の流れやHandler/
workerがcacheを参照するか等が異なる
…
12
kube-controller-manager
sharedInformerFactory
Reflectorについて
© 2022 Fujitsu Limited
kube-
apiserver
Deployment
Controller
workqueue worker
worker
worker
…
sharedIndexInformer (Deployment)
Reflector cache
sharedProcessor
DeltaFIFO
Handler
Handler
…
processListener
controller
※斜体はGoのType名
API Serverから取得したK8sオブ
ジェクトの更新情報(Event)を、
DeltaFIFOにEnqueueする
Watch
…
cacheからK8sオブジェクト取得
※2
※2 コントローラ毎に内部処理の流れやHandler/
workerがcacheを参照するか等が異なる
…
13
Reflectorの役割
○ 「K8s APIサーバから流れてくるK8sリソースのEvent」をDeltaFIFOにエンキューする
○ (例) DeploymentのsharedIndexInformer内のReflectorは、K8sクラスタ内の全Deploymentオブジェクトの各Event
をK8s APIサーバから取得・DeltaFIFOにエンキューしている
○ EventはEventTypeとオブジェクト情報から成る
○ オブジェクト情報:Event発生時のEtcd内のオブジェクトデータ
○ EventTypeは3種類
○ Added
K8sクラスタ内で新しいK8sオブジェクトが作成された際に
K8s APIサーバから送られる
○ Modified
K8sクラスタ内の既存K8sオブジェクトが更新された時に
K8s APIサーバから送られる
○ Deleted
K8sクラスタ内のK8sオブジェクトが削除された時に
K8s APIサーバから送られる
© 2022 Fujitsu Limited
{
"type": "MODIFIED",
"object": {
"kind": "Deployment",
"apiVersion": "apps/v1",
"metadata": {
"name": “dep1",
"namespace": "default",
"uid": "6520f999-3691-4402-af4c-d227a2da27bb",
…
},
"spec": {
"replicas": 1,
"selector": {
…
},
…
},
"status": {}
}
}
Event発生時にEtcdが
保持している
Deployment/dep1データ
Event
← EventType
K8s API
Server
Reflector
DeltaFIFO
Event
Type Object
watch 14
Reflectorのコードについて
○ Reflector作成の契機
○ Eventの取得とDeltaFIFOへのエンキュー
© 2022 Fujitsu Limited
type Reflector {
name string
store Store //DeltaFIFO
listWatcher ListWatcher
…
}
*sharedIndexInformer.Run
- DeltaFIFOの作成
- K8s APIをWatchする際に使用するlistWatcherの指定
*controller.Run
- Reflectorの設定
- Reflectorの作成
*Reflector.Run
- listWatcherからのEvent取得
- EventTypeを見てDeltaFIFOへエンキュー
呼出 呼出
func (r *Reflector) watchHandler(…) {
…
for {
select {
case event, ok := <-w.ResultChan():
…
switch event.Type {
case watch.Added:
err := r.store.Add(event.Object)
case watch.Modified:
err := r.store.Update(event.Object)
case watch.Deleted:
err := r.store.Delete(event.Object)
}
…
Reflector.Runが内部で呼び出すメソッド
listWatcherからのEvent取得
EventTypeを見てDeltaFIFOへエンキュー
*2 staging/src/k8s.io/client-go/tools/cache/controller.go
(*3) (*3)
*1 staging/src/k8s.io/client-go/tools/cache/shared_informer.go
*3 staging/src/k8s.io/client-go/tools/cache/reflector.go
(*1) (*2) (*3)
15
kube-controller-manager
sharedInformerFactory
DeltaFIFOについて
© 2022 Fujitsu Limited
kube-
apiserver
Deployment
Controller
workqueue worker
worker
worker
…
sharedIndexInformer (Deployment)
Reflector cache
sharedProcessor
DeltaFIFO
Handler
Handler
…
processListener
controller
※斜体はGoのType名
同じK8sオブジェクトに関連する更
新情報(Event)を、可能な限りまと
めて処理できるようにする
Watch
…
cacheからK8sオブジェクト取得
※2
※2 コントローラ毎に内部処理の流れやHandler/
workerがcacheを参照するか等が異なる
…
16
DeltaFIFOの役割
○ あるK8sオブジェクトに対する連続したEventをまとめて処理できるようにする
○ 同じオブジェクトに対するEventをDeltaタイプに変換して積み上げ、まとめてデキューする
© 2022 Fujitsu Limited
Del
obj2
Add
obj3
Mod
obj1
Add
obj2
Mod
obj1
Add
obj1
DeltaFIFO
Enqueue
Add
obj3
Del
obj2
Add
obj2
Mod
obj1
Mod
obj1
Add
obj1
DeltaFIFO
Dequeue
Event
Delta
Deltas
①
②
③
④
⑤
⑥
①
②
④
③
⑥
⑤
17
DeltaFIFOのコードについて
○ DeltaFIFO作成の契機
○ DeltaFIFO内部構造
© 2022 Fujitsu Limited
type DeltaFIFO struct {
items map[string]Deltas
queue []string
keyFunc KeyFunc
…
}
type Deltas []Delta
type Delta struct {
Type DeltaType // Added/Updated/Deleted
Object interface{} // K8s Object
}
func (s *sharedIndexInformer) Run(…) {
…
fifo := NewDeltaFIFOWithOption(DeltaFIFOOptions{
KnownObjects: s.indexer,
EmitDelayTypeReplaced: true,
})
…
Key: K8sオブジェクトの <namespace>/<name> ペア
Value: 積み上げたEvent(Deltas)
FIFOキューの機能を提供するため、エンキューされたK8sオブジェクトの順番を保持
itemsのKey, queueのelementとして使用している文字列 <namespace>/<name> を
K8sオブジェクトから作成する関数
(*DeltaFIFO)のAdd, Update, DeleteメソッドにK8s objectを引数として渡し
- DeltaFIFOへのエンキュー
- ADDED, MODIFIED, DELETED EventのDeltaデータ型への変換・積み上げ
を行う
*1 staging/src/k8s.io/client-go/tools/cache/shared_informer.go
(*1)
*2 staging/src/k8s.io/client-go/tools/cache/delta_fifo.go
(*2)
(*2)
18
kube-controller-manager
sharedInformerFactory
controllerについて
© 2022 Fujitsu Limited
kube-
apiserver
Deployment
Controller
workqueue worker
worker
worker
…
sharedIndexInformer (Deployment)
Reflector cache
sharedProcessor
DeltaFIFO
Handler
Handler
…
processListener
controller
※斜体はGoのType名
Watch
…
cacheからK8sオブジェクト取得
※2
※2 コントローラ毎に内部処理の流れやHandler/
workerがcacheを参照するか等が異なる
…
1つのK8sオブジェクトに起きた各Eventに対し
①cacheへの反映
②次のコンポーネントへの受け渡し
の2つ処理を順番に行う
19
○ DeltaFIFOから取得したK8sオブジェクトの状態をcacheに反映した後、次のコンポーネント
(processListener)にK8sオブジェクトの情報(Notification)を渡す
○ DeltaFIFOから取り出したK8sオブジェクトに関連する各Deltaに対しcache反映・processListnerへの引き渡しを行う
sharedProcessor
controllerの役割
© 2022 Fujitsu Limited
Mod
Add
DeltaFIFO
Handler
Handler
cache
①
②
controller
processListener
Dequeue
DeltaFIFOからDequeueした各Deltaに対し以下2つの処理を順番に行う
① 各DeltaのDeltaTypeが
・Added/Updatedのときは、Delta内に保持されているK8sオブジェクトをcacheに保存
・Deletedのときは、Deltaに紐づいているK8sオブジェクトをcacheから削除
② Deltaが保持するK8sオブジェクトとcacheが保持しているK8sオブジェクト情報から
Notificationというデータを作成し、processListenerに渡す
図の例では、Addに対し①②の処理を行ったあと、Modに対し①②の処理を行う
Delta
Notification
Notification
20
controllerのコードについて
○ controller作成・動作契機
○ controller.processLoopの処理
© 2022 Fujitsu Limited
*sharedIndexInformer.Run
- controllerの作成
*controller.Run
- controller.processLoopを呼び以下実行
* DeltaFIFOからのDequeue
* cacheへの更新
* processListenerへのNotification発行
呼出
type Config struct {
Queue
Process
…
}
func (c *controller) processLoop() {
for {
obj, err := c.config.Queue.Pop(PopProcessFunc(c.config.Process))
…
}
type controller struct {
config Config
…
}
DeltaFIFO
sharedIndexInformer.HandleDeltasメソッドがセットされる
以下の処理をループする
DeltaFIFOからDequeueしたDeltasタイプの
変数をsharedIndexInformerの
HandleDeltasメソッドに引数として渡す
*2 staging/src/k8s.io/client-go/tools/cache/controller.go
(*2)
(*2)
(*2)
*1 staging/src/k8s.io/client-go/tools/cache/shared_informer.go
(*2)
(*1)
21
controllerのコードについて
○ controller.processLoopの処理
© 2022 Fujitsu Limited
func (c *controller) processLoop() {
for {
obj, err := c.config.Queue.Pop(PopProcessFunc(c.config.Process))
func (s *sharedIndexInformer) HandleDeltas(obj interface{}) error {
…
for _, d := range obj.(Deltas) {
switch d.Type {
case Sync, Replaced, Added, Updated:
…
if old, exists, err := s.indexer.Get(d.Object); err == nil && exists {
if err := s.indexer.Update(d.Object); err != nil {
…
}
…
s.processor.distribute(updateNotification{oldObj: old, newObj: d.Object}, isSync)
} else {
if err := s.indexer.Add(d.Object); err != nil {
return err
}
s.processor.distribute(addNotification{newObj: d.Object}, false)
}
case Deleted:
if err := s.indexer.Delete(d.Object); err != nil {
return err
}
s.processor.distribute(deleteNotification{oldObj: d.Object}, false)
sharedIndexInformer.indexerがcache
processListenerにNotificationを送る
ためにprocessListenerを管理している
sharedProcessorのdistributeメソッドを
実行
*1 staging/src/k8s.io/client-go/tools/cache/shared_informer.go
(*1)
22
controllerのコードについて
○ controller.processLoopでの次のコンポーネント(processListener)にNotificationを送る処理
© 2022 Fujitsu Limited
type sharedProcessor struct {
listenersStarted bool
listenersLock sync.RWMutex
listeners []*processorListener
syncingListeners []*processorListener
clock clock.Clock
wg wait.Group
}
func NewSharedIndexInformer(…) SharedIndexInformer {
realClock := &clock.RealClock{}
sharedIndexInformer := &sharedIndexInformer{
processor: &sharedProcessor{clock: realClock},
…
}
return sharedIndexInformer
}
func (p *sharedProcessor) distribute(obj interface{}, sync bool) {
…
if sync {
…
} else {
for _, listener := range p.listeners {
listener.add(obj)
}
}
}
sharedProcessorが管理
しているprocessListener
各processListenerのaddメソッドを呼んで
Notification(obj)を渡している
*1 staging/src/k8s.io/client-go/tools/cache/reflector.go
*2 staging/src/k8s.io/client-go/tools/cache/shared_informer.go
(*1)
(*2)
(*2)
23
kube-controller-manager
sharedInformerFactory
processListenerについて
© 2022 Fujitsu Limited
kube-
apiserver
Deployment
Controller
workqueue worker
worker
worker
…
sharedIndexInformer (Deployment)
Reflector cache
sharedProcessor
DeltaFIFO
Handler
Handler
…
processListener
controller
※斜体はGoのType名
Watch
…
cacheからK8sオブジェクト取得
※2
※2 コントローラ毎に内部処理の流れやHandler/
workerがcacheを参照するか等が異なる
…
controllerから送られるK8sオブジェクトの
Eventのバッファリングと各コントローラの
workqueueへのEnqueue
24
○ controllerから渡されるNotificationのバッファリングと、Notificationから各コントローラ
が実際に処理するK8sオブジェクトの抽出・コントローラworkqueueへのエンキューを行う
sharedProcessor
processListenerの役割
© 2022 Fujitsu Limited
Handler
controllerからのK8sオブジェクトの更新情報
(Notification)をRingBufferでバッファリング
• 各コントローラは自身のHandlerを含むprocessListenerを作成し
sharedProcessorに登録
• HandlerはNotificationを見て、どのK8sオブジェクトをコントロー
ラで処理するか判断し、コントローラのworkqueueに送る
processListener
Deployment
Controller
workqueue worker
worker
worker
…
cache
controller
Notification
※ コントローラ毎にコントローラ内部処理の流れや
Handler/workerがcacheを参照するか等が異なる
25
processListenerのコードについて
○ processListener作成の契機
○ 各コントローラ作成時に自身のHandlerをsharedIndexInformer.AddEventHandlerを呼んで登録
© 2022 Fujitsu Limited
func NewDeploymentController(dInformer appsinformers.DeploymentInformer, …) (*DeploymentController, error) {
…
dInformer.Informer().AddEventHandler(cache.ResourceEventHandlerFuncs{
AddFunc: dc.addDeployment,
UpdateFunc: dc.updateDeployment,
DeleteFunc: dc.deleteDeployment,
})
func (s *sharedIndexInformer) AddEventHandler(handler ResourceEventHandler) {
s.AddEventHandlerWithResyncPeriod(handler, s.defaultEventHandlerResyncPeriod)
}
…
func (s *sharedIndexInformer) AddEventHandlerWithResyncPeriod(handler ResourceEventHandler, …) {
…
listener := newProcessListener(handler, …)
…
if !s.started {
s.processor.addListener(listener)
return
}
…
s.processor.addListener(listener)
Deployment sharedIndexInformerにDeployment
コントローラが自身のHandlerを登録している箇所
Handler
processListenerの作成
processListenerを管理するsharedProcessor
に作成したprocessListenerを登録
Notificationからコントローラ
で処理するK8sオブジェクト
を判断するための処理
- AddFunc:
addNotificationを
受け取った際に実行
- UpdateFunc:
updateNotificationを
受け取った際に実行
- DeleteFunc:
deleteNotificationを
受け取った際に実行
*1 pkg/controller/deployment/deployment_controller.go
(*1)
*2 staging/src/k8s.io/client-go/tools/cache/shared_informer.go
(*2)
26
processListenerのコードについて
○ processListenerの動作契機
○ 受け取ったNotificationのprocessListenerでの処理
© 2022 Fujitsu Limited
func (p *sharedProcessor) run(stopCh <-chan struct{}) {
func() {
…
for _, listener := range p.listeners {
p.wg.Start(listener.run)
p.wg.Start(listener.pop)
}
…
*sharedIndexInformer.Run
- processListenerを管理するsharedProcessorをrun
*sharedProcessor.run
- 管理するprocessListenerのpop・run各メソッドを独立goroutineで実行
- sharedProcessor.run実行後にsharedProcessor.addListenerで追加された
processListenerのpop・runメソッドはaddListener実行時に実行される
func (p *processorListener) add(notification interface{}) {
p.addCh <- notification
}
func (p *sharedProcessor) distribute(obj interface{}, …) {
…
for _, listener := range p.listeners {
listener.add(obj)
}
…
呼出
sharedProcessorが管理する各processListenerの
run, popメソッドを個別のgoroutineで実行
processListenerは自身のGoチャンネル(addCh)を通して
Notificationを受け取る
*1 staging/src/k8s.io/client-go/tools/cache/shared_informer.go
(*1)
(*1)
(*1)
(*1)
(*1)
27
processListenerのコードについて
○ processListenerでのNotificationのバッファリング
© 2022 Fujitsu Limited
func (p *processorListener) pop() {
…
for {
select {
case nextCh <- notification:
var ok bool
notification, ok = p.pendingNotifications.ReadOne()
if !ok { // Nothing to pop
nextCh = nil // Disable this select case
}
case notificationToAdd, ok := <-p.addCh:
if !ok {
return
}
if notification == nil {
notification = notificationToAdd
nextCh = p.nextCh
} else { // There is already a notification waiting to be dispatched
p.pendingNotifications.WriteOne(notificationToAdd)
}
}
}
}
Notificationの受け取り
RingBufferへ受け取ったNotification
をエンキュー
RingBufferが空の時はバッファを介さず次
の処理(run)にNotificationを渡すようにする
RingBufferから受け取ったNotificationを
デキュー
p.nextCh (Goチャンネル)経由で次の処理
(run)にNotificationを渡す
*1 staging/src/k8s.io/client-go/tools/cache/shared_informer.go
(*1) 28
processListenerのコードについて
○ HandlerへのNotification内 K8sオブジェクトの受け渡し
© 2022 Fujitsu Limited
func (p *processorListener) run() {
…
stopCh := make(chan struct{})
wait.Until(func() {
for next := range p.nextCh {
switch notification := next.(type) {
case updateNotification:
p.handler.OnUpdate(notification.oldObj, notification.newObj)
case addNotification:
p.handler.OnAdd(notification.newObj)
case deleteNotification:
p.handler.OnDelete(notification.oldObj)
default:
utilruntime.HandleError(fmt.Errorf("unrecognized notification: %T", next))
}
}
close(stopCh)
}, 1*time.Second, stopCh)
}
popからNotificationの受け取り
Notificationの種類に応じて
Handler関数に、Notification内
のK8sオブジェクトをわたす
*1 staging/src/k8s.io/client-go/tools/cache/shared_informer.go
(*1)
29
processListenerのコードについて
○ Deployment sharedIndexInformerにDeploymentコントローラが登録したHandlerの処理
© 2022 Fujitsu Limited
func NewDeploymentController(dInformer appsinformers.DeploymentInformer, …) (*DeploymentController, error) {
…
dInformer.Informer().AddEventHandler(cache.ResourceEventHandlerFuncs{
AddFunc: dc.addDeployment,
UpdateFunc: dc.updateDeployment,
// This will enter the sync loop and no-op, because the deployment has been deleted from the store.
DeleteFunc: dc.deleteDeployment,
})
func (dc *DeploymentController) addDeployment(obj interface{}) {
d := obj.(*apps.Deployment)
klog.V(4).InfoS("Adding deployment", "deployment", klog.KObj(d))
dc.enqueueDeployment(d)
}
func (dc *DeploymentController) enqueue(deployment *apps.Deployment) {
key, err := controller.KeyFunc(deployment)
…
dc.queue.Add(key)
}
DeploymentControllerのenqueueDeployment
フィールドの中身はenqueueメソッド
Deploymentコントローラのworkqueueに
Keyをエンキュー
K8sオブジェクトを一意に識別する文字列(Key)
<namespace>/<name> を作成
*1 pkg/controller/deployment/deployment_controller.go
(*1)
(*1)
(*1)
30
processListenerのコードについて
○ Pod sharedIndexInformerにReplicaSetコントローラが登録したHandlerの処理
© 2022 Fujitsu Limited
func NewBaseController(…, podInformer coreinformers.PodInformer, …) *ReplicaSetController {
…
podInformer.Informer().AddEventHandler(cache.ResourceEventHandlerFuncs{
AddFunc: rsc.addPod,
UpdateFunc: rsc.updatePod,
DeleteFunc: rsc.deletePod,
})
func (rsc *ReplicaSetController) addPod(obj interface{}) {
pod := obj.(*v1.Pod)
…
if controllerRef := metav1.GetControllerOf(pod); controllerRef != nil {
rs := rsc.resolveControllerRef(pod.Namespace, controllerRef)
…
rsKey, err := controller.KeyFunc(rs)
…
rsc.queue.Add(rsKey)
return
}
Podに紐づいたReplicaSetの情報を取得
Podと紐づいたReplicaSetの状態を
cacheから取得
ReplicaSetコントローラのworkqueueに
Keyをエンキュー
K8sオブジェクトを一意に識別する文字列(Key)
<namespace>/<name> を作成
*1 pkg/controller/replicaset/replica_set.go
(*1)
(*1)
31
kube-controller-manager
sharedInformerFactory
コントローラについて
© 2022 Fujitsu Limited
kube-
apiserver
Deployment
Controller
workqueue worker
worker
worker
…
sharedIndexInformer (Deployment)
Reflector cache
sharedProcessor
DeltaFIFO
Handler
Handler
…
processListener
controller
※斜体はGoのType名
Watch
…
cacheからK8sオブジェクト取得
※2
※2 コントローラ毎に内部処理の流れやHandler/
workerがcacheを参照するか等が異なる
…
workqueueからK8sオブジェクトの名前を受け取り、
metadata, spec, statusの内容に従い処理
32
コントローラの役割
○ processListenerから受け取ったトリガーを契機(※)に、K8sオブジェクトのmetadata・
spec・statusに沿って処理を行う
© 2022 Fujitsu Limited
sharedProcessor
Handler
Deployment
Controller
workqueue
worker
worker
worker
…
※ コントローラ毎にコントローラ内部処理の流れやHandler/workerのふるまいが異なる
processListener
sharedProcessor
Handler
…
各workerは独立した
goroutineで動作
多くのHandlerはコントローラが処理するべきK8sオ
ブジェクトを表す文字列 <namespace>/<name>
をworkqueueにエンキューする
同じK8sオブジェクトが複数の
workerで同時に処理されないよう管理
処理
Sync
Start
Sync
End
cacheからK8s
オブジェクト取得
kube-
apiserver
K8sオブジェクト
修正
Loop
33
コントローラのコードについて
○ コントローラ作成契機
© 2022 Fujitsu Limited
main()
- cobra Commandを作成し実行
Run(…)
- flag・configの適用
- コントローラの作成・実行
func Run(…) error {
…
saTokenControllerInitFunc := serviceAccountTokenControllerStarter(…)
…
run := func(…, startSATokenController InitFunc, initializersFunc ControllerInitializersFunc) {
…
controllerInitializers := initializersFunc(controllerContext.LoopMode)
if err := StartControllers(…, startSATokenController, controllerInitializers, …); err != nil {
klog.Fatalf("error starting controllers: %v", err)
}
controllerContext.InformerFactory.Start(stopCh)
controllerContext.ObjectOrMetadataInformerFactory.Start(stopCh)
close(controllerContext.InformersStarted)
select {}
}
…
if !c.ComponentConfig.Generic.LeaderElection.LeaderElect {
run(context.TODO(), saTokenControllerInitFunc, NewControllerInitializers)
panic("unreachable")
}
呼出
ServiceAccountTokentコントローラ生成関数
各種コントローラ生成関数
HA無しController Managerの処理実行
(HA有の場合はさらに下の箇所で処理実行)
コントローラ生成関数を実行し
コントローラ作成・スタート
*1 cmd/kube-controller-manager/controller-manager.go
*2 cmd/kube-controller-manager/app/controllermanager.go
(*1) (*2)
(*2)
34
コントローラのコードについて
○ 各コントローラの作成・実行関数
© 2022 Fujitsu Limited
func NewControllerInitializers(loopMode ControllerLoopMode) map[string]InitFunc {
controllers := map[string]InitFunc{}
controllers["endpoint"] = startEndpointController
controllers["endpointslice"] = startEndpointSliceController
controllers["endpointslicemirroring"] = startEndpointSliceMirroringController
controllers["replicationcontroller"] = startReplicationController
…
controllers["deployment"] = startDeploymentController
…
func startDeploymentController(…) (controller.Interface, bool, error) {
dc, err := deployment.NewDeploymentController(
controllerContext.InformerFactory.Apps().V1().Deployments(),
controllerContext.InformerFactory.Apps().V1().ReplicaSets(),
controllerContext.InformerFactory.Core().V1().Pods(),
controllerContext.ClientBuilder.ClientOrDie("deployment-controller"),
)
if err != nil {
return nil, true, fmt.Errorf("error creating Deployment controller: %v", err)
}
go dc.Run(ctx, int(controllerContext.ComponentConfig.DeploymentController.ConcurrentDeploymentSyncs))
return nil, true, nil
}
ServiceAccountTokenコントローラ
以外のコントローラの作成・実行関数
はNewControllerInitializers内にある
コントローラの作成
コントローラの実行
*1 cmd/kube-controller-manager/app/controllermanager.go
(*1)
*2 cmd/kube-controller-manager/app/apps.go
(*2) 35
コントローラのコードについて
○ Deploymentコントローラの作成
○ workqueueについて
© 2022 Fujitsu Limited
func NewDeploymentController(dInformer appsinformers.DeploymentInformer, …) (*DeploymentController, error) {
…
dc := &DeploymentController{
client: client,
eventRecorder: eventBroadcaster.NewRecorder(scheme.Scheme, v1.EventSource{Component: "deployment-controller"}),
queue: workqueue.NewNamedRateLimitingQueue(…),
}
…
dInformer.Informer().AddEventHandler(cache.ResourceEventHandlerFuncs{
AddFunc: dc.addDeployment,
UpdateFunc: dc.updateDeployment,
DeleteFunc: dc.deleteDeployment,
})
…
type Type struct {
queue []t
dirty set
processing set
…
}
sharedIndexInformerへのHandler登録
workqueueの作成
workqueueの中ではTypeが用いられている
①コントローラで処理する順番を保持
②コントローラで再度処理しなくてはならない、現在処理中のK8sオブジェクトのKeyを保持
③コントローラで処理中のK8sオブジェクトのKeyを保持
①
②
③
*1 pkg/controller/deployment/deployment_controller.go
(*1)
*2 staging/src/k8s.io/client-go/util/workqueue/queue.go
(*2) 36
コントローラのコードについて
○ Deploymentコントローラの内部処理
© 2022 Fujitsu Limited
func (dc *DeploymentController) Run(…, workers int) {
…
for i := 0; i < workers; i++ {
go wait.UntilWithContext(ctx, dc.worker, …)
}
…
}
…
func (dc *DeploymentController) worker(ctx context.Context) {
for dc.processNextWorkItem(ctx) {
}
}
func (dc *DeploymentController) processNextWorkItem(…) bool {
key, quit := dc.queue.Get()
…
err := dc.syncHandler(ctx, key.(string))
dc.handleErr(err, key)
return true
}
func (dc *DeploymentController) syncDeployment(…, key string) error {
namespace, name, err := cache.SplitMetaNamespaceKey(key)
…
deployment, err := dc.dLister.Deployments(namespace).Get(name)
…
d := deployment.DeepCopy()
…
everything := metav1.LabelSelector{}
if reflect.DeepEqual(d.Spec.Selector, &everything) {
dc.eventRecorder.Eventf(…
if d.Status.ObservedGeneration < d.Generation {
d.Status.ObservedGeneration = d.Generation
dc.client.AppsV1().Deployments(d.Namespace).UpdateStatus(ctx, d, metav1.UpdateOptions{})
}
…
独立したgoroutineでworker実行 workqueueからデキューしたKey
<namespace>/<name> を処理
メソッドに渡す
Keyから処理するDeploymentオブジェクトの
Namspace・Nameを取得
cacheからDeploymentオブジェクトを取得
DeploymentオブジェクトのStatusの更新
処理でエラーが出たら
workqueueにリキュー
*1 pkg/controller/deployment/deployment_controller.go
(*1)
(*1)
(*1)
37
kube-controller-manager内の非同期性について
○ コントローラ処理の契機となったK8sオブジェクトとキャッシュ内部のオブジェクトのずれ
○ キャッシュ参照時に更新されたオブジェクトを見たり、契機となったオブジェクトが更新されている可能性がある
© 2022 Fujitsu Limited
sharedInformerFactory
kube-
apiserver
Deployment
Controller
workqueue worker
worker
worker
…
ReplicaSet
Controller
workqueue worker
worker
worker
…
sharedIndexInformer (Deployment)
Reflector cache
sharedProcessor
DeltaFIFO
Handler
Handler
…
sharedIndexInformer (ReplicaSet)
Reflector cache
sharedProcessor
DeltaFIFO
Handler
Handler
…
processListener
ReplicaSetをWatch
DeploymentをWatch
controller
controller
cacheからK8sオブジェクト取得
obj2
obj2’
obj1
obj1’
kube-controller-manager
38
各コントローラのコードについて
kube-controller-managerが管理する各コントローラの内部構造はコントローラ毎に異なる
○ workqueue
○ エンキュー契機
○ K8sオブジェクトの変更をReflectorが通知し、Handlerが処理するK8sオブジェクトのKeyをエンキューする
○ 一定時間ごとにkube-apiserverからK8sオブジェクトを取得し、処理するオブジェクトのKeyをエンキュー
○ workqueueが無く、コントローラ内部で一定時間ごとにkube-apiserverからオブジェクトを取得
○ workqueueの数・実装
○ 一つのコントローラ内に複数種類のworkqueueがある
○ GoチャンネルやGo mapを用いてworkqueueを実装している
○ <namespace>/<name> の文字列(Key)ではなく、K8sオブジェクト自体をworkqueueにエンキュー
○ コントローラの処理
○ cacheだけでなくkube-spiserverからK8sオブジェクトを取得し、metadata・spec・statusに従って処理
○ 複数個の種類の異なる処理フローが別々のgoroutineで動作している
○ processListenerを動的に作成し、sharedProcessorに登録
© 2022 Fujitsu Limited
39
Thank you
© 2022 Fujitsu Limited

More Related Content

What's hot

containerdの概要と最近の機能
containerdの概要と最近の機能containerdの概要と最近の機能
containerdの概要と最近の機能Kohei Tokunaga
 
Kubernetesでの性能解析 ~なんとなく遅いからの脱却~(Kubernetes Meetup Tokyo #33 発表資料)
Kubernetesでの性能解析 ~なんとなく遅いからの脱却~(Kubernetes Meetup Tokyo #33 発表資料)Kubernetesでの性能解析 ~なんとなく遅いからの脱却~(Kubernetes Meetup Tokyo #33 発表資料)
Kubernetesでの性能解析 ~なんとなく遅いからの脱却~(Kubernetes Meetup Tokyo #33 発表資料)NTT DATA Technology & Innovation
 
Hyperledger Fabric Private Chaincodeについて
Hyperledger Fabric Private ChaincodeについてHyperledger Fabric Private Chaincodeについて
Hyperledger Fabric Private ChaincodeについてHyperleger Tokyo Meetup
 
Topology Managerについて / Kubernetes Meetup Tokyo 50
Topology Managerについて / Kubernetes Meetup Tokyo 50Topology Managerについて / Kubernetes Meetup Tokyo 50
Topology Managerについて / Kubernetes Meetup Tokyo 50Preferred Networks
 
ソフトウェアでのパケット処理あれこれ〜何故我々はロードバランサを自作するに至ったのか〜
ソフトウェアでのパケット処理あれこれ〜何故我々はロードバランサを自作するに至ったのか〜ソフトウェアでのパケット処理あれこれ〜何故我々はロードバランサを自作するに至ったのか〜
ソフトウェアでのパケット処理あれこれ〜何故我々はロードバランサを自作するに至ったのか〜LINE Corporation
 
乗っ取れコンテナ!!開発者から見たコンテナセキュリティの考え方(CloudNative Days Tokyo 2021 発表資料)
乗っ取れコンテナ!!開発者から見たコンテナセキュリティの考え方(CloudNative Days Tokyo 2021 発表資料)乗っ取れコンテナ!!開発者から見たコンテナセキュリティの考え方(CloudNative Days Tokyo 2021 発表資料)
乗っ取れコンテナ!!開発者から見たコンテナセキュリティの考え方(CloudNative Days Tokyo 2021 発表資料)NTT DATA Technology & Innovation
 
Kubernetesのしくみ やさしく学ぶ 内部構造とアーキテクチャー
Kubernetesのしくみ やさしく学ぶ 内部構造とアーキテクチャーKubernetesのしくみ やさしく学ぶ 内部構造とアーキテクチャー
Kubernetesのしくみ やさしく学ぶ 内部構造とアーキテクチャーToru Makabe
 
[CEDEC 2021] 運用中タイトルでも怖くない! 『メルクストーリア』におけるハイパフォーマンス・ローコストなリアルタイム通信技術の導入事例
[CEDEC 2021] 運用中タイトルでも怖くない! 『メルクストーリア』におけるハイパフォーマンス・ローコストなリアルタイム通信技術の導入事例[CEDEC 2021] 運用中タイトルでも怖くない! 『メルクストーリア』におけるハイパフォーマンス・ローコストなリアルタイム通信技術の導入事例
[CEDEC 2021] 運用中タイトルでも怖くない! 『メルクストーリア』におけるハイパフォーマンス・ローコストなリアルタイム通信技術の導入事例Naoya Kishimoto
 
入門 Kubeflow ~Kubernetesで機械学習をはじめるために~ (NTT Tech Conference #4 講演資料)
入門 Kubeflow ~Kubernetesで機械学習をはじめるために~ (NTT Tech Conference #4 講演資料)入門 Kubeflow ~Kubernetesで機械学習をはじめるために~ (NTT Tech Conference #4 講演資料)
入門 Kubeflow ~Kubernetesで機械学習をはじめるために~ (NTT Tech Conference #4 講演資料)NTT DATA Technology & Innovation
 
Prometheus monitoring from outside of Kubernetes
 〜どうして我々はKubernetes上のPromet...
Prometheus monitoring from outside of Kubernetes
 〜どうして我々はKubernetes上のPromet...Prometheus monitoring from outside of Kubernetes
 〜どうして我々はKubernetes上のPromet...
Prometheus monitoring from outside of Kubernetes
 〜どうして我々はKubernetes上のPromet...whywaita
 
マイクロサービスバックエンドAPIのためのRESTとgRPC
マイクロサービスバックエンドAPIのためのRESTとgRPCマイクロサービスバックエンドAPIのためのRESTとgRPC
マイクロサービスバックエンドAPIのためのRESTとgRPCdisc99_
 
KubernetesのRBACを掘り下げてみる(Kubernetes Novice Tokyo #17 発表資料)
KubernetesのRBACを掘り下げてみる(Kubernetes Novice Tokyo #17 発表資料)KubernetesのRBACを掘り下げてみる(Kubernetes Novice Tokyo #17 発表資料)
KubernetesのRBACを掘り下げてみる(Kubernetes Novice Tokyo #17 発表資料)NTT DATA Technology & Innovation
 
GKE に飛んでくるトラフィックを 自由自在に操る力 | 第 10 回 Google Cloud INSIDE Games & Apps Online
GKE に飛んでくるトラフィックを 自由自在に操る力 | 第 10 回 Google Cloud INSIDE Games & Apps OnlineGKE に飛んでくるトラフィックを 自由自在に操る力 | 第 10 回 Google Cloud INSIDE Games & Apps Online
GKE に飛んでくるトラフィックを 自由自在に操る力 | 第 10 回 Google Cloud INSIDE Games & Apps OnlineGoogle Cloud Platform - Japan
 
Kubernetes ControllerをScale-Outさせる方法 / Kubernetes Meetup Tokyo #55
Kubernetes ControllerをScale-Outさせる方法 / Kubernetes Meetup Tokyo #55Kubernetes ControllerをScale-Outさせる方法 / Kubernetes Meetup Tokyo #55
Kubernetes ControllerをScale-Outさせる方法 / Kubernetes Meetup Tokyo #55Preferred Networks
 
Linuxにて複数のコマンドを並列実行(同時実行数の制限付き)
Linuxにて複数のコマンドを並列実行(同時実行数の制限付き)Linuxにて複数のコマンドを並列実行(同時実行数の制限付き)
Linuxにて複数のコマンドを並列実行(同時実行数の制限付き)Hiro H.
 
BuildKitによる高速でセキュアなイメージビルド
BuildKitによる高速でセキュアなイメージビルドBuildKitによる高速でセキュアなイメージビルド
BuildKitによる高速でセキュアなイメージビルドAkihiro Suda
 
eStargzイメージとlazy pullingによる高速なコンテナ起動
eStargzイメージとlazy pullingによる高速なコンテナ起動eStargzイメージとlazy pullingによる高速なコンテナ起動
eStargzイメージとlazy pullingによる高速なコンテナ起動Kohei Tokunaga
 
Dockerからcontainerdへの移行
Dockerからcontainerdへの移行Dockerからcontainerdへの移行
Dockerからcontainerdへの移行Akihiro Suda
 
【CNDT2022】SIerで実践!クラウドネイティブを普及させる取り組み
【CNDT2022】SIerで実践!クラウドネイティブを普及させる取り組み【CNDT2022】SIerで実践!クラウドネイティブを普及させる取り組み
【CNDT2022】SIerで実践!クラウドネイティブを普及させる取り組みYuta Shimada
 

What's hot (20)

containerdの概要と最近の機能
containerdの概要と最近の機能containerdの概要と最近の機能
containerdの概要と最近の機能
 
Kubernetesでの性能解析 ~なんとなく遅いからの脱却~(Kubernetes Meetup Tokyo #33 発表資料)
Kubernetesでの性能解析 ~なんとなく遅いからの脱却~(Kubernetes Meetup Tokyo #33 発表資料)Kubernetesでの性能解析 ~なんとなく遅いからの脱却~(Kubernetes Meetup Tokyo #33 発表資料)
Kubernetesでの性能解析 ~なんとなく遅いからの脱却~(Kubernetes Meetup Tokyo #33 発表資料)
 
Hyperledger Fabric Private Chaincodeについて
Hyperledger Fabric Private ChaincodeについてHyperledger Fabric Private Chaincodeについて
Hyperledger Fabric Private Chaincodeについて
 
Topology Managerについて / Kubernetes Meetup Tokyo 50
Topology Managerについて / Kubernetes Meetup Tokyo 50Topology Managerについて / Kubernetes Meetup Tokyo 50
Topology Managerについて / Kubernetes Meetup Tokyo 50
 
ソフトウェアでのパケット処理あれこれ〜何故我々はロードバランサを自作するに至ったのか〜
ソフトウェアでのパケット処理あれこれ〜何故我々はロードバランサを自作するに至ったのか〜ソフトウェアでのパケット処理あれこれ〜何故我々はロードバランサを自作するに至ったのか〜
ソフトウェアでのパケット処理あれこれ〜何故我々はロードバランサを自作するに至ったのか〜
 
乗っ取れコンテナ!!開発者から見たコンテナセキュリティの考え方(CloudNative Days Tokyo 2021 発表資料)
乗っ取れコンテナ!!開発者から見たコンテナセキュリティの考え方(CloudNative Days Tokyo 2021 発表資料)乗っ取れコンテナ!!開発者から見たコンテナセキュリティの考え方(CloudNative Days Tokyo 2021 発表資料)
乗っ取れコンテナ!!開発者から見たコンテナセキュリティの考え方(CloudNative Days Tokyo 2021 発表資料)
 
NGINXをBFF (Backend for Frontend)として利用した話
NGINXをBFF (Backend for Frontend)として利用した話NGINXをBFF (Backend for Frontend)として利用した話
NGINXをBFF (Backend for Frontend)として利用した話
 
Kubernetesのしくみ やさしく学ぶ 内部構造とアーキテクチャー
Kubernetesのしくみ やさしく学ぶ 内部構造とアーキテクチャーKubernetesのしくみ やさしく学ぶ 内部構造とアーキテクチャー
Kubernetesのしくみ やさしく学ぶ 内部構造とアーキテクチャー
 
[CEDEC 2021] 運用中タイトルでも怖くない! 『メルクストーリア』におけるハイパフォーマンス・ローコストなリアルタイム通信技術の導入事例
[CEDEC 2021] 運用中タイトルでも怖くない! 『メルクストーリア』におけるハイパフォーマンス・ローコストなリアルタイム通信技術の導入事例[CEDEC 2021] 運用中タイトルでも怖くない! 『メルクストーリア』におけるハイパフォーマンス・ローコストなリアルタイム通信技術の導入事例
[CEDEC 2021] 運用中タイトルでも怖くない! 『メルクストーリア』におけるハイパフォーマンス・ローコストなリアルタイム通信技術の導入事例
 
入門 Kubeflow ~Kubernetesで機械学習をはじめるために~ (NTT Tech Conference #4 講演資料)
入門 Kubeflow ~Kubernetesで機械学習をはじめるために~ (NTT Tech Conference #4 講演資料)入門 Kubeflow ~Kubernetesで機械学習をはじめるために~ (NTT Tech Conference #4 講演資料)
入門 Kubeflow ~Kubernetesで機械学習をはじめるために~ (NTT Tech Conference #4 講演資料)
 
Prometheus monitoring from outside of Kubernetes
 〜どうして我々はKubernetes上のPromet...
Prometheus monitoring from outside of Kubernetes
 〜どうして我々はKubernetes上のPromet...Prometheus monitoring from outside of Kubernetes
 〜どうして我々はKubernetes上のPromet...
Prometheus monitoring from outside of Kubernetes
 〜どうして我々はKubernetes上のPromet...
 
マイクロサービスバックエンドAPIのためのRESTとgRPC
マイクロサービスバックエンドAPIのためのRESTとgRPCマイクロサービスバックエンドAPIのためのRESTとgRPC
マイクロサービスバックエンドAPIのためのRESTとgRPC
 
KubernetesのRBACを掘り下げてみる(Kubernetes Novice Tokyo #17 発表資料)
KubernetesのRBACを掘り下げてみる(Kubernetes Novice Tokyo #17 発表資料)KubernetesのRBACを掘り下げてみる(Kubernetes Novice Tokyo #17 発表資料)
KubernetesのRBACを掘り下げてみる(Kubernetes Novice Tokyo #17 発表資料)
 
GKE に飛んでくるトラフィックを 自由自在に操る力 | 第 10 回 Google Cloud INSIDE Games & Apps Online
GKE に飛んでくるトラフィックを 自由自在に操る力 | 第 10 回 Google Cloud INSIDE Games & Apps OnlineGKE に飛んでくるトラフィックを 自由自在に操る力 | 第 10 回 Google Cloud INSIDE Games & Apps Online
GKE に飛んでくるトラフィックを 自由自在に操る力 | 第 10 回 Google Cloud INSIDE Games & Apps Online
 
Kubernetes ControllerをScale-Outさせる方法 / Kubernetes Meetup Tokyo #55
Kubernetes ControllerをScale-Outさせる方法 / Kubernetes Meetup Tokyo #55Kubernetes ControllerをScale-Outさせる方法 / Kubernetes Meetup Tokyo #55
Kubernetes ControllerをScale-Outさせる方法 / Kubernetes Meetup Tokyo #55
 
Linuxにて複数のコマンドを並列実行(同時実行数の制限付き)
Linuxにて複数のコマンドを並列実行(同時実行数の制限付き)Linuxにて複数のコマンドを並列実行(同時実行数の制限付き)
Linuxにて複数のコマンドを並列実行(同時実行数の制限付き)
 
BuildKitによる高速でセキュアなイメージビルド
BuildKitによる高速でセキュアなイメージビルドBuildKitによる高速でセキュアなイメージビルド
BuildKitによる高速でセキュアなイメージビルド
 
eStargzイメージとlazy pullingによる高速なコンテナ起動
eStargzイメージとlazy pullingによる高速なコンテナ起動eStargzイメージとlazy pullingによる高速なコンテナ起動
eStargzイメージとlazy pullingによる高速なコンテナ起動
 
Dockerからcontainerdへの移行
Dockerからcontainerdへの移行Dockerからcontainerdへの移行
Dockerからcontainerdへの移行
 
【CNDT2022】SIerで実践!クラウドネイティブを普及させる取り組み
【CNDT2022】SIerで実践!クラウドネイティブを普及させる取り組み【CNDT2022】SIerで実践!クラウドネイティブを普及させる取り組み
【CNDT2022】SIerで実践!クラウドネイティブを普及させる取り組み
 

Similar to 20220427-k8s-meetup-tokyo.pdf

Japan Container Day 2018
Japan Container Day 2018Japan Container Day 2018
Japan Container Day 2018Yoshio Terada
 
Kubernete Meetup Tokyo #18 - Kubebuilder/controller-runtime 入門
Kubernete Meetup Tokyo #18 - Kubebuilder/controller-runtime 入門Kubernete Meetup Tokyo #18 - Kubebuilder/controller-runtime 入門
Kubernete Meetup Tokyo #18 - Kubebuilder/controller-runtime 入門Preferred Networks
 
BuildKitの概要と最近の機能
BuildKitの概要と最近の機能BuildKitの概要と最近の機能
BuildKitの概要と最近の機能Kohei Tokunaga
 
Kubernetes Meetup Tokyo #23 kubebuilder-v2
Kubernetes Meetup Tokyo #23 kubebuilder-v2Kubernetes Meetup Tokyo #23 kubebuilder-v2
Kubernetes Meetup Tokyo #23 kubebuilder-v2Kazuhito Matsuda
 
Kubernetes Operator for vSphere VM
Kubernetes Operator for vSphere VMKubernetes Operator for vSphere VM
Kubernetes Operator for vSphere VMMasanori Nara
 
Kubernetes Meetup Tokyo #8 Self-hosted Kubernetes を調べてみた
Kubernetes Meetup Tokyo #8 Self-hosted Kubernetes を調べてみたKubernetes Meetup Tokyo #8 Self-hosted Kubernetes を調べてみた
Kubernetes Meetup Tokyo #8 Self-hosted Kubernetes を調べてみたAkihito Inoh
 
CI/CD Pipeline を考える 〜KubeCon 2017 + CyberAgent の最大公倍数〜
CI/CD Pipeline を考える 〜KubeCon 2017 + CyberAgent の最大公倍数〜CI/CD Pipeline を考える 〜KubeCon 2017 + CyberAgent の最大公倍数〜
CI/CD Pipeline を考える 〜KubeCon 2017 + CyberAgent の最大公倍数〜Masaya Aoyama
 
KueCon 2020 NA Recap - Building a Global Supercomputer with Virtual Kubelet /...
KueCon 2020 NA Recap - Building a Global Supercomputer with Virtual Kubelet /...KueCon 2020 NA Recap - Building a Global Supercomputer with Virtual Kubelet /...
KueCon 2020 NA Recap - Building a Global Supercomputer with Virtual Kubelet /...Preferred Networks
 
Kube con + cloudnativecon 2017 社内報告会(外部公開用)
Kube con + cloudnativecon 2017 社内報告会(外部公開用)Kube con + cloudnativecon 2017 社内報告会(外部公開用)
Kube con + cloudnativecon 2017 社内報告会(外部公開用)Masaya Aoyama
 
20190219 hyperledger tokyo_meetup_min_bft
20190219 hyperledger tokyo_meetup_min_bft20190219 hyperledger tokyo_meetup_min_bft
20190219 hyperledger tokyo_meetup_min_bftHyperleger Tokyo Meetup
 
Container Storage Interface のすべて
Container Storage Interface のすべてContainer Storage Interface のすべて
Container Storage Interface のすべて祐司 伊藤
 
[OracleCodeTokyo2019] Kubernetesで実現する運用自動化の新しいアプローチとは
[OracleCodeTokyo2019] Kubernetesで実現する運用自動化の新しいアプローチとは[OracleCodeTokyo2019] Kubernetesで実現する運用自動化の新しいアプローチとは
[OracleCodeTokyo2019] Kubernetesで実現する運用自動化の新しいアプローチとはKoto Shigeru
 
Docker Meetup tpkyo #30 kubecon recap
Docker Meetup tpkyo #30 kubecon recapDocker Meetup tpkyo #30 kubecon recap
Docker Meetup tpkyo #30 kubecon recapYutaro Wada
 
GitLab Auto DevOps with Container CI/CD
GitLab Auto DevOps with Container CI/CDGitLab Auto DevOps with Container CI/CD
GitLab Auto DevOps with Container CI/CDShingo Kitayama
 
Kubernetes Meetup Tokyo #35_GitOps Toolkit による Kubernetes マニフェスト CD
Kubernetes Meetup Tokyo #35_GitOps Toolkit による Kubernetes マニフェスト CDKubernetes Meetup Tokyo #35_GitOps Toolkit による Kubernetes マニフェスト CD
Kubernetes Meetup Tokyo #35_GitOps Toolkit による Kubernetes マニフェスト CDPreferred Networks
 
[Docker Tokyo #35] Docker 20.10
[Docker Tokyo #35] Docker 20.10[Docker Tokyo #35] Docker 20.10
[Docker Tokyo #35] Docker 20.10Akihiro Suda
 
独断と偏見で選んだ Kubernetes 1.24 の注目機能と今後! / Kubernetes Meetup Tokyo 50
独断と偏見で選んだ Kubernetes 1.24 の注目機能と今後! / Kubernetes Meetup Tokyo 50独断と偏見で選んだ Kubernetes 1.24 の注目機能と今後! / Kubernetes Meetup Tokyo 50
独断と偏見で選んだ Kubernetes 1.24 の注目機能と今後! / Kubernetes Meetup Tokyo 50Preferred Networks
 
[External] 2021.12.15 コンテナ移行の前に知っておきたいこと @ gcpug 湘南
[External] 2021.12.15 コンテナ移行の前に知っておきたいこと  @ gcpug 湘南[External] 2021.12.15 コンテナ移行の前に知っておきたいこと  @ gcpug 湘南
[External] 2021.12.15 コンテナ移行の前に知っておきたいこと @ gcpug 湘南Google Cloud Platform - Japan
 
OCHaCafe2#5 変幻自在♪ 広がるKubernetesのエコシステム
OCHaCafe2#5 変幻自在♪ 広がるKubernetesのエコシステムOCHaCafe2#5 変幻自在♪ 広がるKubernetesのエコシステム
OCHaCafe2#5 変幻自在♪ 広がるKubernetesのエコシステムオラクルエンジニア通信
 

Similar to 20220427-k8s-meetup-tokyo.pdf (20)

Japan Container Day 2018
Japan Container Day 2018Japan Container Day 2018
Japan Container Day 2018
 
Kubernete Meetup Tokyo #18 - Kubebuilder/controller-runtime 入門
Kubernete Meetup Tokyo #18 - Kubebuilder/controller-runtime 入門Kubernete Meetup Tokyo #18 - Kubebuilder/controller-runtime 入門
Kubernete Meetup Tokyo #18 - Kubebuilder/controller-runtime 入門
 
BuildKitの概要と最近の機能
BuildKitの概要と最近の機能BuildKitの概要と最近の機能
BuildKitの概要と最近の機能
 
Kubernetes Meetup Tokyo #23 kubebuilder-v2
Kubernetes Meetup Tokyo #23 kubebuilder-v2Kubernetes Meetup Tokyo #23 kubebuilder-v2
Kubernetes Meetup Tokyo #23 kubebuilder-v2
 
Kubernetes Operator for vSphere VM
Kubernetes Operator for vSphere VMKubernetes Operator for vSphere VM
Kubernetes Operator for vSphere VM
 
Kubernetes Meetup Tokyo #8 Self-hosted Kubernetes を調べてみた
Kubernetes Meetup Tokyo #8 Self-hosted Kubernetes を調べてみたKubernetes Meetup Tokyo #8 Self-hosted Kubernetes を調べてみた
Kubernetes Meetup Tokyo #8 Self-hosted Kubernetes を調べてみた
 
Tekton 入門
Tekton 入門Tekton 入門
Tekton 入門
 
CI/CD Pipeline を考える 〜KubeCon 2017 + CyberAgent の最大公倍数〜
CI/CD Pipeline を考える 〜KubeCon 2017 + CyberAgent の最大公倍数〜CI/CD Pipeline を考える 〜KubeCon 2017 + CyberAgent の最大公倍数〜
CI/CD Pipeline を考える 〜KubeCon 2017 + CyberAgent の最大公倍数〜
 
KueCon 2020 NA Recap - Building a Global Supercomputer with Virtual Kubelet /...
KueCon 2020 NA Recap - Building a Global Supercomputer with Virtual Kubelet /...KueCon 2020 NA Recap - Building a Global Supercomputer with Virtual Kubelet /...
KueCon 2020 NA Recap - Building a Global Supercomputer with Virtual Kubelet /...
 
Kube con + cloudnativecon 2017 社内報告会(外部公開用)
Kube con + cloudnativecon 2017 社内報告会(外部公開用)Kube con + cloudnativecon 2017 社内報告会(外部公開用)
Kube con + cloudnativecon 2017 社内報告会(外部公開用)
 
20190219 hyperledger tokyo_meetup_min_bft
20190219 hyperledger tokyo_meetup_min_bft20190219 hyperledger tokyo_meetup_min_bft
20190219 hyperledger tokyo_meetup_min_bft
 
Container Storage Interface のすべて
Container Storage Interface のすべてContainer Storage Interface のすべて
Container Storage Interface のすべて
 
[OracleCodeTokyo2019] Kubernetesで実現する運用自動化の新しいアプローチとは
[OracleCodeTokyo2019] Kubernetesで実現する運用自動化の新しいアプローチとは[OracleCodeTokyo2019] Kubernetesで実現する運用自動化の新しいアプローチとは
[OracleCodeTokyo2019] Kubernetesで実現する運用自動化の新しいアプローチとは
 
Docker Meetup tpkyo #30 kubecon recap
Docker Meetup tpkyo #30 kubecon recapDocker Meetup tpkyo #30 kubecon recap
Docker Meetup tpkyo #30 kubecon recap
 
GitLab Auto DevOps with Container CI/CD
GitLab Auto DevOps with Container CI/CDGitLab Auto DevOps with Container CI/CD
GitLab Auto DevOps with Container CI/CD
 
Kubernetes Meetup Tokyo #35_GitOps Toolkit による Kubernetes マニフェスト CD
Kubernetes Meetup Tokyo #35_GitOps Toolkit による Kubernetes マニフェスト CDKubernetes Meetup Tokyo #35_GitOps Toolkit による Kubernetes マニフェスト CD
Kubernetes Meetup Tokyo #35_GitOps Toolkit による Kubernetes マニフェスト CD
 
[Docker Tokyo #35] Docker 20.10
[Docker Tokyo #35] Docker 20.10[Docker Tokyo #35] Docker 20.10
[Docker Tokyo #35] Docker 20.10
 
独断と偏見で選んだ Kubernetes 1.24 の注目機能と今後! / Kubernetes Meetup Tokyo 50
独断と偏見で選んだ Kubernetes 1.24 の注目機能と今後! / Kubernetes Meetup Tokyo 50独断と偏見で選んだ Kubernetes 1.24 の注目機能と今後! / Kubernetes Meetup Tokyo 50
独断と偏見で選んだ Kubernetes 1.24 の注目機能と今後! / Kubernetes Meetup Tokyo 50
 
[External] 2021.12.15 コンテナ移行の前に知っておきたいこと @ gcpug 湘南
[External] 2021.12.15 コンテナ移行の前に知っておきたいこと  @ gcpug 湘南[External] 2021.12.15 コンテナ移行の前に知っておきたいこと  @ gcpug 湘南
[External] 2021.12.15 コンテナ移行の前に知っておきたいこと @ gcpug 湘南
 
OCHaCafe2#5 変幻自在♪ 広がるKubernetesのエコシステム
OCHaCafe2#5 変幻自在♪ 広がるKubernetesのエコシステムOCHaCafe2#5 変幻自在♪ 広がるKubernetesのエコシステム
OCHaCafe2#5 変幻自在♪ 広がるKubernetesのエコシステム
 

20220427-k8s-meetup-tokyo.pdf

  • 1. K8s Controller Manager & KubeBuilder Deep Dive 2022/4/27 富士通株式会社 石井伴旺 © 2022 Fujitsu Limited Kubernetes Meetup Tokyo #50
  • 2. 本発表の目的 ○ K8sオブジェクトの作成/更新/削除からK8sコントローラがReconcile処理を実行するまでの 間にkube-controller-manager内部でどのような処理が行われているのかを説明します ○ 本発表を通してkube-controller-managerの処理がイメージしやすくなります ○ kube-controller-managerとkubebuilderで作成したコントローラとの間の差異について説 明する kube-controller-managerの分量が多くなってしまったため、割愛させて頂きます ○ 前提知識 ○ K8sのコンポーネント・K8sリソースの役割といった、K8sの知識がある程度ある方を対象としています ○ Goをある程度読める方を想定していますが、図を使っての説明が有るのでGoに不慣れな方でもkube-controller- managerの内部処理の感触がつかめると思います ○ K8s v1.23のコードをベースにしています © 2022 Fujitsu Limited ※スライド内に記載のソースコードのパスはK8sレポジトリrootからのrelative pathです 2
  • 4. K8sクラスタでのkube-controller-managerの役割と概要 ○ Etcdに保存されたK8sオブジェクトの定義に従ってK8sクラスタ内の処理を行う © 2022 Fujitsu Limited kube-apiserver Etcd kube-controller-manager K8sオブジェクト 作成・更新・削除 アプリ ユーザ sharedIndexInformer (Deployment) sharedIndexInformer (ReplicaSet) sharedIndexInformer (Pod) Deploymentコントローラ Worker Worker Worker 処理 work queue Sync Start Sync End Loop ReplicaSetコントローラ YYYコントローラ sharedIndexInformer (XXX) … … K8sオブジェクトの監視(Watch) Dequeue 4
  • 5. kube-controller-manager sharedInformerFactory kube-controller-managerの内部コンポーネント © 2022 Fujitsu Limited kube- apiserver Deployment Controller workqueue worker worker worker … ReplicaSet Controller workqueue worker worker worker … sharedIndexInformer (Deployment) Reflector cache sharedProcessor DeltaFIFO Handler Handler … sharedIndexInformer (ReplicaSet) Reflector cache sharedProcessor DeltaFIFO Handler Handler … … … processListener ReplicaSetをWatch DeploymentをWatch controller controller ※斜体はGoのType名 cacheからK8sオブジェクト取得 ※2 ※2 ※2 コントローラ毎に内部処理の流れやHandler/ workerがcacheを参照するか等が異なる 5
  • 6. kube-controller-manager sharedInformerFactory kube-controller-managerでのK8sオブジェクト処理フロー © 2022 Fujitsu Limited kube- apiserver Deployment Controller workqueue worker worker worker … sharedIndexInformer (Deployment) Reflector cache sharedProcessor DeltaFIFO Handler Handler … … processListener controller ※斜体はGoのType名 Watch cacheからK8sオブジェクト取得 ※2 ※2 コントローラ毎に内部処理の流れやHandler/ workerがcacheを参照するか等が異なる … 6
  • 7. kube-controller-manager sharedInformerFactory kube-controller-managerでのK8sオブジェクト処理フロー © 2022 Fujitsu Limited kube- apiserver Deployment Controller workqueue worker worker worker … sharedIndexInformer (Deployment) Reflector cache sharedProcessor DeltaFIFO Handler Handler … processListener controller ※斜体はGoのType名 API Serverから取得したK8sオブ ジェクトの更新情報(Event)を、 DeltaFIFOにEnqueueする Watch … cacheからK8sオブジェクト取得 ※2 ※2 コントローラ毎に内部処理の流れやHandler/ workerがcacheを参照するか等が異なる … 7
  • 8. kube-controller-manager sharedInformerFactory kube-controller-managerでのK8sオブジェクト処理フロー © 2022 Fujitsu Limited kube- apiserver Deployment Controller workqueue worker worker worker … sharedIndexInformer (Deployment) Reflector cache sharedProcessor DeltaFIFO Handler Handler … processListener controller ※斜体はGoのType名 同じK8sオブジェクトに関連する更 新情報(Event)を、可能な限りまと めて処理できるようにする Watch … cacheからK8sオブジェクト取得 ※2 ※2 コントローラ毎に内部処理の流れやHandler/ workerがcacheを参照するか等が異なる … 8
  • 9. kube-controller-manager sharedInformerFactory kube-controller-managerでのK8sオブジェクト処理フロー © 2022 Fujitsu Limited kube- apiserver Deployment Controller workqueue worker worker worker … sharedIndexInformer (Deployment) Reflector cache sharedProcessor DeltaFIFO Handler Handler … processListener controller ※斜体はGoのType名 Watch … cacheからK8sオブジェクト取得 ※2 ※2 コントローラ毎に内部処理の流れやHandler/ workerがcacheを参照するか等が異なる … 1つのK8sオブジェクトに起きた各Eventに対し ①cacheへの反映 ②次のコンポーネントへの受け渡し の2つ処理を順番に行う 9
  • 10. kube-controller-manager sharedInformerFactory kube-controller-managerでのK8sオブジェクト処理フロー © 2022 Fujitsu Limited kube- apiserver Deployment Controller workqueue worker worker worker … sharedIndexInformer (Deployment) Reflector cache sharedProcessor DeltaFIFO Handler Handler … processListener controller ※斜体はGoのType名 Watch … cacheからK8sオブジェクト取得 ※2 ※2 コントローラ毎に内部処理の流れやHandler/ workerがcacheを参照するか等が異なる … controllerから送られるK8sオブジェクトの Eventのバッファリングと各コントローラの workqueueへのEnqueue 10
  • 11. kube-controller-manager sharedInformerFactory kube-controller-managerでのK8sオブジェクト処理フロー © 2022 Fujitsu Limited kube- apiserver Deployment Controller workqueue worker worker worker … sharedIndexInformer (Deployment) Reflector cache sharedProcessor DeltaFIFO Handler Handler … processListener controller ※斜体はGoのType名 Watch … cacheからK8sオブジェクト取得 ※2 ※2 コントローラ毎に内部処理の流れやHandler/ workerがcacheを参照するか等が異なる … workqueueからK8sオブジェクトの名前を受け取り、 metadata, spec, statusの内容に従い処理 11
  • 12. kube-controller-manager sharedInformerFactory kube-controller-managerでのK8sオブジェクト処理フロー © 2022 Fujitsu Limited kube- apiserver Deployment Controller workqueue worker worker worker … sharedIndexInformer (Deployment) Reflector cache sharedProcessor DeltaFIFO Handler Handler … processListener controller ※斜体はGoのType名 独立したgoroutine Watch … cacheからK8sオブジェクト取得 ※2 ※2 コントローラ毎に内部処理の流れやHandler/ workerがcacheを参照するか等が異なる … 12
  • 13. kube-controller-manager sharedInformerFactory Reflectorについて © 2022 Fujitsu Limited kube- apiserver Deployment Controller workqueue worker worker worker … sharedIndexInformer (Deployment) Reflector cache sharedProcessor DeltaFIFO Handler Handler … processListener controller ※斜体はGoのType名 API Serverから取得したK8sオブ ジェクトの更新情報(Event)を、 DeltaFIFOにEnqueueする Watch … cacheからK8sオブジェクト取得 ※2 ※2 コントローラ毎に内部処理の流れやHandler/ workerがcacheを参照するか等が異なる … 13
  • 14. Reflectorの役割 ○ 「K8s APIサーバから流れてくるK8sリソースのEvent」をDeltaFIFOにエンキューする ○ (例) DeploymentのsharedIndexInformer内のReflectorは、K8sクラスタ内の全Deploymentオブジェクトの各Event をK8s APIサーバから取得・DeltaFIFOにエンキューしている ○ EventはEventTypeとオブジェクト情報から成る ○ オブジェクト情報:Event発生時のEtcd内のオブジェクトデータ ○ EventTypeは3種類 ○ Added K8sクラスタ内で新しいK8sオブジェクトが作成された際に K8s APIサーバから送られる ○ Modified K8sクラスタ内の既存K8sオブジェクトが更新された時に K8s APIサーバから送られる ○ Deleted K8sクラスタ内のK8sオブジェクトが削除された時に K8s APIサーバから送られる © 2022 Fujitsu Limited { "type": "MODIFIED", "object": { "kind": "Deployment", "apiVersion": "apps/v1", "metadata": { "name": “dep1", "namespace": "default", "uid": "6520f999-3691-4402-af4c-d227a2da27bb", … }, "spec": { "replicas": 1, "selector": { … }, … }, "status": {} } } Event発生時にEtcdが 保持している Deployment/dep1データ Event ← EventType K8s API Server Reflector DeltaFIFO Event Type Object watch 14
  • 15. Reflectorのコードについて ○ Reflector作成の契機 ○ Eventの取得とDeltaFIFOへのエンキュー © 2022 Fujitsu Limited type Reflector { name string store Store //DeltaFIFO listWatcher ListWatcher … } *sharedIndexInformer.Run - DeltaFIFOの作成 - K8s APIをWatchする際に使用するlistWatcherの指定 *controller.Run - Reflectorの設定 - Reflectorの作成 *Reflector.Run - listWatcherからのEvent取得 - EventTypeを見てDeltaFIFOへエンキュー 呼出 呼出 func (r *Reflector) watchHandler(…) { … for { select { case event, ok := <-w.ResultChan(): … switch event.Type { case watch.Added: err := r.store.Add(event.Object) case watch.Modified: err := r.store.Update(event.Object) case watch.Deleted: err := r.store.Delete(event.Object) } … Reflector.Runが内部で呼び出すメソッド listWatcherからのEvent取得 EventTypeを見てDeltaFIFOへエンキュー *2 staging/src/k8s.io/client-go/tools/cache/controller.go (*3) (*3) *1 staging/src/k8s.io/client-go/tools/cache/shared_informer.go *3 staging/src/k8s.io/client-go/tools/cache/reflector.go (*1) (*2) (*3) 15
  • 16. kube-controller-manager sharedInformerFactory DeltaFIFOについて © 2022 Fujitsu Limited kube- apiserver Deployment Controller workqueue worker worker worker … sharedIndexInformer (Deployment) Reflector cache sharedProcessor DeltaFIFO Handler Handler … processListener controller ※斜体はGoのType名 同じK8sオブジェクトに関連する更 新情報(Event)を、可能な限りまと めて処理できるようにする Watch … cacheからK8sオブジェクト取得 ※2 ※2 コントローラ毎に内部処理の流れやHandler/ workerがcacheを参照するか等が異なる … 16
  • 17. DeltaFIFOの役割 ○ あるK8sオブジェクトに対する連続したEventをまとめて処理できるようにする ○ 同じオブジェクトに対するEventをDeltaタイプに変換して積み上げ、まとめてデキューする © 2022 Fujitsu Limited Del obj2 Add obj3 Mod obj1 Add obj2 Mod obj1 Add obj1 DeltaFIFO Enqueue Add obj3 Del obj2 Add obj2 Mod obj1 Mod obj1 Add obj1 DeltaFIFO Dequeue Event Delta Deltas ① ② ③ ④ ⑤ ⑥ ① ② ④ ③ ⑥ ⑤ 17
  • 18. DeltaFIFOのコードについて ○ DeltaFIFO作成の契機 ○ DeltaFIFO内部構造 © 2022 Fujitsu Limited type DeltaFIFO struct { items map[string]Deltas queue []string keyFunc KeyFunc … } type Deltas []Delta type Delta struct { Type DeltaType // Added/Updated/Deleted Object interface{} // K8s Object } func (s *sharedIndexInformer) Run(…) { … fifo := NewDeltaFIFOWithOption(DeltaFIFOOptions{ KnownObjects: s.indexer, EmitDelayTypeReplaced: true, }) … Key: K8sオブジェクトの <namespace>/<name> ペア Value: 積み上げたEvent(Deltas) FIFOキューの機能を提供するため、エンキューされたK8sオブジェクトの順番を保持 itemsのKey, queueのelementとして使用している文字列 <namespace>/<name> を K8sオブジェクトから作成する関数 (*DeltaFIFO)のAdd, Update, DeleteメソッドにK8s objectを引数として渡し - DeltaFIFOへのエンキュー - ADDED, MODIFIED, DELETED EventのDeltaデータ型への変換・積み上げ を行う *1 staging/src/k8s.io/client-go/tools/cache/shared_informer.go (*1) *2 staging/src/k8s.io/client-go/tools/cache/delta_fifo.go (*2) (*2) 18
  • 19. kube-controller-manager sharedInformerFactory controllerについて © 2022 Fujitsu Limited kube- apiserver Deployment Controller workqueue worker worker worker … sharedIndexInformer (Deployment) Reflector cache sharedProcessor DeltaFIFO Handler Handler … processListener controller ※斜体はGoのType名 Watch … cacheからK8sオブジェクト取得 ※2 ※2 コントローラ毎に内部処理の流れやHandler/ workerがcacheを参照するか等が異なる … 1つのK8sオブジェクトに起きた各Eventに対し ①cacheへの反映 ②次のコンポーネントへの受け渡し の2つ処理を順番に行う 19
  • 20. ○ DeltaFIFOから取得したK8sオブジェクトの状態をcacheに反映した後、次のコンポーネント (processListener)にK8sオブジェクトの情報(Notification)を渡す ○ DeltaFIFOから取り出したK8sオブジェクトに関連する各Deltaに対しcache反映・processListnerへの引き渡しを行う sharedProcessor controllerの役割 © 2022 Fujitsu Limited Mod Add DeltaFIFO Handler Handler cache ① ② controller processListener Dequeue DeltaFIFOからDequeueした各Deltaに対し以下2つの処理を順番に行う ① 各DeltaのDeltaTypeが ・Added/Updatedのときは、Delta内に保持されているK8sオブジェクトをcacheに保存 ・Deletedのときは、Deltaに紐づいているK8sオブジェクトをcacheから削除 ② Deltaが保持するK8sオブジェクトとcacheが保持しているK8sオブジェクト情報から Notificationというデータを作成し、processListenerに渡す 図の例では、Addに対し①②の処理を行ったあと、Modに対し①②の処理を行う Delta Notification Notification 20
  • 21. controllerのコードについて ○ controller作成・動作契機 ○ controller.processLoopの処理 © 2022 Fujitsu Limited *sharedIndexInformer.Run - controllerの作成 *controller.Run - controller.processLoopを呼び以下実行 * DeltaFIFOからのDequeue * cacheへの更新 * processListenerへのNotification発行 呼出 type Config struct { Queue Process … } func (c *controller) processLoop() { for { obj, err := c.config.Queue.Pop(PopProcessFunc(c.config.Process)) … } type controller struct { config Config … } DeltaFIFO sharedIndexInformer.HandleDeltasメソッドがセットされる 以下の処理をループする DeltaFIFOからDequeueしたDeltasタイプの 変数をsharedIndexInformerの HandleDeltasメソッドに引数として渡す *2 staging/src/k8s.io/client-go/tools/cache/controller.go (*2) (*2) (*2) *1 staging/src/k8s.io/client-go/tools/cache/shared_informer.go (*2) (*1) 21
  • 22. controllerのコードについて ○ controller.processLoopの処理 © 2022 Fujitsu Limited func (c *controller) processLoop() { for { obj, err := c.config.Queue.Pop(PopProcessFunc(c.config.Process)) func (s *sharedIndexInformer) HandleDeltas(obj interface{}) error { … for _, d := range obj.(Deltas) { switch d.Type { case Sync, Replaced, Added, Updated: … if old, exists, err := s.indexer.Get(d.Object); err == nil && exists { if err := s.indexer.Update(d.Object); err != nil { … } … s.processor.distribute(updateNotification{oldObj: old, newObj: d.Object}, isSync) } else { if err := s.indexer.Add(d.Object); err != nil { return err } s.processor.distribute(addNotification{newObj: d.Object}, false) } case Deleted: if err := s.indexer.Delete(d.Object); err != nil { return err } s.processor.distribute(deleteNotification{oldObj: d.Object}, false) sharedIndexInformer.indexerがcache processListenerにNotificationを送る ためにprocessListenerを管理している sharedProcessorのdistributeメソッドを 実行 *1 staging/src/k8s.io/client-go/tools/cache/shared_informer.go (*1) 22
  • 23. controllerのコードについて ○ controller.processLoopでの次のコンポーネント(processListener)にNotificationを送る処理 © 2022 Fujitsu Limited type sharedProcessor struct { listenersStarted bool listenersLock sync.RWMutex listeners []*processorListener syncingListeners []*processorListener clock clock.Clock wg wait.Group } func NewSharedIndexInformer(…) SharedIndexInformer { realClock := &clock.RealClock{} sharedIndexInformer := &sharedIndexInformer{ processor: &sharedProcessor{clock: realClock}, … } return sharedIndexInformer } func (p *sharedProcessor) distribute(obj interface{}, sync bool) { … if sync { … } else { for _, listener := range p.listeners { listener.add(obj) } } } sharedProcessorが管理 しているprocessListener 各processListenerのaddメソッドを呼んで Notification(obj)を渡している *1 staging/src/k8s.io/client-go/tools/cache/reflector.go *2 staging/src/k8s.io/client-go/tools/cache/shared_informer.go (*1) (*2) (*2) 23
  • 24. kube-controller-manager sharedInformerFactory processListenerについて © 2022 Fujitsu Limited kube- apiserver Deployment Controller workqueue worker worker worker … sharedIndexInformer (Deployment) Reflector cache sharedProcessor DeltaFIFO Handler Handler … processListener controller ※斜体はGoのType名 Watch … cacheからK8sオブジェクト取得 ※2 ※2 コントローラ毎に内部処理の流れやHandler/ workerがcacheを参照するか等が異なる … controllerから送られるK8sオブジェクトの Eventのバッファリングと各コントローラの workqueueへのEnqueue 24
  • 25. ○ controllerから渡されるNotificationのバッファリングと、Notificationから各コントローラ が実際に処理するK8sオブジェクトの抽出・コントローラworkqueueへのエンキューを行う sharedProcessor processListenerの役割 © 2022 Fujitsu Limited Handler controllerからのK8sオブジェクトの更新情報 (Notification)をRingBufferでバッファリング • 各コントローラは自身のHandlerを含むprocessListenerを作成し sharedProcessorに登録 • HandlerはNotificationを見て、どのK8sオブジェクトをコントロー ラで処理するか判断し、コントローラのworkqueueに送る processListener Deployment Controller workqueue worker worker worker … cache controller Notification ※ コントローラ毎にコントローラ内部処理の流れや Handler/workerがcacheを参照するか等が異なる 25
  • 26. processListenerのコードについて ○ processListener作成の契機 ○ 各コントローラ作成時に自身のHandlerをsharedIndexInformer.AddEventHandlerを呼んで登録 © 2022 Fujitsu Limited func NewDeploymentController(dInformer appsinformers.DeploymentInformer, …) (*DeploymentController, error) { … dInformer.Informer().AddEventHandler(cache.ResourceEventHandlerFuncs{ AddFunc: dc.addDeployment, UpdateFunc: dc.updateDeployment, DeleteFunc: dc.deleteDeployment, }) func (s *sharedIndexInformer) AddEventHandler(handler ResourceEventHandler) { s.AddEventHandlerWithResyncPeriod(handler, s.defaultEventHandlerResyncPeriod) } … func (s *sharedIndexInformer) AddEventHandlerWithResyncPeriod(handler ResourceEventHandler, …) { … listener := newProcessListener(handler, …) … if !s.started { s.processor.addListener(listener) return } … s.processor.addListener(listener) Deployment sharedIndexInformerにDeployment コントローラが自身のHandlerを登録している箇所 Handler processListenerの作成 processListenerを管理するsharedProcessor に作成したprocessListenerを登録 Notificationからコントローラ で処理するK8sオブジェクト を判断するための処理 - AddFunc: addNotificationを 受け取った際に実行 - UpdateFunc: updateNotificationを 受け取った際に実行 - DeleteFunc: deleteNotificationを 受け取った際に実行 *1 pkg/controller/deployment/deployment_controller.go (*1) *2 staging/src/k8s.io/client-go/tools/cache/shared_informer.go (*2) 26
  • 27. processListenerのコードについて ○ processListenerの動作契機 ○ 受け取ったNotificationのprocessListenerでの処理 © 2022 Fujitsu Limited func (p *sharedProcessor) run(stopCh <-chan struct{}) { func() { … for _, listener := range p.listeners { p.wg.Start(listener.run) p.wg.Start(listener.pop) } … *sharedIndexInformer.Run - processListenerを管理するsharedProcessorをrun *sharedProcessor.run - 管理するprocessListenerのpop・run各メソッドを独立goroutineで実行 - sharedProcessor.run実行後にsharedProcessor.addListenerで追加された processListenerのpop・runメソッドはaddListener実行時に実行される func (p *processorListener) add(notification interface{}) { p.addCh <- notification } func (p *sharedProcessor) distribute(obj interface{}, …) { … for _, listener := range p.listeners { listener.add(obj) } … 呼出 sharedProcessorが管理する各processListenerの run, popメソッドを個別のgoroutineで実行 processListenerは自身のGoチャンネル(addCh)を通して Notificationを受け取る *1 staging/src/k8s.io/client-go/tools/cache/shared_informer.go (*1) (*1) (*1) (*1) (*1) 27
  • 28. processListenerのコードについて ○ processListenerでのNotificationのバッファリング © 2022 Fujitsu Limited func (p *processorListener) pop() { … for { select { case nextCh <- notification: var ok bool notification, ok = p.pendingNotifications.ReadOne() if !ok { // Nothing to pop nextCh = nil // Disable this select case } case notificationToAdd, ok := <-p.addCh: if !ok { return } if notification == nil { notification = notificationToAdd nextCh = p.nextCh } else { // There is already a notification waiting to be dispatched p.pendingNotifications.WriteOne(notificationToAdd) } } } } Notificationの受け取り RingBufferへ受け取ったNotification をエンキュー RingBufferが空の時はバッファを介さず次 の処理(run)にNotificationを渡すようにする RingBufferから受け取ったNotificationを デキュー p.nextCh (Goチャンネル)経由で次の処理 (run)にNotificationを渡す *1 staging/src/k8s.io/client-go/tools/cache/shared_informer.go (*1) 28
  • 29. processListenerのコードについて ○ HandlerへのNotification内 K8sオブジェクトの受け渡し © 2022 Fujitsu Limited func (p *processorListener) run() { … stopCh := make(chan struct{}) wait.Until(func() { for next := range p.nextCh { switch notification := next.(type) { case updateNotification: p.handler.OnUpdate(notification.oldObj, notification.newObj) case addNotification: p.handler.OnAdd(notification.newObj) case deleteNotification: p.handler.OnDelete(notification.oldObj) default: utilruntime.HandleError(fmt.Errorf("unrecognized notification: %T", next)) } } close(stopCh) }, 1*time.Second, stopCh) } popからNotificationの受け取り Notificationの種類に応じて Handler関数に、Notification内 のK8sオブジェクトをわたす *1 staging/src/k8s.io/client-go/tools/cache/shared_informer.go (*1) 29
  • 30. processListenerのコードについて ○ Deployment sharedIndexInformerにDeploymentコントローラが登録したHandlerの処理 © 2022 Fujitsu Limited func NewDeploymentController(dInformer appsinformers.DeploymentInformer, …) (*DeploymentController, error) { … dInformer.Informer().AddEventHandler(cache.ResourceEventHandlerFuncs{ AddFunc: dc.addDeployment, UpdateFunc: dc.updateDeployment, // This will enter the sync loop and no-op, because the deployment has been deleted from the store. DeleteFunc: dc.deleteDeployment, }) func (dc *DeploymentController) addDeployment(obj interface{}) { d := obj.(*apps.Deployment) klog.V(4).InfoS("Adding deployment", "deployment", klog.KObj(d)) dc.enqueueDeployment(d) } func (dc *DeploymentController) enqueue(deployment *apps.Deployment) { key, err := controller.KeyFunc(deployment) … dc.queue.Add(key) } DeploymentControllerのenqueueDeployment フィールドの中身はenqueueメソッド Deploymentコントローラのworkqueueに Keyをエンキュー K8sオブジェクトを一意に識別する文字列(Key) <namespace>/<name> を作成 *1 pkg/controller/deployment/deployment_controller.go (*1) (*1) (*1) 30
  • 31. processListenerのコードについて ○ Pod sharedIndexInformerにReplicaSetコントローラが登録したHandlerの処理 © 2022 Fujitsu Limited func NewBaseController(…, podInformer coreinformers.PodInformer, …) *ReplicaSetController { … podInformer.Informer().AddEventHandler(cache.ResourceEventHandlerFuncs{ AddFunc: rsc.addPod, UpdateFunc: rsc.updatePod, DeleteFunc: rsc.deletePod, }) func (rsc *ReplicaSetController) addPod(obj interface{}) { pod := obj.(*v1.Pod) … if controllerRef := metav1.GetControllerOf(pod); controllerRef != nil { rs := rsc.resolveControllerRef(pod.Namespace, controllerRef) … rsKey, err := controller.KeyFunc(rs) … rsc.queue.Add(rsKey) return } Podに紐づいたReplicaSetの情報を取得 Podと紐づいたReplicaSetの状態を cacheから取得 ReplicaSetコントローラのworkqueueに Keyをエンキュー K8sオブジェクトを一意に識別する文字列(Key) <namespace>/<name> を作成 *1 pkg/controller/replicaset/replica_set.go (*1) (*1) 31
  • 32. kube-controller-manager sharedInformerFactory コントローラについて © 2022 Fujitsu Limited kube- apiserver Deployment Controller workqueue worker worker worker … sharedIndexInformer (Deployment) Reflector cache sharedProcessor DeltaFIFO Handler Handler … processListener controller ※斜体はGoのType名 Watch … cacheからK8sオブジェクト取得 ※2 ※2 コントローラ毎に内部処理の流れやHandler/ workerがcacheを参照するか等が異なる … workqueueからK8sオブジェクトの名前を受け取り、 metadata, spec, statusの内容に従い処理 32
  • 33. コントローラの役割 ○ processListenerから受け取ったトリガーを契機(※)に、K8sオブジェクトのmetadata・ spec・statusに沿って処理を行う © 2022 Fujitsu Limited sharedProcessor Handler Deployment Controller workqueue worker worker worker … ※ コントローラ毎にコントローラ内部処理の流れやHandler/workerのふるまいが異なる processListener sharedProcessor Handler … 各workerは独立した goroutineで動作 多くのHandlerはコントローラが処理するべきK8sオ ブジェクトを表す文字列 <namespace>/<name> をworkqueueにエンキューする 同じK8sオブジェクトが複数の workerで同時に処理されないよう管理 処理 Sync Start Sync End cacheからK8s オブジェクト取得 kube- apiserver K8sオブジェクト 修正 Loop 33
  • 34. コントローラのコードについて ○ コントローラ作成契機 © 2022 Fujitsu Limited main() - cobra Commandを作成し実行 Run(…) - flag・configの適用 - コントローラの作成・実行 func Run(…) error { … saTokenControllerInitFunc := serviceAccountTokenControllerStarter(…) … run := func(…, startSATokenController InitFunc, initializersFunc ControllerInitializersFunc) { … controllerInitializers := initializersFunc(controllerContext.LoopMode) if err := StartControllers(…, startSATokenController, controllerInitializers, …); err != nil { klog.Fatalf("error starting controllers: %v", err) } controllerContext.InformerFactory.Start(stopCh) controllerContext.ObjectOrMetadataInformerFactory.Start(stopCh) close(controllerContext.InformersStarted) select {} } … if !c.ComponentConfig.Generic.LeaderElection.LeaderElect { run(context.TODO(), saTokenControllerInitFunc, NewControllerInitializers) panic("unreachable") } 呼出 ServiceAccountTokentコントローラ生成関数 各種コントローラ生成関数 HA無しController Managerの処理実行 (HA有の場合はさらに下の箇所で処理実行) コントローラ生成関数を実行し コントローラ作成・スタート *1 cmd/kube-controller-manager/controller-manager.go *2 cmd/kube-controller-manager/app/controllermanager.go (*1) (*2) (*2) 34
  • 35. コントローラのコードについて ○ 各コントローラの作成・実行関数 © 2022 Fujitsu Limited func NewControllerInitializers(loopMode ControllerLoopMode) map[string]InitFunc { controllers := map[string]InitFunc{} controllers["endpoint"] = startEndpointController controllers["endpointslice"] = startEndpointSliceController controllers["endpointslicemirroring"] = startEndpointSliceMirroringController controllers["replicationcontroller"] = startReplicationController … controllers["deployment"] = startDeploymentController … func startDeploymentController(…) (controller.Interface, bool, error) { dc, err := deployment.NewDeploymentController( controllerContext.InformerFactory.Apps().V1().Deployments(), controllerContext.InformerFactory.Apps().V1().ReplicaSets(), controllerContext.InformerFactory.Core().V1().Pods(), controllerContext.ClientBuilder.ClientOrDie("deployment-controller"), ) if err != nil { return nil, true, fmt.Errorf("error creating Deployment controller: %v", err) } go dc.Run(ctx, int(controllerContext.ComponentConfig.DeploymentController.ConcurrentDeploymentSyncs)) return nil, true, nil } ServiceAccountTokenコントローラ 以外のコントローラの作成・実行関数 はNewControllerInitializers内にある コントローラの作成 コントローラの実行 *1 cmd/kube-controller-manager/app/controllermanager.go (*1) *2 cmd/kube-controller-manager/app/apps.go (*2) 35
  • 36. コントローラのコードについて ○ Deploymentコントローラの作成 ○ workqueueについて © 2022 Fujitsu Limited func NewDeploymentController(dInformer appsinformers.DeploymentInformer, …) (*DeploymentController, error) { … dc := &DeploymentController{ client: client, eventRecorder: eventBroadcaster.NewRecorder(scheme.Scheme, v1.EventSource{Component: "deployment-controller"}), queue: workqueue.NewNamedRateLimitingQueue(…), } … dInformer.Informer().AddEventHandler(cache.ResourceEventHandlerFuncs{ AddFunc: dc.addDeployment, UpdateFunc: dc.updateDeployment, DeleteFunc: dc.deleteDeployment, }) … type Type struct { queue []t dirty set processing set … } sharedIndexInformerへのHandler登録 workqueueの作成 workqueueの中ではTypeが用いられている ①コントローラで処理する順番を保持 ②コントローラで再度処理しなくてはならない、現在処理中のK8sオブジェクトのKeyを保持 ③コントローラで処理中のK8sオブジェクトのKeyを保持 ① ② ③ *1 pkg/controller/deployment/deployment_controller.go (*1) *2 staging/src/k8s.io/client-go/util/workqueue/queue.go (*2) 36
  • 37. コントローラのコードについて ○ Deploymentコントローラの内部処理 © 2022 Fujitsu Limited func (dc *DeploymentController) Run(…, workers int) { … for i := 0; i < workers; i++ { go wait.UntilWithContext(ctx, dc.worker, …) } … } … func (dc *DeploymentController) worker(ctx context.Context) { for dc.processNextWorkItem(ctx) { } } func (dc *DeploymentController) processNextWorkItem(…) bool { key, quit := dc.queue.Get() … err := dc.syncHandler(ctx, key.(string)) dc.handleErr(err, key) return true } func (dc *DeploymentController) syncDeployment(…, key string) error { namespace, name, err := cache.SplitMetaNamespaceKey(key) … deployment, err := dc.dLister.Deployments(namespace).Get(name) … d := deployment.DeepCopy() … everything := metav1.LabelSelector{} if reflect.DeepEqual(d.Spec.Selector, &everything) { dc.eventRecorder.Eventf(… if d.Status.ObservedGeneration < d.Generation { d.Status.ObservedGeneration = d.Generation dc.client.AppsV1().Deployments(d.Namespace).UpdateStatus(ctx, d, metav1.UpdateOptions{}) } … 独立したgoroutineでworker実行 workqueueからデキューしたKey <namespace>/<name> を処理 メソッドに渡す Keyから処理するDeploymentオブジェクトの Namspace・Nameを取得 cacheからDeploymentオブジェクトを取得 DeploymentオブジェクトのStatusの更新 処理でエラーが出たら workqueueにリキュー *1 pkg/controller/deployment/deployment_controller.go (*1) (*1) (*1) 37
  • 38. kube-controller-manager内の非同期性について ○ コントローラ処理の契機となったK8sオブジェクトとキャッシュ内部のオブジェクトのずれ ○ キャッシュ参照時に更新されたオブジェクトを見たり、契機となったオブジェクトが更新されている可能性がある © 2022 Fujitsu Limited sharedInformerFactory kube- apiserver Deployment Controller workqueue worker worker worker … ReplicaSet Controller workqueue worker worker worker … sharedIndexInformer (Deployment) Reflector cache sharedProcessor DeltaFIFO Handler Handler … sharedIndexInformer (ReplicaSet) Reflector cache sharedProcessor DeltaFIFO Handler Handler … processListener ReplicaSetをWatch DeploymentをWatch controller controller cacheからK8sオブジェクト取得 obj2 obj2’ obj1 obj1’ kube-controller-manager 38
  • 39. 各コントローラのコードについて kube-controller-managerが管理する各コントローラの内部構造はコントローラ毎に異なる ○ workqueue ○ エンキュー契機 ○ K8sオブジェクトの変更をReflectorが通知し、Handlerが処理するK8sオブジェクトのKeyをエンキューする ○ 一定時間ごとにkube-apiserverからK8sオブジェクトを取得し、処理するオブジェクトのKeyをエンキュー ○ workqueueが無く、コントローラ内部で一定時間ごとにkube-apiserverからオブジェクトを取得 ○ workqueueの数・実装 ○ 一つのコントローラ内に複数種類のworkqueueがある ○ GoチャンネルやGo mapを用いてworkqueueを実装している ○ <namespace>/<name> の文字列(Key)ではなく、K8sオブジェクト自体をworkqueueにエンキュー ○ コントローラの処理 ○ cacheだけでなくkube-spiserverからK8sオブジェクトを取得し、metadata・spec・statusに従って処理 ○ 複数個の種類の異なる処理フローが別々のgoroutineで動作している ○ processListenerを動的に作成し、sharedProcessorに登録 © 2022 Fujitsu Limited 39
  • 40. Thank you © 2022 Fujitsu Limited