kubelet 源码分析 devicemanager
device-plugin
是 Kubernetes
用来扩展除 CPU
Memory
之外的硬件设备,比如常见的 Nvidia GPU
.
下面主要来分析一下在 Kubelet
中是如何调用 device-plugin
的,以及如何生成 OCI Spec
内容。
device-plugin
也存在一些限制,因为它不感知 Pod
和 Container
,就导致没办法做一些动态的资源分配,比如根据用户设置选用某个 GPU
型号或者是指定使用某个设备的 UUID
;目前社区主要是在推进 DRA
来解决这些问题。
kubelet 调用流程
device plugin
的工作原理其实不复杂。主要有以下步骤:
- 首先
device plugin
可以通过daemonset
部署到需要的节点上。 - 为了让
Kubernetes
发现device plugin
,需要向kubelet
的unix socket
。 进行注册,注册的信息包括device plugin
的unix socket
API Version
ResourceName
kubelet
通过grpc
向device plugin
调用ListAndWatch
, 获取当前节点上的资源。kubelet
向api server
更新节点状态来通知资源变更。- 用户创建
pod
,请求资源并调度到节点上后,kubelet
调用device plugin
的Allocate
进行资源分配。
时序图如下:
device-plugin
源码模块在 pkg/kubelet/cm/devicemanager
目录下,是 ContainerManager
模块的一部分,主要是用来在创建 Container
过程中,生成 OCI Spec
内容的。
下面按照两个流程来讲解源码,一个是注册流程和获取节点设备,还有一个是分配流程;
注册和获取可用设备流程:
资源分配流程
从 ContainerManager
的 GetResources
方法进入 devicemanager
模块中,开始获取分配的设备,最后返回一个 DeviceRunContainerOptions
对象:
type DeviceRunContainerOptions struct {
// The environment variables list.
Envs []kubecontainer.EnvVar
// The mounts for the container.
Mounts []kubecontainer.Mount
// The host devices mapped into the container.
Devices []kubecontainer.DeviceInfo
// The Annotations for the container
Annotations []kubecontainer.Annotation
// CDI Devices for the container
CDIDevices []kubecontainer.CDIDevice
}
如果启用了 CDI
则 CDIDevices
这个字段非空,此时需要挂载哪些设备就需要等容器运行时解析 CDI
文件然后 Merge
到 OCI Spec
文件中了。
下面主要讲一下几个函数的实现逻辑;
ListAndWatch
ListAndWatch
主要在启动的时候发送 Send
一次设备,之后进入监听本地设备的环节,如果出现设备不健康,则重新 Send
所有健康的设备。
Allocate
在用户创建的 Pod
请求资源时,Kubernetes
的调度器会进行调度,并通过 kubelet
向 device plugin
发出 Allocate
调用,这一步的调用主要是为了让 device plugin
为容器调度资源。 在调度成功后向 kubelet
返回调度结果即可。
GetDevicePluginOption
主要返回与 Device Manager
通信的一些可选参数设置,主要返回如下结构:
type DevicePluginOptions struct {
// 每个容器启动前是否需要调用 PreStartContainer
PreStartRequired bool
// GetPreferredAllocationAvailable: 是否提供优选方法
GetPreferredAllocationAvailable bool
}
PreStartContainer
如果设备插件在注册阶段设置 PreStartRequired=true
了要调用,则在每个容器启动之前调用 PreStartContainer
。 设备插件可以运行设备特定的操作,例如在使设备可供容器使用之前重置设备。
GetPreferredAllocation
如果设备插件在注册阶段设置 PreStartRequired=true
了要调用,可以针对指定的设备列表做二次最优分配。
官方的 nvidia-device-plugin
在 GetPreferredAllocation
内部实现了节点内多卡最优选择的逻辑,通过确定多卡之间的拓扑信息来决定通信量。