kubebuilder 学习笔记(1)-- controller

controller用于将给定对象的实际状态和期望状态相匹配,每个controller专注于一个kind(kubebuiler中由于For的Forinput只能放一个obj,实际在底层controller中可以watch多个)。具体的办法是通过使用workqueue的方式缓存informer传递过来的对象,后续提取workqueue中的对象,传递给Reconciler进行处理。

builder

在kubebuilder中controller.go主要用于返回一个builder对象,即controller,结构体定义如下。

// Builder builds a Controller.
type Builder struct {
	forInput         ForInput
	forInput        []OwnsInput
	watchesInput     []WatchesInput
	mgr              manager.Manager
	globalPredicates []predicate.Predicate
	config           *rest.Config
	ctrl             controller.Controller
	ctrlOptions      controller.Options
	log              logr.Logger
	name             string
}

forInput forInput owsInput是dowatch和docontroller时候的对象,globalPredicates是predicate的范围,mgr是manager,ctrl是controller对象,ctrloption,log,name

For watches owns

kubebuilder中Forinput的结构体,在dowatch和docontroller被使用。

type ForInput struct {
	object           runtime.Object
	predicates       []predicat⁄e.Predicate
	objectProjection objectProjection
}

forinput在For方法中被使用,For需要提供runtime的object来使用,方法主要用于填充forinput。

func (blder *Builder) For(object runtime.Object, opts ...ForOption) *Builder {
	input := ForInput{object: object}
	for _, opt := range opts {
		opt.ApplyToFor(&input)
	}

	blder.forInput = input
	return blder
}

watches和owns是差不多的,都是要实现watch,现在仅使用for。

withconfig withEventFilter withOptions Named

提供config(不再使用).
wef提供过滤的event,event包括update delete create ge事件,可以通过过滤时间决定reconcile逻辑,填充predicate。
wo提供option。,option包括MaxConcurrentReconciles(是可以运行的最大并发 Reconciles 数量。默认为 1),reconcile, RateLimiter(用于限制请求排队的频率)。
Named提供name。

func (blder *Builder) WithConfig(config *rest.Config) *Builder {
	blder.config = config
	return blder
}

func (blder *Builder) WithEventFilter(p predicate.Predicate) *Builder {
	blder.globalPredicates = append(blder.globalPredicates, p)
	return blder
}

func (blder *Builder) WithOptions(options controller.Options) *Builder {
	blder.ctrlOptions = options
	return blder
}

complete 实现build方法. 完成应用程序的构建 ControllerManagedBy.

func (blder *Builder) Complete(r reconcile.Reconciler) error {
	_, err := blder.Build(r)
	return err
}

Build

主要完成 docontroller和dowatch。且确保提供mgr和reconciler,以及config(没有提供时,从mgr拿–mgr.GetConfig())

docontroller

  1. 拿ctrlOption(没有提供reconciler时赋值r)
  2. 通过forinput的obj和mgr的scheme拿gvk
  3. log
  4. 做new controller,需要mgr/option/controllername(name或用kind命名)
func (blder *Builder) doController(r reconcile.Reconciler) error {
	ctrlOptions := blder.ctrlOptions
	if ctrlOptions.Reconciler == nil {
		ctrlOptions.Reconciler = r
	}

	// Retrieve the GVK from the object we're reconciling
	// to prepopulate logger information, and to optionally generate a default name.
	gvk, err := getGvk(blder.forInput.object, blder.mgr.GetScheme())
	if err != nil {
		return err
	}

	// Setup the logger.
	if ctrlOptions.Log == nil {
		ctrlOptions.Log = blder.mgr.GetLogger()
	}
	ctrlOptions.Log = ctrlOptions.Log.WithValues("reconcilerGroup", gvk.Group, "reconcilerKind", gvk.Kind)

	// Build the controller and return.
	blder.ctrl, err = newController(blder.getControllerName(gvk), blder.mgr, ctrlOptions)
	return err
}

docontroller后拿到有ctrl的builder。

dowatch

仅放了for的部分,因为controller只放了forinput。

  1. project放置对象,如果没有设置foroption,则直接放给的runtimeobj
  2. src利用obj拿到
  3. 建立一个handler.EnqueueRequestForObject{}(queue)
  4. allPredicates利用event过滤后拿到。
  5. 做watch(Watch(src, hdler, allPredicates…))
