🚀 优质资源分享 🚀
学习路线指引(点击解锁) | 知识定位 | 人群定位 |
---|---|---|
🧡 Python实战微信订餐小程序 🧡 | 进阶级 | 本课程是python flask+微信小程序的完美结合,从项目搭建到腾讯云部署上线,打造一个全栈订餐系统。 |
💛Python量化交易实战💛 | 入门级 | 手把手带你打造一个易扩展、更安全、效率更高的量化交易系统 |
Overview
controller-runtime 是 Kubernetes 社区提供可供快速搭建一套 实现了controller 功能的工具,无需自行实现Controller的功能了;在 Kubebuilder
与 Operator SDK
也是使用 controller-runtime
。本文将对 controller-runtime
的工作原理以及在不同场景下的使用方式进行简要的总结和介绍。
controller-runtime structure
controller-runtime
主要组成是需要用户创建的 Manager
和 Reconciler
以及 Controller Runtime
自己启动的 Cache
和 Controller
。
- Manager:是用户在初始化时创建的,用于启动
Controller Runtime
组件 - Reconciler:是用户需要提供来处理自己的业务逻辑的组件(即在通过
code-generator
生成的api-like而实现的controller中的业务处理部分)。 - Cache:一个缓存,用来建立
Informer
到ApiServer
的连接来监听资源并将被监听的对象推送到queue中。 - Controller: 一方面向 Informer 注册
eventHandler
,另一方面从队列中获取数据。controller 将从队列中获取数据并执行用户自定义的Reconciler
功能。
图:controller-runtime structure
图:controller-runtime flowchart
由图可知,Controller会向 Informer 注册一些列eventHandler;然后Cache启动Informer(informer属于cache包中),与ApiServer建立监听;当Informer检测到资源变化时,将对象加入queue,Controller 将元素取出并在用户端执行 Reconciler。
Controller引入
我们从 controller-rumtime项目的 example 进行引入看下,整个架构都是如何实现的。
可以看到 example 下的实际上实现了一个 reconciler
的结构体,实现了 Reconciler
抽象和 Client
结构体
type reconciler struct {
client.Client
scheme *runtime.Scheme
}
那么来看下 抽象的 Reconciler 是什么,可以看到就是抽象了 Reconcile
方法,这个是具体处理的逻辑过程
type Reconciler interface {
Reconcile(context.Context, Request) (Result, error)
}
下面在看下谁来实现了这个 Reconciler 抽象
type Controller interface {
reconcile.Reconciler // 协调的具体步骤,通过ns/name\
// 通过predicates来评估来源数据,并加入queue中(放入队列的是reconcile.Requests)
Watch(src source.Source, eventhandler handler.EventHandler, predicates ...predicate.Predicate) error
// 启动controller,类似于自定义的Run()
Start(ctx context.Context) error
GetLogger() logr.Logger
}
controller structure
在 controller-runtime\pkg\internal\controller\controller.go 中实现了这个 Controller
type Controller struct {
Name string // controller的标识
MaxConcurrentReconciles int // 并发运行Reconciler的数量,默认1
// 实现了reconcile.Reconciler的调节器, 默认DefaultReconcileFunc
Do reconcile.Reconciler
// makeQueue会构建一个对应的队列,就是返回一个限速队列
MakeQueue func() workqueue.RateLimitingInterface
// MakeQueue创造出来的,在出入队列就是操作的这个
Queue workqueue.RateLimitingInterface
// 用于注入其他内容
// 已弃用
SetFields func(i interface{}) error
mu sync.Mutex
// 标识开始的状态
Started bool
// 在启动时传递的上下文,用于停止控制器
ctx context.Context
// 等待缓存同步的时间 默认2分钟
CacheSyncTimeout time.Duration
// 维护了eventHandler predicates,在控制器启动时启动
startWatches []watchDescription
// 日志构建器,输出入日志
LogConstructor func(request *reconcile.Request) logr.Logger
// RecoverPanic为是否对reconcile引起的panic恢复
RecoverPanic bool
}
看完了controller的structure,接下来看看controller是如何使用的
injection
Controller.Watch 实现了注入的动作,可以看到 watch()
通过参数将 对应的事件函数传入到内部
func (c *Controller) Watch(src source.Source, evthdler handler.EventHandler, prct ...predicate.Predicate) error {
c.mu.Lock()
defer c.mu.Unlock()
// 使用SetFields来完成注入操作
if err := c.SetFields(src); err != nil {
return err
}
if err := c.SetFields(evthdler); err != nil {
return err
}
for _, pr := range prct {
if err := c.SetFields(pr); err != nil {
return err
}
}
// 如果Controller还未启动,那么将这些动作缓存到本地
if !c.Started {
c.startWatches = append(c.startWatches, watchDescription{src: src, handler: evthdler, predicates: prct})
return nil
}
c.LogConstructor(nil).Info("Starting EventSource", "source", src)
return src.Start(c.ctx, evthdler, c.Queue, prct...)
}
启动操作实际上为informer注入事件函数
type Source interface {
// start 是Controller 调用,用以向 Informer 注册 EventHandler, 将 reconcile.Requests(一个入队列的动作) 排入队列。
Start(context.Context, handler.EventHandler, workqueue.RateLimitingInterface, ...predicate.Predicate) error
}
func (is *Informer) Start(ctx context.Context, handler handler.EventHandler, queue workqueue.RateLimitingInterface,
prct ...predicate.Predicate) error {
// Informer should have been specified by the user.
if is.Informer == nil {
return fmt.Errorf("must specify Informer.Informer")
}
is.Informer.AddEventHandler(internal.EventHandler{Queue: queue, EventHandle