在Kubernetes集群中使用GPU资源
Kubernetes(下文简称为k8s)具有对机器的资源进行分配和使用的能力,比如k8s可以指定容器最多使用多少内存以及使用多少CPU计算资源。那么问题来了,一般来说容器就是使用CPU和内存资源,那么对于需要使用显卡的Pod,k8s也能够支持吗?答案当然是可以啦!目前k8s不仅支持容器请求GPU资源,还支持请求几块显卡的GPU资源,这使得k8s在深度学习等场景下也有了用武之地。
所以本文的主要内容就是如何在k8s集群中使用GPU资源
系列文章
本文为【Docker & Kubernetes & GPU】系列文章中的一篇:
- Docker安装指南以及使用GPU
- 使用Harbor搭建Docker私有仓库
- 基于Docker的Kubernetes-1.12集群搭建
- 在Kubernetes集群中使用GPU资源(本文)
环境配置
本文实践的服务器环境为:
- CentOS Linux release 7.5.1804 (Core)
- 内核版本:3.10.0-862.14.4.el7.x86_64
- Docker-CE版本:18.06.1-ce
- Nvidia-Docker版本:2.0.3
- Kubernetes版本:1.12.2
- NVIDIA/k8s-device-plugin版本:1.11
- 每个Node节点具有两张P4显卡
1、安装k8s-device-plugin
以下内容根据官方安装指南进行简化整理,完整版请移步:https://kubernetes.io/docs/tasks/manage-gpus/scheduling-gpus/、https://github.com/NVIDIA/k8s-device-plugin
自从k8s 1.8版本开始,官方开始推荐使用device plugin的方式来调用GPU使用。截至目前,Nvidia和AMD都推出了相应的设备插件,使得k8s调用GPU变得容易起来。因为我们是Nvidia的显卡,所以需要安装NVIDIA GPU device plugin
在这里需要提前说明两个参数,--feature-gates="Accelerators=true"
和--feature-gates="DevicePlugins=true"
。在很多教程中都说明若要使用GPU,需要设置Accelerators为true,而实际上该参数在1.11版本之后就弃用了。而将DevicePlugins设置为true也是在1.9版本之前需要做的事情,在1.10版本之后默认就为true。所以对于我们来说,因为使用的是1.12版本,这两个feature-gates都不需要做设置
具体的feature-gates说明可以参见该链接
前期准备
运行NVIDIA GPU device plugin需要所有Node节点满足以下条件(如果允许Master节点部署Pod,那么Master节点也需要满足):
- 显卡驱动版本大于361.93
- Nvidia-Docker版本大于2.0
- 将nvidia配置为Docker默认的runtime
- Kubernetes版本为1.11
关于支持的k8s版本不用担心,并不是局限于1.11。因为使用的API版本为beta,所以还可额外支持未来两个版本,也即1.11、1.12、1.13。详见该issue
显卡驱动以及Nvidia-Docker的准备工作在之前的《Docker安装指南以及使用GPU》介绍中已经完成,所以这里我们只需要将nvidia配置为Docker默认的runtime
修改Docker默认的runtime
编辑/etc/docker/daemon.json
文件,增加"default-runtime": "nvidia"
键值对,此时该文件的内容应该如下所示(registry-mirrors是之前添加的国内镜像下载地址):
1 | { |
修改Docker的配置后,切记一定要将Docker重启systemctl restart docker
,否则配置修改无效
安装
在Master节点上执行
1 | kubectl create -f https://raw.githubusercontent.com/NVIDIA/k8s-device-plugin/v1.11/nvidia-device-plugin.yml |
稍等一会后,使用kubectl describe nodes
查看节点信息,可以看到具有GPU的Node节点中可获取的资源已包括GPU
1 | # 安装前 |
测试
在Master节点上创建~/tf-pod.yaml
文件,内容如下:
1 | apiVersion: v1 |
执行kubectl apply -f ~/tf-pod.yaml
创建Pod。使用kubectl get pod
可以看到该Pod已经启动成功
1 | NAME READY STATUS RESTARTS AGE |
执行kubectl exec tf-pod -it -- bash
进入Pod内部。测试显卡信息以及TensorFlow的GPU调用,结果如下:
可以看到成功运行。这也说明k8s完成了对GPU资源的调用
一些错误
- 0/3 nodes are available: 3 Insufficient nvidia.com/gpu.
该错误是通过执行kubectl describe pod xxx
查看调用GPU的Pod中Event部分呈现的。导致该错误的原因有很多种:比如没有GPU资源却申请,或者申请的GPU资源超过物理机。总而言之就是请求不到GPU资源
- Failed to initialize NVML: could not load NVML library.If this is a GPU node, did you set the docker default runtime to `nvidia`?
该错误也是通过执行kubectl describe pod xxx
查看调用GPU的Pod中Event部分呈现的。如果修改了Docker的配置后(增加默认runtime)没有重启Docker就直接安装device-plugin的话会导致该错误。因为这时device-plugin启动Pod所运行的容器是加载不到显卡的。所以修改Docker配置后一定要重启Docker,再进行安装
也可以用以下命令测试device-plugin在节点上是否生效
1 | docker run --security-opt=no-new-privileges --cap-drop=ALL --network=none -it -v /var/lib/kubelet/device-plugins:/var/lib/kubelet/device-plugins nvidia/k8s-device-plugin:1.11 |
出现以下信息代表没生效
1 | 2018/11/08 02:58:17 Loading NVML |
出现以下信息代表生效了
1 | 2018/11/08 02:58:46 Loading NVML |
- 安装了device-plugin后,device-plugin Pod正常启动,但是依旧无法调用GPU资源,查看Node节点信息发现GPU处数量为0
当时遇见该问题的过程为:修改Docker配置,安装device-plugin,无法启动,重启Docker,device-plugin启动正常,但GPU无法调用
原因就在于启动device-plugin的时候Docker配置没有生效,虽然后续重启Docker了,但是device-plugin的Pod没有更新,所以依旧捕获不到GPU信息。解决办法是杀掉device-plugin的Pod,让其重新生成
最主要的原因是没按顺序操作!!!灵感来源
2、多型号GPU支持
如果不同的节点具有不同的GPU型号,可以给节点打上Label,然后在调用的时候指定Node
1 | # Label your nodes with the accelerator type they have. |
1 | apiVersion: v1 |
3、小结
k8s能够调度GPU资源,使得k8s的应用范围又大大扩展了,尤其是在深度学习领域。不过目前k8s只支持卡级别的调度,并且显卡资源是独占,无法在多个容器之间分享,这一点在使用过程中需要特别注意。
References
官方指南:https://kubernetes.io/docs/tasks/manage-gpus/scheduling-gpus/
NVIDIA device plugin问题解决方案聚集地:https://github.com/NVIDIA/k8s-device-plugin/issues