導(dǎo)讀:上一篇blog主要是簡(jiǎn)單介紹了一下kubebuilder的使用,這里再分析一下kubebuilder的代碼邏輯娄徊。
1.kubebuilder的基礎(chǔ):controller
首先介紹一下k8s的一個(gè)controller的邏輯考余,下圖主要參考client-go給的一個(gè)workQueue的例子:
這里我把代碼分為通用的Common part和Special Part。前者是client-go的基本流程,而后者部分是controller自身邏輯部分蔽午。具體過(guò)程包含8個(gè)步驟:
1.Reflector通過(guò)ListAndWatch
方法去監(jiān)聽指定的Object;
func (r *Reflector) Run(stopCh <-chan struct{}) {
klog.V(3).Infof("Starting reflector %v (%s) from %s", r.expectedTypeName, r.resyncPeriod, r.name)
wait.Until(func() {
if err := r.ListAndWatch(stopCh); err != nil {
utilruntime.HandleError(err)
}
}, r.period, stopCh)
}
2.Reflector會(huì)將所監(jiān)聽到的event酬蹋,包括對(duì)object的Add
及老,Update
,Delete
的操作push到DeltaFIFO這個(gè)queue中范抓;
3.Informer首先會(huì)解析event中的action和object骄恶;
4.Informer將解析的object更新到local store,也就是本地cache中的數(shù)據(jù)更新匕垫;
5.然后Informer會(huì)執(zhí)行Controller在初始化Infromer時(shí)注冊(cè)的ResourceEventHandler(這些callback是可以自己修改的)僧鲁;
6.ResourceEventHandler中注冊(cè)的callback會(huì)將對(duì)應(yīng)變化的object的key存入其初始化的一個(gè)workQueue;
7.最終controller會(huì)循環(huán)進(jìn)行reconcile象泵,就是從workQueue不停地pop key寞秃,然后去local store中取到對(duì)應(yīng)的object,然后進(jìn)行處理单芜,最終多數(shù)情況會(huì)再通過(guò)client去更新這個(gè)object蜕该。
上面這個(gè)具體過(guò)程,我看網(wǎng)上大佬們也都分析過(guò)很多次了洲鸠,但是根據(jù)我的經(jīng)驗(yàn)?zāi)靥玫€是需要去看一遍代碼心里才有底。以后出問(wèn)題或者二次開發(fā)的時(shí)候扒腕,都是需要知道重要的結(jié)構(gòu)體和API的绢淀。
2.kubebuilder的封裝
想說(shuō)明一下kubebuilder實(shí)際上是提供了對(duì)client-go進(jìn)行封裝的library(準(zhǔn)確來(lái)說(shuō)是runtime-controller),更加便利我們來(lái)開發(fā)k8s的operator瘾腰。
我上面提到的workQueue的例子已經(jīng)實(shí)現(xiàn)了一個(gè)controller的邏輯皆的。而kubebuilder還幫我們做了以下的額外工作:
- kubebuilder引入了manager這個(gè)概念,一個(gè)manager可以管理多個(gè)controller蹋盆,而這些controller會(huì)共享manager的client费薄;
- 如果manager掛掉或者停止了硝全,所有的controller也會(huì)隨之停止;
- kubebuilder使用一個(gè)
map[GroupVersionKind]informer
來(lái)管理這些controller楞抡,所以每個(gè)controller還是擁有其獨(dú)立的workQueue伟众,deltaFIFO,并且kubebuilder也已經(jīng)幫我們實(shí)現(xiàn)了這部分代碼召廷; - 我們主要需要做的開發(fā)凳厢,就是寫
Reconcile
中的邏輯。
1.Manager通過(guò)map[GroupVersionKind]informer
啟動(dòng)所有controller:
func (ip *specificInformersMap) Start(stop <-chan struct{}) {
...
for _, informer := range ip.informersByGVK {
go informer.Informer.Run(stop)
}
...
<-stop
}
2.Controller處理event的邏輯都在https://github.com/kubernetes-sigs/controller-runtime/blob/master/pkg/internal/controller/controller.go這個(gè)文件里面竞慢,其實(shí)它就是實(shí)現(xiàn)了workqueue這個(gè)例子的大部分代碼先紫,推薦先看懂這個(gè)例子再來(lái)分析這個(gè)文件。
3.小結(jié)
寫這篇blog本來(lái)想講一下kubebuilder的代碼流程的筹煮,但是發(fā)現(xiàn)要理解kubebuilder必須先理解client-go遮精,基本上client-go代碼熟悉之后再來(lái)分析kubebuilder就easy了...我自己太笨了,花了很多時(shí)間去啃client-go寺谤,假期余額緊張仑鸥,所以關(guān)于kubebuilder自身的分析就沒(méi)寫太多了吮播,有時(shí)間再補(bǔ)充吧变屁。網(wǎng)上有一篇關(guān)于kubebuilder的分析,有興趣的同學(xué)可以參考一下吧意狠,但是我覺得做二次開發(fā)一定要看自己親自看和分析一遍粟关。