func (blder *Builder) doWatch() error {
	// Reconcile type
	typeForSrc, err := blder.project(blder.forInput.object, blder.forInput.objectProjection)
	if err != nil {
		return err
	}
	src := &source.Kind{Type: typeForSrc}
	hdler := &handler.EnqueueRequestForObject{}
	allPredicates := append(blder.globalPredicates, blder.forInput.predicates...)
	if err := blder.ctrl.Watch(src, hdler, allPredicates...); err != nil {
		return err
	}

使用流程

  1. new reconciler(build和docontroller时使用)
  2. new mgr(通过cfg和managerOpt拿到,用于)
  3. NewControllerManageredBy(mgr)
  4. For(watch筛选)
  5. with…(predicate)
  6. Complete(Builder返回)
func (r *CrsReconciler) SetupWithManager(mgr ctrl.Manager) (err error) {

	p := predicate.Funcs{
		CreateFunc: func(e event.CreateEvent) bool {
			...
		},
		GenericFunc: func(e event.GenericEvent) bool {
			...
		},
		...
	}

	cr := &unstructured.Unstructured{} // runtimeobject
	err = ctrl.NewControllerManagedBy(mgr).
		// Watches(&source.Kind{Type: cr}, &handler.EnqueueRequestForObject{}).
		For(&metav1.Pod{}). //
		WithEventFilter(&p).
		Named("testName").
		Complete(r)
	return
}

实际流程:

  1. new controller(DC)
  2. add mgr(DC)
  3. watch (DW)

底层ctrl的实现逻辑

  1. New mgr/reconciler
  2. New ctrl(提供mgr/options<–reconciler) <-- 实现了填充以及add to mgr
  3. 实现Watch (提供obj hdler predicate)和start(chan)

mgr的意义:

  1. 拿scheme(GVK)/cfg/Log
  2. add ctrl to mgr

reconciler的意义:

  1. 注册到ctrl op的r --> reconcile实现抓取状态更新后的逻辑

ctrl struct

// Controller implements controller.Controller
type Controller struct {
	// Name is used to uniquely identify a Controller in tracing, logging and monitoring.  Name is required.
	Name string

	// MaxConcurrentReconciles is the maximum number of concurrent Reconciles which can be run. Defaults to 1.
	MaxConcurrentReconciles int

	// Reconciler is a function that can be called at any time with the Name / Namespace of an object and
	// ensures that the state of the system matches the state specified in the object.
	// Defaults to the DefaultReconcileFunc.
	Do reconcile.Reconciler

	// MakeQueue constructs the queue for this controller once the controller is ready to start.
	// This exists because the standard Kubernetes workqueues start themselves immediately, which
	// leads to goroutine leaks if something calls controller.New repeatedly.
	MakeQueue func() workqueue.RateLimitingInterface

	// Queue is an listeningQueue that listens for events from Informers and adds object keys to
	// the Queue for processing
	Queue workqueue.RateLimitingInterface

	// SetFields is used to inject dependencies into other objects such as Sources, EventHandlers and Predicates
	SetFields func(i interface{}) error

	// mu is used to synchronize Controller setup
	mu sync.Mutex

	// JitterPeriod allows tests to reduce the JitterPeriod so they complete faster
	JitterPeriod time.Duration

	// Started is true if the Controller has been Started
	Started bool

	// TODO(community): Consider initializing a logger with the Controller Name as the tag

	// startWatches maintains a list of sources, handlers, and predicates to start when the controller is started.
	startWatches []watchDescription

	// Log is used to log messages to users during reconciliation, or for example when a watch is started.
	Log logr.Logger
}

ctrl.watch

// Watch implements controller.Controller
func (c *Controller) Watch(src source.Source, evthdler handler.EventHandler, prct ...predicate.Predicate) error {
	c.mu.Lock()
	defer c.mu.Unlock()

	// Inject Cache into arguments
	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 hasn't started yet, store the watches locally and return.
	//
	// These watches are going to be held on the controller struct until the manager or user calls Start(...).
	if !c.Started {
		c.startWatches = append(c.startWatches, watchDescription{src: src, handler: evthdler, predicates: prct})
		return nil
	}

	c.Log.Info("Starting EventSource", "source", src)
	return src.Start(evthdler, c.Queue, prct...)
}
  1. c.setFields(src/evthdler/pr)
  2. watch many before start(appen startwatches)

kubebuilder operator的运行逻辑
watch:

调用了src.Start(src的类型为 source.Kind),将evthdler(&handler.EnqueueRequestForObject{})、c.Qeueue关联起来(c.Qeueue为Reconciler提供参数)。在Kind.Start 中会根据ks.Type选择合适的informer,并添加事件管理器internal.EventHandler:

在Manager初始化时(如未指定)默认会创建一个Cache,该Cache中保存了gvk到cache.SharedIndexInformer 的映射关系,ks.cache.GetInformer 中会提取对象的gvk信息,并根据gvk获取informer。
在Manager.Start的时候会启动Cache中的informer。

informer.AddEventHandler

kubebuilder 进阶使用

ctrl.start

controller-runtime 之控制器实现

先等待informer同步完成,再启动worker(MaxConcurrentReconciles个,循环)处理资源对象。reconcileehandler处理业务,c.Do.Reconcile(req)暴露给开发者。实现re完成逻辑,result=c.Do.Reconcile(req)。
result。result.RequeueAfter > 0,queue先忘记,result.RequeueAfter时间后再加入。result.Requeue,直接加入。正常返回则忘记。

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 1
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值