上一篇文章讲到了限制显存的一个方案,这里补发下之前写的k8s中的gpu共享功能的实现分析。以下内容为之前写的:
GPU在容器间共享这个功能其实都有需要,但是官方都没有,之前在公司内实现的改动也太过于in-tree,无法opensource,今天看到阿里云开源了个GPU共享的方案,那么顺道借分析下阿里的方案来总结下这方面的事情。
阿里云的代码在
https://github.com/AliyunContainerService/gpushare-scheduler-extender
https://github.com/AliyunContainerService/gpushare-device-plugin
阿里云实现了一个gpushare的device-plugin,然后实现了相关的调度逻辑
由于具体的共享逻辑在node上,所以我们先看下device-plugin的实现。
之前看过nvidia的官方device-plugin实现,本质很简单,需要实现2个接口 1.listandwatch用于获得机器上的device列表,2. allocate接口用于kubelet分配设备时,这个设备要做的一些事情 这个设计其实不是那么好,这个之前的nvidia k8s和官方的区别中 有提到,限制了deviceplugin对设备的调度控制能力 (device-plugin相关的实现后面也看下补篇文章)
入口代码,和nvidia官方本质没什么区别,加载了nvml的库(cgo的)用于获取机器上的gpu的信息
创建了个fsNotify去实现deviceplugin要求的相关逻辑
1 | func (ngm *sharedGPUManager) Run() error { |
ListAndWatch的逻辑
1 | //listandwatch 返回的是m.Devs, 实际是从下面这个函数获得的 |
具体的分配逻辑(注意看注释):
1 | // Allocate which return list of devices. |
device-plugin控制了设备真正的使用,所以从这里可以看出来,阿里的方案并没有真正控制gpu的使用,只是实现了共享,最终还需要业务方从传入的环境变量来适应这个共享
然后阿里这个scheduler首先我们需要了解scheduler-extender的设计
https://github.com/kubernetes/community/blob/master/contributors/design-proposals/scheduling/scheduler_extender.md
即官方提供了个方案允许你扩展它的调度器
只需要你指定一个描述文件https://github.com/AliyunContainerService/gpushare-scheduler-extender/blob/master/config/scheduler-policy-config.json 其中设置好几个verb,官方调度器会在相应的环节调用你的调度器处理你的逻辑,
1 | { |
从描述文件来看,阿里实现了filter和bind接口来接管gpu-mem这个资源的预选操作,具体另外开文章说吧。
然后再描述下我之前对gpu共享的改动,和阿里不太一样,我这里主要是修改了nvidia.com/gpu这个原有的资源,让其支持小数。
主要是改动了scheduler和kubelet,这个比阿里的好处是由于是已有的资源,调度上实现不用太多,改动很少,只有
plugin/pkg/scheduler/algorithm/predicates/predicates.go 以及plugin/pkg/scheduler/schedulercache/node_info.go中资源相关的数据又原来的Value()改成MilliValue()。
剩下的改动主要是kubelet中pkg/kubelet/gpu/nvidia/nvidia_gpu_manager.go 这里由于支持了小数,并且比阿里好的是支持了多gpu的共享
主要是扩展了原有的定义,以及改动了 AllocateGPU(pod v1.Pod, container v1.Container) 这个func中的具体逻辑,具体就不列出来了
1 | //扩展了原有的结构,记录了pod对container,container对gpu的使用量的情况,便于allocate处使用 |
总结下来看,目前对k8s容器中gpu共享的方案,都没有实现真正的资源控制,只是实现了gpu卡在多个容器中的共享,并且需要业务去适应这样的问题。
另外再补充一句,gpu这种资源还是适合用的时候多分配,不用的时候就回收(所以某mlp平台启动个jupyter notebook一直占着个显卡就很蠢了,不如做个web-ide用户点运行的时候再去占GPU),即适合结合自动扩缩容的方案来做资源管理,尤其是对在线的预测服务。
PS:看这个的时候纠正了我一个想法错误,之前看deviceplugin的设计是plugin告诉kubelet有那些设备,然后真正使用的时候kubelet自己去选,plugin不参与这块的调度,但是其实nvidia-docker可以通过设置环境变量的方式来选择用那个卡,所以这块由于nvidia-docker本身的设计使得deviceplugin可以抉择使用哪块卡。




