图解kubernetes资源扩展机制实现(下)

断了今生、忘了曾经 提交于 2020-02-28 09:31:01

昨天我们介绍了k8s中资源插件机制的核心关键组件,今天我们继续来看下各个组件是如何进行通信的,以及k8s中针对事件处理背后的关键设计

1.PluginManager

PluginManager是一个上层组件,其内部包含了上篇文章中的关键组件,并且协调其内部数据流,而且还提供针对不同插件的具体的控制器 image.png

1.1 核心数据结构

核心结构里面其实就是按照数据流来进行设计的,首先需要一个感知插件desiredStateOfWorldPopulator用于感知后端服务的创建或者删除,然后将感知到的事件加入到desiredStateOfWorld期望状态缓存,由reconciler负责期进行底层的注册和下线,并且将结果存储到actualStateOfWorld实际状态缓存

type pluginManager struct {
	// 插件感知
	desiredStateOfWorldPopulator *pluginwatcher.Watcher

    // 协调器插件
	reconciler reconciler.Reconciler

    // 实际状态缓存
	actualStateOfWorld cache.ActualStateOfWorld
	// 期望状态缓存
	desiredStateOfWorld cache.DesiredStateOfWorld
}

1.2 初始化

初始化中会将dsw和asw都交给reconciler用于进行事件的感知和更新对应的缓存

func NewPluginManager(
	sockDir string,
	recorder record.EventRecorder) PluginManager {
	asw := cache.NewActualStateOfWorld()
	dsw := cache.NewDesiredStateOfWorld()
    // 这里会将期望状态缓存和实际状态缓存,都交给reconciler
	reconciler := reconciler.NewReconciler(
		operationexecutor.NewOperationExecutor(
			operationexecutor.NewOperationGenerator(
				recorder,
			),
		),
		loopSleepDuration,
		dsw,
		asw,
	)

	pm := &pluginManager{
        //  启动一个watcher并且存储dsw期望状态缓存,后续reconciler就可以通过dsw感知到新的状态了
		desiredStateOfWorldPopulator: pluginwatcher.NewWatcher(
			sockDir,
			dsw,
		),
		reconciler:          reconciler,
		desiredStateOfWorld: dsw,
		actualStateOfWorld:  asw,
	}
	return pm
}

1.3 启动插件管理器

插件管理器启动其实就是启动内部的desiredStateOfWorldPopulator就会讲watcher感知的事件,不断的修改自己的内部缓存这样reconciler就可以不断的通过期望状态缓存,进行对应grpc的调用从而满足期望状态

func (pm *pluginManager) Run(sourcesReady config.SourcesReady, stopCh <-chan struct{}) {
	defer runtime.HandleCrash()

    // 运行期望状态缓存,其实主要是通过watcher感知到的事件,修改自身的缓存
    // 后续reconciler会周期性的获取
	pm.desiredStateOfWorldPopulator.Start(stopCh)
	klog.V(2).Infof("The desired_state_of_world populator (plugin watcher) starts")

	klog.Infof("Starting Kubelet Plugin Manager")
    // 周期性的运行校证数据
	go pm.reconciler.Run(stopCh)

	metrics.Register(pm.actualStateOfWorld, pm.desiredStateOfWorld)
	<-stopCh
	klog.Infof("Shutting down Kubelet Plugin Manager")
}

1.4 控制器注册

控制器其实主要是指的reconciler通过对比期望缓存和实际缓存之间的差异,产生对应的事件之后,针对该类型的插件,后续的处理流程是什么,比如注册/下线具体的grpc接口和对应插件类型的处理机制

func (pm *pluginManager) AddHandler(pluginType string, handler cache.PluginHandler) {
	pm.reconciler.AddHandler(pluginType, handler)
}

1.5 CSI与普通设备

当前的kubelet中有注册两种类型的插件控制器,CSI与DEVICPLUGIn,从名字上大家也能知道大概的意思

	kl.pluginManager.AddHandler(pluginwatcherapi.CSIPlugin, plugincache.PluginHandler(csi.PluginHandler))
	kl.pluginManager.AddHandler(pluginwatcherapi.DevicePlugin, kl.containerManager.GetPluginRegistrationHandler())

2. PluginHandler

这里我们只介绍一个即DevicePlugin的核心实现机制 image.png

2.1 Endpoint

Endpoint其实指的就是某个提供扩展资源的服务,在之前说的reconciler中,会获取其对应的grpc服务的地址,后续则会直接调用grpc进行通信

Endpoint需要感知对应的资源设备的变化,同时将对应的设备信息,回调通知给当前的

2.2 Manager

Manager则是主要负责实现后端真正的Register/UnRegister的具体实现,其在内部会为每个Device创建一个Endpoint并负责收集后端提供资源服务上报上来的信息, 最终会讲对应的信息发送给kubelet,然后由kubelet在负责节点信息更新的时候,将信息传递给APIServer

2.3 Checkpoint

Checkpoint机制其实在很多系统中都比较常用,主要是用于周期性的将内存中的数据序列化存储到本地的磁盘中,在后续恢复的时候,会通过磁盘重新加载之前的数据,从而实现内存资源的快速恢复

扩展资源的整体实现流程大概就是这个样子,从如何感知数据,注册资源服务,获取资源服务的资源信息,并最终汇报给kubelet,同时落地本地磁盘,实现了完整的资源从感知到上报的整体流程的探测,其不足主要是在于关于资源实体的描述,从而导致资源的分配和资源的上报上有比较大的扩展性限制,比如要实现精细化的资源分配扩展,则不太能实现

k8s源码阅读电子书地址: https://www.yuque.com/baxiaoshi/tyado3

> 微信号:baxiaoshi2020 > 关注公告号阅读更多源码分析文章 21天大棚 > 更多文章关注 www.sreguide.com > 本文由博客一文多发平台 OpenWrite 发布

易学教程内所有资源均来自网络或用户发布的内容,如有违反法律规定的内容欢迎反馈
该文章没有解决你所遇到的问题?点击提问,说说你的问题,让更多的人一起探讨吧!