最近和AI团队一起做项目,需要将机器学习的项目部署进k8s。因为要使用节点的GPU资源,普通部署的k8s集群不能用了,因为docker只能对CPU和内存而不能对GPU资源进行共享和隔离。这一节我们就一起来看看怎么部署一个能分配GPU资源的k8s集群。
我是T型人小付,一位坚持终身学习的互联网从业者。喜欢我的博客欢迎在csdn上关注我,如果有问题欢迎在底下的评论区交流,谢谢。
文章目录
操作环境
- master(CPU) - ubuntu 18.04
- gpu-node(GPU) - ubuntu 18.04
利用kubeadm安装
基本上跟着《【Kubernetes 003】Centos7通过Kubeadm安装Kubernetes1.15详解(附一键安装脚本)》进行安装即可成功创建集群。Centos和Ubuntu的命令稍微有些不同,但是大同小异,不影响整体步骤。
但是如果想在GPU节点的pod内使用GPU资源,还得对GPU节点做一些特殊的设定。所以请在将GPU节点加入master之前,对GPU节点完成下述操作。
GPU节点安装准备
查看Linux的GPU信息
先更新本地数据库,然后获取GPU的详细信息
sudo update-pciids
sudo lspci | grep VGA -A 10
如果lspci
命令没有找到,先通过下面命令安装
sudo yum install pciutils
我这边机器信息如下
root@gpu-node:~# lspci -v | grep VGA -A 10
01:00.0 VGA compatible controller: NVIDIA Corporation TU104 [GeForce RTX 2070 SUPER] (rev a1) (prog-if 00 [VGA controller])
Subsystem: Micro-Star International Co., Ltd. [MSI] Device c729
Flags: bus master, fast devsel, latency 0, IRQ 130
Memory at a3000000 (32-bit, non-prefetchable) [size=16M]
Memory at 90000000 (64-bit, prefetchable) [size=256M]
Memory at a0000000 (64-bit, prefetchable) [size=32M]
I/O ports at 3000 [size=128]
[virtual] Expansion ROM at 000c0000 [disabled] [size=128K]
Capabilities: [60] Power Management version 3
Capabilities: [68] MSI: Enable+ Count=1/1 Maskable- 64bit+
Capabilities: [78] Express Legacy Endpoint, MSI 00
如果跟我的机器一样是nvidia的显卡,根据显示的型号去查询支持的最新driver,安装完driver就会有管理工具nvidia-smi
nvidia显卡持续查看使用情况,每秒更新一次
watch -n 1 nvidia-smi
我这边的GPU和driver信息如下
root@gpu-node:~# nvidia-smi
Tue May 19 10:58:25 2020
+-----------------------------------------------------------------------------+
| NVIDIA-SMI 435.21 Driver Version: 435.21 CUDA Version: 10.1 |
|-------------------------------+----------------------+----------------------+
| GPU Name Persistence-M| Bus-Id Disp.A | Volatile Uncorr. ECC |
| Fan Temp Perf Pwr:Usage/Cap| Memory-Usage | GPU-Util Compute M. |
|===============================+======================+======================|
| 0 GeForce RTX 207... Off | 00000000:01:00.0 Off | N/A |
| 24% 28C P8 11W / 215W | 19MiB / 7982MiB | 0% Default |
+-------------------------------+----------------------+----------------------+
+-----------------------------------------------------------------------------+
| Processes: GPU Memory |
| GPU PID Type Process name Usage |
|=============================================================================|
| 0 1765 G /usr/lib/xorg/Xorg 9MiB |
| 0 1799 G /usr/bin/gnome-shell 8MiB |
+-----------------------------------------------------------------------------+
- Nvidia GeForce RTX 2070 SUPER
- Driver版本 435.21
- 显存大小 7982MiB
安装nvidia-docker2
下面对原生docker进行改进,使其能使用GPU资源。不同厂商有自己的解决方法,Nvidia官方推出了nvidia-docker来对原生进行改善,目前是2.x版本,说明看这里。
首先确保安装了nvidia driver以及原生docker,然后跟着这里的方法安装repo,命令如下
curl -s -L https://nvidia.github.io/nvidia-docker/gpgkey | \
sudo apt-key add -
distribution=$(. /etc/os-release;echo $ID$VERSION_ID)
curl -s -L https://nvidia.github.io/nvidia-docker/$distribution/nvidia-docker.list | \
sudo tee /etc/apt/sources.list.d/nvidia-docker.list
sudo apt-get update
之后就可以搜索到了,这里是2.3版本
root@gpu-node:~# apt search nvidia-docker
Sorting... Done
Full Text Search... Done
nvidia-docker2/bionic 2.3.0-1 all
nvidia-docker CLI wrapper
因为后面还要安装别的插件,有兼容性问题,请确保版本在2.0以上
然后安装nvidia-docker2
sudo apt-get install -y nvidia-docker2
在最后会问你要如何操作/etc/docker/daemon.json
这个文件
Configuration file '/etc/docker/daemon.json'
==> File on system created by you or by a script.
==> File also in package provided by package maintainer.
What would you like to do about it ? Your options are:
Y or I : install the package maintainer's version
N or O : keep your currently-installed version
D : show the differences between the versions
Z : start a shell to examine the situation
The default action is to keep your current version.
*** daemon.json (Y/I/N/O/D/Z) [default=N] ?
这里我们直接选择Y
让安装程序去覆盖现有文件,如下
root@gpu-node:~# cat /etc/docker/daemon.json
{
"runtimes": {
"nvidia": {
"path": "nvidia-container-runtime",
"runtimeArgs": []
}
}
}
可以看到为docker添加了一个新的runtime
重启一下docker服务
service docker restart
这样在机器上就多了一个docker的runtime,在跑docker的时候可以指定runtime
docker run --runtime=nvidia --rm nvidia/cuda nvidia-smi
或者用下面的方法一劳永逸直接将nvidia指定为默认的runtime,代替runc
# Update the default configuration and restart
pushd $(mktemp -d)
(sudo cat /etc/docker/daemon.json 2>/dev/null || echo '{}') | \
jq '. + {"default-runtime": "nvidia"}' | \
tee tmp.json
sudo mv tmp.json /etc/docker/daemon.json
popd
sudo systemctl restart docker
# No need for nvidia-docker or --engine=nvidia
docker run --rm -it nvidia/cuda nvidia-smi
通过下面的命令查看是否成功
docker info | grep nvidia
如果出现下面的信息表示已经成功将nvidia变为默认的docker runtime,代表容器可以使用GPU资源了
root@gpu-node:~# docker info | grep nvidia
WARNING: No swap limit support
Runtimes: nvidia runc
Default Runtime: nvidia
GPU节点加入集群
完成上述步骤,按照master的log信息将GPU节点加入集群,之后就会看到有两个node
root@control-plane-1:~# kubectl get node
NAME STATUS ROLES AGE VERSION
control-plane-1 Ready master 80m v1.15.10
gpu-node Ready <none> 53m v1.15.10
我这里对master设置了taint,不允许pod被调度到master上
root@control-plane-1:~# kubectl describe node control-plane-1 | grep Taints
Taints: node-role.kubernetes.io/master:NoSchedule
安装插件
虽然容器可以使用GPU资源了,此时如果试着去跑官方给的GPU的测试deployment,会发现所有pod都在pending状态,查看pod状态会出现如下报错
Events:
Type Reason Age From Message
---- ------ ---- ---- -------
Warning FailedScheduling 48s (x18 over 24m) default-scheduler 0/2 nodes are available: 2 Insufficient nvidia.com/gpu.
根据k8s官方文档对于GPU分配的说明,必须要安装另一个第三方的Nvidia插件才可以完成。
官方给出的插件对于GPU的分配不够智能和灵活,我们采用Aliyun的一个extender。
自带插件的说明,不建议使用
http://www.podman.cn/?/article/7
阿里云的extender说明,颗粒更细
https://blog.spider.im/post/gpu-share-in-k8s/
步骤有点多,直接按照官方安装指导书一步步来。
部署extender
cd /etc/kubernetes/
curl -O https://raw.githubusercontent.com/AliyunContainerService/gpushare-scheduler-extender/master/config/scheduler-policy-config.json
cd /tmp/
curl -O https://raw.githubusercontent.com/AliyunContainerService/gpushare-scheduler-extender/master/config/gpushare-schd-extender.yaml
kubectl create -f gpushare-schd-extender.yaml
修改scheduler配置
目标是将/etc/kubernetes/scheduler-policy-config.json
加入到/etc/kubernetes/manifests/kube-scheduler.yaml
配置中。需要注意的是需要先在/etc/kubernetes/manifests/
目录外生成配置文件再复制到目录内,触发静态pod的自动更新
首先复制配置文件
sudo cp /etc/kubernetes/manifests/kube-scheduler.yaml /tmp
然后模仿这个示例添加下面的两部分内容
- --policy-config-file=/etc/kubernetes/scheduler-policy-config.json
- mountPath: /etc/kubernetes/scheduler-policy-config.json
name: scheduler-policy-config
readOnly: true
- hostPath:
path: /etc/kubernetes/scheduler-policy-config.json
type: FileOrCreate
name: scheduler-policy-config
然后复制回去
sudo cp /tmp/kube-scheduler.yaml /etc/kubernetes/manifests/kube-scheduler.yaml
检查发现shceduler的pod重启了表示修改生效
配置Device Plugin
注意如果这里已经配置了官方的Device Plugin例如nvidia-device-plugin,需要先删除
wget https://raw.githubusercontent.com/AliyunContainerService/gpushare-device-plugin/master/device-plugin-rbac.yaml
kubectl create -f device-plugin-rbac.yaml
wget https://raw.githubusercontent.com/AliyunContainerService/gpushare-device-plugin/master/device-plugin-ds.yaml
kubectl create -f device-plugin-ds.yaml
将GPU节点打上label
kubectl label node <target_node> gpushare=true
安装kubectl的扩展
cd /usr/bin/
wget https://github.com/AliyunContainerService/gpushare-device-plugin/releases/download/v0.3.0/kubectl-inspect-gpushare
chmod u+x /usr/bin/kubectl-inspect-gpushare
之后就可以用下面的命令查看GPU的分配情况了
root@control-plane-1:~# kubectl-inspect-gpushare
NAME IPADDRESS GPU0(Allocated/Total) GPU Memory(GiB)
gpu-node 172.29.57.202 0/7 0/7
---------------------------------------------------
Allocated/Total GPU Memory In Cluster:
0/7 (0%)
我这里有7G的显存,所以显示为7。更详细的信息可以查看kubectl-inspect-gpushare -d
GPU分配测试
想要申请GPU,只需要声明aliyun.com/gpu-mem
即可,单位是GiB。
例如如下测试文件deployment.yaml
起两个pod,每个pod生成1GiB的GPU
apiVersion: apps/v1
kind: Deployment
metadata:
name: nvidia-deployment
spec:
replicas: 2
selector:
matchLabels:
name: nvidia-gpu-deploy
template:
metadata:
labels:
name: nvidia-gpu-deploy
spec:
containers:
- name: cuda-container
image: ubuntu
command: ["sleep"]
args: ["100000"]
resources:
limits:
aliyun.com/gpu-mem: 1
等两个pod起来以后查看分配情况
root@control-plane-1:~/nvidia-test# kubectl-inspect-gpushare -d
NAME: gpu-node
IPADDRESS: 172.29.57.202
NAME NAMESPACE GPU0(Allocated)
nvidia-deployment-5f4bbd9457-h4rfk default 1
nvidia-deployment-5f4bbd9457-wqx8v default 1
Allocated : 2 (28%)
Total : 7
------------------------------------------------------------------------------------------------------
Allocated/Total GPU Memory In Cluster: 2/7 (28%)
删除kubeadm创建的集群
如果因为某些原因要销毁整个集群也很容易,因为是用kubeadm搭建的,只需要用下面的命令就可以
kubeadm reset
总结
在k8s中部署GPU机器学习程序已经成为一种趋势,虽然原生docker对GPU的支持没跟上,但是厂商的支持还是很多的,可以多去看看Nvidia的文档,很详细。