20

Kubernetes资源扩展机制(二)

 4 years ago
source link: http://mp.weixin.qq.com/s?__biz=MzIzNzU5NTYzMA%3D%3D&%3Bmid=2247489532&%3Bidx=1&%3Bsn=2b8fed5db9b281aca1320f7d9d13275a
Go to the source link to view the article. You can view the picture content, updated content and better typesetting reading experience. If the link is broken, please click the button below to view the snapshot at that time.
neoserver,ios ssh client

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

0 1

PluginManager

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

2UJzi2u.jpg!web

核心数据结构

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

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

    // 协调器插件
    reconciler reconciler.Reconciler

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

初始化

初始化中会将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
}

启动插件管理器

插件管理器启动其实就是启动内部的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")
}

控制器注册

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

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

CSI与普通设备

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

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

0 2

PluginHandler

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

au2Q3uj.jpg!web

Endpoint

Endpoint其实指的就是某个提供扩展资源的服务,在之前说的reconciler中,会获取其对应的grpc服务的地址,后续则会直接调用grpc进行通信。 Endpoint需要感知对应的资源设备的变化,同时将对 应的设备信息,回调通知给当前的。

Manager

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

Checkpoint

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

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

作者:8小时coding

原文地址:http://rrd.me/fKges


About Joyk


Aggregate valuable and interesting links.
Joyk means Joy of geeK