導(dǎo)讀:上一篇blog主要是簡單介紹了一下kubebuilder的使用,這里再分析一下kubebuilder的代碼邏輯。
1.kubebuilder的基礎(chǔ):controller
首先介紹一下k8s的一個(gè)controller的邏輯,下圖主要參考client-go給的一個(gè)workQueue的例子:

這里我把代碼分為通用的Common part和Special Part。前者是client-go的基本流程,而后者部分是controller自身邏輯部分。具體過程包含8個(gè)步驟:
1.Reflector通過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ì)再通過client去更新這個(gè)object。
上面這個(gè)具體過程,我看網(wǎng)上大佬們也都分析過很多次了,但是根據(jù)我的經(jīng)驗(yàn)?zāi)兀€是需要去看一遍代碼心里才有底。以后出問題或者二次開發(fā)的時(shí)候,都是需要知道重要的結(jié)構(gòu)體和API的。
2.kubebuilder的封裝
想說明一下kubebuilder實(shí)際上是提供了對(duì)client-go進(jìn)行封裝的library(準(zhǔn)確來說是runtime-controller),更加便利我們來開發(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來管理這些controller,所以每個(gè)controller還是擁有其獨(dú)立的workQueue,deltaFIFO,并且kubebuilder也已經(jīng)幫我們實(shí)現(xiàn)了這部分代碼; - 我們主要需要做的開發(fā),就是寫
Reconcile中的邏輯。
1.Manager通過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è)例子再來分析這個(gè)文件。
3.小結(jié)
寫這篇blog本來想講一下kubebuilder的代碼流程的,但是發(fā)現(xiàn)要理解kubebuilder必須先理解client-go,基本上client-go代碼熟悉之后再來分析kubebuilder就easy了...我自己太笨了,花了很多時(shí)間去啃client-go,假期余額緊張,所以關(guān)于kubebuilder自身的分析就沒寫太多了,有時(shí)間再補(bǔ)充吧。網(wǎng)上有一篇關(guān)于kubebuilder的分析,有興趣的同學(xué)可以參考一下吧,但是我覺得做二次開發(fā)一定要看自己親自看和分析一遍。