友情提示:全文3090多文字,预计阅读时间5分钟
摘要
《Kubelet从入门到放弃系列》将对Kubelet组件由Linux基础知识到源码进行深入梳理。上一篇zouyee带各位看了Kubelet从入门到放弃:拓扑管理,其中提及设备插件,在本文<Kubelet从入门到放弃系列:与GPU齐飞>,今天zouyee跟段全峰童鞋为各位介绍Kubernetes如何利用Nvidia系列GPU,后续介绍Device Plugin的相关概念以及Kubelet组件源码逻辑。
一、需求说明
1.1 需求说明
在Kubernetes 1.8之前,用户使用GPU等设备时,推荐使用Accelerators Feature Gate的内置方式,延续Kubernetes的插件化的实现理念,各司其职,在Kubernetes 1.10版本后,引入设备插件框架,用户可以将系统硬件资源引入到Kubernetes生态。本文将介绍NVIDIA GPU如何安装部署,Device Plugins的相关介绍、工作机制和源码分析,包括插件框架、使用和调度GPU、和异常处理及优化等相关内容。
1.2 相关说明
在Kubernetes 1.10中Device Plugins升为Beta特性,在Kubernetes 1.8时,为了给第三方厂商通过插件化的方式将设备资源接入到Kubernetes,给容器提供Extended Resources。
通过Device Plugins方式,用户无需要改Kubernetes的代码,由第三方设备厂商开发插件,实现Kubernetes Device Plugins的相关接口即可(仔细想想,Kubernetes中的volume管理是否也是类似的逻辑?CSI、CNI、CRI?)。
目前Device Plugins典型实现有:
a) AMD GPU插件
b)Intel设备插件:GPU、FPGA和QuickAssist设备
c)KubeVirt用于硬件辅助的虚拟化设备插件
d)Nvidia提供的GPU插件
e)高性能低延迟RDMA卡插件
f)低延迟Solarflare万兆网卡驱动
g)SR-IOV网络设备插件
h)Xilinx FPGA设备插件
Kubelet启动Device plugins服务端,对应设备商启动Device Plugin服务,对外暴露几个gRPC Service提供服务,并通过/var/lib/kubelet/device-plugins/kubelet.sock与Kubelet通信。
二、部署介绍
2.1 部署说明
当前Nvidia GPU提供三种部署方式:docker方式、Containerd方式及Operator方式。
因docker后续不再内置,相关说明可以查看关于Kubernetes废弃内置docker CRI功能的说明,下文将主要介绍 Containerd部署,Operator方式后续单独成文,当前nvidia-container-toolkit已经支持containerd和cri-o两种部署方式,在接受containerd部署前,先说明前期遇到的相关问题:
a. 默认runtime设置
其中Kubelet问题描述:
Events:
Type Reason Age From Message
---- ------ ---- ---- -------
Normal Scheduled 10m default-scheduler Successfully assigned gpu-operator-resources/nvidia-device-plugin-daemonset-f99md to cl-gpu-md-0-f4gm6
Warning InspectFailed 10m (x3 over 10m) kubelet Failed to inspect image "nvcr.io/nvidia/k8s/cuda-sample:vectoradd-cuda10.2": rpc error: code = Unavailable desc = all SubConns are in TransientFailure, latest connection error: connection error: desc = "transport: Error while dialing dial unix /run/containerd/containerd.sock: connect: connection refused"
其中Nvidia Device Plugin Daemonset某一个Pod相关错误,如下
# kubectl logs ‐f nvidia‐device‐plugin‐daemonset‐q9svq ‐nkube‐system
2021/02/11 01:32:29 Loading NVML
2021/02/11 01:32:29 Failed to initialize NVML: could not load NVML library.
2021/02/11 01:32:29 If this is a GPU node, did you set the docker default runtime to `nvidia`?
2021/02/11 01:32:29 You can check the prerequisites at: https://github.com/NVIDIA/k8s-device-plugin#prerequisites
2021/02/11 01:32:29 You can learn how to set the runtime at: https://github.com/NVIDIA/k8s-device-plugin#quick-start
2021/02/11 01:32:29 If this is not a GPU node, you should set up a toleration or nodeSelector to only deploy this plugin on GPU nodes
该问题由于containerd的配置文件containerd.toml未将default_runtime_name = "runc"修改为default_runtime_name = "nvidia",相关问题:https://github.com/NVIDIA/gpu-operator/issues/143
相关问题:https://github.com/NVIDIA/libnvidia-container/issues/119
在kubelet配置的cgroup driver为systemd时,Nvidia的container prestart hook在处理cgroup路径逻辑与containerd不一致。
containerd[76114]: time="2020-12-04T08:52:13.029072066Z" level=error msg="StartContainer for "7a1453c6e7ab8af7395ccc8dac5efcffa94a0834aa7b252e1dcd5b51f92bf13e" failed" error="failed to create containerd task: OCI runtime create failed: container_linux.go:370: starting container process caused: process_linux.go:459: container init caused: Running hook #0:: error running hook: exit status 1, stdout: , stderr: nvidia-container-cli: mount error: open failed: /sys/fs/cgroup/devices/system.slice/containerd.service/kubepods-pod80540e95304d8cece2ae2afafd8b8976.slice/devices.allow: no such file or directory: unknown"
解决方案为升级libnvidia-container或者container-toolkit。
接下来,介绍部署相关内容。
1)版本说明
软件 | 版本说明 |
---|---|
CentOS | 7 |
内核 | 4.19.25 |
GPU型号 | Tesla T4 |
driver版本 | 418.39 |
CUDA版本 | 10.1 |
K8S | 1.18.5 |
Nvidia Device Plugin | 0.7.3 |
Containerd | v1.4.3 |
runc | 1.0.0-rc1 |
2)安装
注:下文为内网离线部署,若各位在联网环境下,只需参考部署步骤及部署配置即可
a. 安装驱动
$ tar ‐zxvf gpu.tar.gz
## 安装依赖
$ cd gpu/runtime
$ tar ‐zxvf dependency.tar.gz
$ cd dependency
## 查看是否支持CUDA的Nvidia的GPU
$ cd ./lspci/
$ yum localinstall ‐y *.rpm
$ lspci | grep ‐i nvidia ## 安装devel
$ cd ../devel
$ yum localinstall ‐y *.rpm
## 安装gcc $ cd ../gcc
$ yum localinstall ‐y *.rpm
## 卸载nouveau驱动
$ lsmod | grep nouveau
$ rmmod nouveau
## 安装驱动,过程见下面附的图片。如果要更新驱动,从https://developer.nvidia.com/cuda‐75‐downloads‐ archive下载
$ cd ../../../driver
$ sh cuda_10.1.105_418.39_linux.run ## 测试驱动,有如下输出则正常安装
结果验证
$ nvidia‐smi
附:安装驱动图
(1) 输入accept,回车
(2) 选择install,回车
2)配置Containerd
## 更新runc,下载地址https://github.com/opencontainers/runc/releases
$ cd ../runtime
$ cp runc /usr/bin/
## 更新containerd,下载地址 https://github.com/containerd/containerd/releases
$ tar ‐zxvf containerd‐1.4.3‐linux‐amd64.tar.gz
$ cp bin/* /usr/bin/
## 安装nvidia‐container‐runtime,yum源https://nvidia.github.io/nvidia‐docker/centos7/nvidia‐ docker.repo,yum安装:yum install ‐y nvidia‐container‐runtime $ tar ‐zxvf nvidia‐container‐runtime.tar.gz
$ cd nvidia‐container‐runtime
$ yum localinstall ‐y *.rpm
# 配置containerd的参数
$ mkdir /etc/containerd/
$ vi /etc/containerd/config.toml
# 配置containerd.service
$ vi /usr/lib/systemd/system/containerd.service
$ systemctl daemon‐reload
$ systemctl restart containerd
# 配置crictl
$ tar ‐zxvf crictl‐v1.18.0‐linux‐amd64.tar.gz
$ mv crictl /usr/bin/
$ vi /etc/profile alias crictl='crictl ‐‐runtime‐endpoint unix:///run/containerd/containerd.sock'
$ source /etc/profile
# 测试containerd和nvidia‐container‐runtime安装是否成功
$ cd test‐image
$ ctr images import cuda‐vector‐add_v0.1.tar
$ ctr images push ‐‐plain‐http registry.paas/cmss/cuda‐vector‐add:v0.1
执行检验
ctr run ‐t ‐‐gpus 0 registry.paas/cmss/cuda‐vector‐add:v0.1 cp nvidia‐smi
清理容器
ctr c rm cp
配置config.toml
执行containerd config default > /etc/containerd/config.toml生成配置,并做如下修改:
注意:如上所述,1)default_runtime_name值为nvidia,2)新增一个runtimes 3)若有内部镜像仓库,可修改docker.io为内部仓库名称
配置containerd.service
[Unit]
Description=containerd container runtime
Documentation=https://containerd.io After=network.target
[Service]
ExecStartPre=‐/sbin/modprobe overlay
ExecStart=/usr/bin/containerd
KillMode=process
Delegate=yes
LimitNOFILE=1048576
# Having non‐zero Limit*s causes performance problems due to accounting overhead # in the kernel. We recommend using cgroups to do container‐local accounting. LimitNPROC=infinity
LimitCORE=infinity
TasksMax=infinity
[Install]
WantedBy=multi‐user.target
c. 部署Device Plugin
在部署完Kubernetes集群后,修改kubelet运行时配置:
$ vi /apps/conf/kubernetes/kubelet.env ‐‐container‐runtime=remote ‐‐container‐runtime‐endpoint=unix:///run/containerd/containerd.sock
$ cd device‐plugin
$ docker load ‐i k8s‐device‐plugin_v0.7.3.tar
$ docker push
// https://github.com/NVIDIA/k8s-device-plugin/tree/master/deployments/static
$ kubectl apply ‐f nvidia‐device‐plugin.yml
$ kubectl logs ‐f nvidia‐device‐plugin‐daemonset‐q9svq ‐nkube‐system
2021/02/08 06:32:36 Loading NVML 2021/02/08 06:32:42 Starting FS watcher. 2021/02/08 06:32:42 Starting OS watcher. 2021/02/08 06:32:42 Retreiving plugins. 2021/02/08 06:32:42 Starting GRPC server for 'nvidia.com/gpu' 2021/02/08 06:32:42 Starting to serve 'nvidia.com/gpu' on /var/lib/kubelet/device‐ plugins/nvidia‐gpu.sock 2021/02/08 06:32:42 Registered device plugin for 'nvidia.com/gpu' with Kubelet
d. 功能测试
$ cd test‐image
# 启动测试pod
$ kubectl apply ‐f demo.yml
// https://github.com/NVIDIA/gpu-operator/blob/master/tests/gpu-pod.yaml
$ kubectl logs ‐f cuda‐vector‐add
[Vector addition of 50000 elements]
Copy input data from the host memory to the CUDA device
CUDA kernel launch with 196 blocks of 256 threads
Copy output data from the CUDA device to the host memory
Test PASSED
Done
未完,待续.
三、参考资料
1. https://kubernetes.io/zh/docs/concepts/extend-kubernetes/compute-storage-net/device-plugins/
2.https://github.com/kubernetes/community/blob/master/contributors/design-proposals/resource-management/device-plugin.md