gpushare-scheduler-extender源码解析
阿里云在k8s中实现了在容器间对GPU的资源共享,具体实现为:aliyun/gpushare-scheduler-extenderaliyun/gpushare-device-pluginscheduler-extender与default scheduler的关联:在default scheduler的默认启动参数中添加参数--configextender-config.yaml中为extend
- 阿里云在k8s中实现了在容器间对GPU的资源共享,具体实现为:
aliyun/gpushare-scheduler-extender
aliyun/gpushare-device-plugin - scheduler-extender与default scheduler的关联:
- 在default scheduler的默认启动参数中添加参数
--config
- extender-config.yaml中为
- extender-polilcy.json中包含了定义的extender详细拓展接口,扩产verb动词支持filter、predicate、prioritize、preemption、bind
- default scheduler 发送给extender scheduler的请求参数为:其中包含被调度的pod与候选节点。
extender根据verb会有不同的请求参数,例如bind的请求参数为
- 核心代码解析
- 关键问题:如何去限制GPU的算力?目前没有很好的方法去限制,但是可以控制GPU内存使用上限。cuda中有一个
cuMemGetInfo
接口可以得到GPU的空余资源数量;
sharedegpu-device-plugin的代码中定义了一个MemoryUnit
去分割一个GPU的资源实现调度层的虚拟化。
代码中可以看到getGPUMemory
其实就是被分割的GPUmemory的份数。
虚拟后的GPU个数=物理GPU数*单个GPU分割后的份数。
for i := uint(0); i < deviceNumber; i++ {
for j := uint(0); j < getGPUMemory(i); j++{
devs = append(devs, &pluginapi.Device{
ID: fakeID,
Health: pluginapi.Healthy,
}
}
}
-
Allocate的主要逻辑
作者获取pending的pod,对pending的pod进行与allocate的pod资源进行对比,如果一致就分配资源。
这里存在两个问题:1.为啥还要自己手动的去获取pod?2.allocate的pod与pending的pod只要分配资源数就当成一个,显然不正确。这种设计有些多此一举? -
scheduler-extender的核心代码:
(1)predicate Handler:gpushare-scheduler-extender/pkg/scheduler/gpushare-predicate.go包下是predicate的主要逻辑:
函数输入为:func(pod *v1.Pod, nodeName string, c *cache.SchedulerCache)
// 1. 获取node的详细信息
nodeInfo, err := GetNodeInfo(nodeName)
// 2. 判断当前节点是否有GPU资源
utils.IsGPUSharingNode(nodeInfo.GetNode()
// 3. 判断pod能否分配在这个节点上
allocatable := nodeInfo.Assume(pod)
predicate的逻辑比较简单,需要注意的是使用了一个SchedulerCache缓存对nodeinfo进行缓存,在读取nodeinfo的时候需要加锁sync.RWMutex
,防止数据不一致。
(2)bind Handler:主要逻辑为
pod = getPod(podId)
nodeInfo = GetNodeInfo(nodeName)
nodeInfo.Allocate(pod)
Allocate中包含的逻辑有:
//1. 更新pod的annotation信息,以供后续scheduler-extender使用
utils.GetUpdatedPodAnnotationSpec(pod, devId, n.GetTotalGPUMemory()/n.GetGPUCount())
// 2. 绑定节点
clientset.CoreV1().Pods(pod.Namespace).Bind(binding)
// 3. 绑定成功后更新设备信息
dev.addPod(newPod)
更多推荐
所有评论(0)