3.3.3 Controller
Controller是 Controller-runtime的核心结构, 其实现了 Controller的基本逻辑:Controller管理一个工作队列,并从 source.Sources中获取 reconcile.Requests加入队列,通过执行 reconcile.Reconciler来处理队列中的每项 reconcile.Requests,而 reconcile.
Reconciler可以通过读写 Kubernetes 资源来确保集群状态与期望状态一致。
接口:
Controller接口定义在 pkg/controller/controller.go下,包括如下内容。
(1) reconcile.Reconciler:匿名接口,定义了 Reconcile(context.Context,Request)
(Result,error)。
(2) Watch(srcsource.Source,eventhandlerhandler.EventHandler,predicates
...predicate.Predicate)error:定义入队 reconcile.Requests,Watch() 方法会从 sour-ce.Source中获取Event, 并根据参数 Eventhandler来决定如何入队, 根据参数Predicates进行 Event过滤,Preficates可能有多个, 只有所有的 Preficates都返回True 时,才会将 Event 发送给 Eventhandler 处理。
(3) Start(ctxcontext.Context)error:Controller的启动方法,实现了 Controller接口的对象,也实现了Runnable,因此,该方法可以被Manager管理。
(4) GetLogger()logr.Logger:获取 Controller内的 Logger,用于日志输出。
实现:
Controller的实现在 pkg/internal/controller/controller.go下,为结构体 Controller,Controller结构体中包括的主要成员如下。
(1) Namestring:必须设置, 用于标识 Controller,会在 Controller的日志输出中进行关联。
(2) MaxConcurrentReconcilesint:定义允许 reconcile.Reconciler 同时运行的最多个数,默认为 1。
(3) Doreconcile.Reconciler:定义了 Reconcile() 方法,包含了 Controller同步的业务逻辑。Reconcile()能在任意时刻被调用,接收一个对象的 Name与 Namespace,并同步集群当前实际状态至该对象被设置的期望状态。
(4) MakeQueue func() workqueue.RateLimitingInterface:用 于在 Controller启动时,创建工作队列。由于标准的Kubernetes工作队列创建后会立即启动,因此,如果在 Controller启动前就创建队列,在重复调用 controller.New() 方法创建 Con-troller 的情况下,就会导致 Goroutine 泄露。
(5) Queueworkqueue.RateLimitingInterface:使用上面方法创建的工作队列。
(6) SetFieldsfunc(iinterface{})error:用 于 从 Manager中 获 取 Controller依赖的方法, 依赖包括 Sourcess、EventHandlers和 Predicates等。 此方法存储的是controllerManager.SetFields()方法。
(7) StartedBool:用于表示Controller 是否已经启动。
(8) CacheSyncTimeouttime.Duration:定义了 Cache 完成同步的等待时长,超过时长会被认为是同步失败。默认时长为 2分钟。
(9) startWatches[ ]watchDescription:定 义 了 一 组Watch操 作 的 属 性, 会在Controller启动时, 根据属性进行 Watch操作。watchDescription的定义见代码 清单3-30,watchDescription包括 Event的源 source.Source、Event的入队方法handler.EventHandler以及 Event的过滤方法 predicate.Predicate。
typewatchDescriptionstruct{srcsource.Source
handlerhandler.EventHandlerpredicates[]predicate.Predicate
}
(10) LogLogr.Logger:用于记录日志的日志对象。
Controller的主要逻辑在Controller.Start()方法内,流程如图 3-4所示。
图 3—4Controiier 逻辑
(1) 在Manager调用 Start()方法后,进入 Controller 的启动流程,经过选举等预处理后,Controller进入Start()方法。
(2) Controller根据 MakeQueue() 创建工作队列,并启动工作队列。
(3) Controller根据 startWatches参数启动各个 Watch 流程,并将工作队列注入各个Watcher中。
(4) Controller根据 MaxConcurrentReconciles启动多个 Worker程序,用于处理队列中的对象。
(5) Work程序先从工作队列中获取需要处理的对象,然后调用 Controller成员 Do的 Reconcile()方法进行处理。
(6) 根据 Reconcile() 方法返回的结果, 将对象重新入队列或从队列中删除。重新入队列的方法可以是带有一定延迟的Queue.AddAfter(), 也可以是有限速的 Queue.AddRateLimited()。重新加入的次数无限制。