3.2.3 Client初始化
实现 Controller 时,不可避免地需要对某些资源类型进行创建、删除、更新和查询,这些操作就是通过Client实现的,查询功能实际查询的是本地的 Cache,写操作是直接访问 APIServer。Client是进行初始化的过程见代码清单 3-11。
//ctrl.NewManager⽤于创建 Manager,在创建Manager的过程中会初始化相应的Client
mgr,err:=ctrl.NewManager(ctrl.GetConfigOrDie(),ctrl.Options{
Scheme: scheme,
MetricsBindAddress: metricsAddr,Port: 9443,
HealthProbeBindAddress:probeAddr,LeaderElection: enableLeaderElection,LeaderElectionID: "8bf23ea1.my.domain",
})
//...
iferr=(&controllers.GuestbookReconciler{
//将 Manager的 Client传给Controller,
//并且调⽤SetupWithManager⽅法传⼊Manager进⾏ Controller的初始化
Client:mgr.GetClient(),
Log:ctrl.Log.WithName("controllers").WithName("Guestbook"),Scheme:mgr.GetScheme(),
}).SetupWithManager(mgr);err!=nil{
setupLog.Error(err,"unabletocreatecontroller","controller","Guestbook")
os.Exit(1)
}
在 Manager初始化过程中创建 Client,见代码清单 3-12。
funcNew(config*rest.Config,optionsOptions)(Manager,error){
//...
//如果⽤户没有指定⾃⼰⽤的Client,那么在 setOptionsDefaults函数中会创建
//默认的Client
options=setOptionsDefaults(options)
//...
//创建Cache⽤于Client读操作
cache,err:=options.NewCache(config,cache.Options{Scheme:options.Scheme,
Mapper:mapper,Resync:options.SyncPeriod,Namespace:options.Namespace})
//...
clientOptions:=client.Options{Scheme:options.Scheme,Mapper:mapper}
apiReader,err:=client.New(config,clientOptions)
iferr!=nil{
returnnil,err
}
//初始化⽤于写操作的Client
writeObj,err:=options.ClientBuilder.
WithUncached(options.ClientDisableCacheFor...).Build(cache,config,clientOptions)
iferr!=nil{
returnnil,err
}
//dryRun模式
ifoptions.DryRunClient{
writeObj=client.NewDryRunClient(writeObj)
}
}
初始化默认的 Client,见代码清单 3-13。
funcsetOptionsDefaults(optionsOptions)Options{
//...
//如果⽤户没有指定Client,那么创建默认的 Client
ifoptions.ClientBuilder==nil{options.ClientBuilder=NewClientBuilder()
}
//如果⽤户没有指定Cache,那么创建默认的 Cache
ifoptions.NewCache==nil{options.NewCache=cache.New
}
//...
}
Manager 启动的入口函数一般在 main() 函数中,具体见代码清单 3-14。
setupLog.Info("startingmanager")
if err:=mgr.Start(ctrl.SetupSignalHandler());err!=nil{setupLog.Error(err,"problemrunningmanager")os.Exit(1)
}
MGR的类型是一个Interface,底层实际上调用的是 controllerManager的Start方法。Start方法的主要逻辑就是启动 Cache、Controller,将整个事件流运转起来。
代码清单 3-15展示了启动逻辑。
func(cm*controllerManager)Start(ctxcontext.Context)(errerror){
...
//根据是否需要选举来选择启动⽅式
gocm.startNonLeaderElectionRunnables()gofunc(){
ifcm.resourceLock!=nil{
err:=cm.startLeaderElection()iferr!=nil{
cm.errChan<-err
}
}else{
close(cm.elected)
gocm.startLeaderElectionRunnables()
}
}()
..
}
选举和非选举方式的启动逻辑类似,都是先初始化Cache,再启动 Controller,见代码清单 3-16。
func(cm*controllerManager)startNonLeaderElectionRunnables(){cm.mu.Lock()
defercm.mu.Unlock()
//启动Cache
cm.waitForCache(cm.internalCtx)
//启动Controller
for_,c:=rangecm.nonLeaderElectionRunnables{cm.startRunnable(c)
}
}