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

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

1.PluginManager

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

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接口和对应插件类型的处理机制ide

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

1.5 CSI与普通设备

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

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进行通讯ui

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

2.2 Manager

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

2.3 Checkpoint

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

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

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

微信号:baxiaoshi2020

关注公告号阅读更多源码分析文章 21天大棚

更多文章关注 www.sreguide.com

本文由博客一文多发平台 OpenWrite 发布

相关文章
相关标签/搜索