原文连接:https://fuckcloudnative.io/posts/add-nvidia-gpu-support-to-k8s-with-containerd/php
前两天闹得沸沸扬扬的事件不知道你们有没有据说,Google 居然将 Docker
踢出了 Kubernetes
的群聊,不带它玩了。。。linux
具体的解释请看《据说 K8s 要甩了 Docker 了》,我这里简单描述下,Kubernetes 是经过 CRI 来对接容器运行时的,而 Docker 自己是没有实现 CRI 的,因此 Kubernetes 内置了一个 “为 Docker 提供 CRI 支持” 的 dockershim
组件。如今 Kubernetes 宣布再也不维护这个组件了,大概的意思就是:Docker 虽然好用,但那是对人来讲的,Kubernetes 又不是人,不须要那些花里胡哨的东西!git
Kubernetes 这是话里有话,说白了就是:我特么之前为了兼容你,我集成在我本身这里,如今我就想本身单纯一点,要么你本身写 CRI 的接口 要么就再见。github
众 YAML 工程师直呼 Containerd 真香!docker
下面进入今天的主题,Kubernetes 具备对机器的资源进行分配和使用的能力,好比能够指定容器最多使用多少内存以及使用多少 CPU 计算资源。那么问题来了,通常来讲容器就是使用 CPU 和内存资源,那么对于须要使用显卡的 Pod,Kubernetes 也可以支持吗?答案固然是能够啦!目前 Kubernetes 不只支持容器请求 GPU
资源,还支持请求几块显卡的 GPU 资源,这使得 Kubernetes 在深度学习和区块链等场景下也有了用武之地。api
关于 Kubernetes 集群中 Docker 如何使用 GPU,Kubernetes 的官方文档已经说的很清楚了,网上也有铺天盖地的博客手把手教你怎么作。至于以 Containerd 做为容器运行时的集群如何使用 GPU,网上还找不到一篇像样的文档来告诉你们怎么作,今天我就来作吃螃蟹的第一人。bash
要想在容器里使用 GPU,本质上就是咱们要在容器里能看到而且使用宿主机上的显卡,全部的步骤都是围绕这个来作的。固然,本文不会涉及如何安装 Containerd,也不会涉及如何安装 Kubernetes,若是这些都搞不定,建议不要往下看。架构
某些命令以 Ubuntu 做为示例。 首先宿主机上必现安装 Nvidia 驱动。这里推荐从 Nvidia 官网下载脚本安装,安装和卸载都比较方便而且适用于任何 Linux 发行版,包括 CentOS,Ubuntu 等。 NVIDIA Telsa GPU 的 Linux 驱动在安装过程当中须要编译 kernel module,系统需提早安装 gcc 和编译 Linux Kernel Module 所依赖的包,例如 kernel-devel-$(uname -r) 等。app
安装 gcc 和 kernel-dev(若是没有) sudo apt install gcc kernel-dev -y
。curl
访问官网下载。
选择操做系统和安装包,并单击【SEARCH】搜寻驱动,选择要下载的驱动版本
下载对应版本安装脚本 在宿主机上执行:
$ wget https://www.nvidia.com/content/DriverDownload-March2009/confirmation.php?url=/tesla/450.80.02/NVIDIA-Linux-x86_64-450.80.02.run&lang=us&type=Tesla
安装 执行脚本安装:
$ chmod +x NVIDIA-Linux-x86_64-450.80.02.run && ./NVIDIA-Linux-x86_64-450.80.02.run
验证 使用以下命令验证是否安装成功 nvidia-smi
若是输出相似下图则驱动安装成功。
CUDA(Compute Unified Device Architecture)是显卡厂商 NVIDIA 推出的运算平台。CUDA™ 是一种由 NVIDIA 推出的通用并行计算架构,该架构使 GPU 可以解决复杂的计算问题。它包含了 CUDA 指令集架构(ISA)以及 GPU 内部的并行计算引擎。 这里安装的方式和显卡驱动安装相似。
访问官网下载
下载对应版本以下图
配置环境变量
$ echo 'export PATH=/usr/local/cuda/bin:$PATH' | sudo tee /etc/profile.d/cuda.sh $ source /etc/profile
nvidia-container-runtime 是在 runc 基础上多实现了 nvidia-container-runime-hook(如今叫 nvidia-container-toolkit),该 hook 是在容器启动后(Namespace已建立完成),容器自定义命令(Entrypoint)启动前执行。当检测到 NVIDIA_VISIBLE_DEVICES 环境变量时,会调用 libnvidia-container 挂载 GPU Device 和 CUDA Driver。若是没有检测到 NVIDIA_VISIBLE_DEVICES 就会执行默认的 runc。
下面分两步安装:
先设置 repository 和 GPG key:
$ curl -s -L https://nvidia.github.io/nvidia-container-runtime/gpgkey | sudo apt-key add - $ curl -s -L https://nvidia.github.io/nvidia-container-runtime/$(. /etc/os-release;echo $ID$VERSION_ID)/nvidia-container-runtime.list | sudo tee /etc/apt/sources.list.d/nvidia-container-runtime.list
安装:
$ apt install nvidia-container-runtime -y
若是 /etc/containerd
目录不存在,就先建立它:
$ mkdir /etc/containerd
生成默认配置:
$ containerd config default > /etc/containerd/config.toml
Kubernetes 使用设备插件(Device Plugins) 来容许 Pod 访问相似 GPU 这类特殊的硬件功能特性,但前提是默认的 OCI runtime 必须改为 nvidia-container-runtime
,须要修改的内容以下:
/etc/containerd/config.toml
... [plugins."io.containerd.grpc.v1.cri".containerd] snapshotter = "overlayfs" default_runtime_name = "runc" no_pivot = false ... [plugins."io.containerd.grpc.v1.cri".containerd.runtimes] [plugins."io.containerd.grpc.v1.cri".containerd.runtimes.runc] runtime_type = "io.containerd.runtime.v1.linux" # 将此处 runtime_type 的值改为 io.containerd.runtime.v1.linux ... [plugins."io.containerd.runtime.v1.linux"] shim = "containerd-shim" runtime = "nvidia-container-runtime" # 将此处 runtime 的值改为 nvidia-container-runtime ...
重启 containerd 服务:
$ systemctl restart containerd
一条命令解决战斗:
$ kubectl apply -f https://raw.githubusercontent.com/NVIDIA/k8s-device-plugin/v0.7.1/nvidia-device-plugin.yml
查看日志:
$ kubectl -n kube-system logs nvidia-device-plugin-daemonset-xxx 2020/12/04 06:30:28 Loading NVML 2020/12/04 06:30:28 Starting FS watcher. 2020/12/04 06:30:28 Starting OS watcher. 2020/12/04 06:30:28 Retreiving plugins. 2020/12/04 06:30:28 Starting GRPC server for 'nvidia.com/gpu' 2020/12/04 06:30:28 Starting to serve 'nvidia.com/gpu' on /var/lib/kubelet/device-plugins/nvidia-gpu.sock 2020/12/04 06:30:28 Registered device plugin for 'nvidia.com/gpu' with Kubelet
能够看到设备插件部署成功了。在 Node 上面能够看到设备插件目录下的 socket:
$ ll /var/lib/kubelet/device-plugins/ total 12 drwxr-xr-x 2 root root 4096 Dec 4 01:30 ./ drwxr-xr-x 8 root root 4096 Dec 3 05:05 ../ -rw-r--r-- 1 root root 0 Dec 4 01:11 DEPRECATION -rw------- 1 root root 3804 Dec 4 01:30 kubelet_internal_checkpoint srwxr-xr-x 1 root root 0 Dec 4 01:11 kubelet.sock= srwxr-xr-x 1 root root 0 Dec 4 01:11 kubevirt-kvm.sock= srwxr-xr-x 1 root root 0 Dec 4 01:11 kubevirt-tun.sock= srwxr-xr-x 1 root root 0 Dec 4 01:11 kubevirt-vhost-net.sock= srwxr-xr-x 1 root root 0 Dec 4 01:30 nvidia-gpu.sock=
首先测试本地命令行工具 ctr,这个应该没啥问题:
$ ctr images pull docker.io/nvidia/cuda:9.0-base $ ctr run --rm -t --gpus 0 docker.io/nvidia/cuda:9.0-base nvidia-smi nvidia-smi Fri Dec 4 07:01:38 2020 +-----------------------------------------------------------------------------+ | NVIDIA-SMI 440.95.01 Driver Version: 440.95.01 CUDA Version: 10.2 | |-------------------------------+----------------------+----------------------+ | 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 208... Off | 00000000:A1:00.0 Off | N/A | | 30% 33C P8 9W / 250W | 0MiB / 11019MiB | 0% Default | +-------------------------------+----------------------+----------------------+ +-----------------------------------------------------------------------------+ | Processes: GPU Memory | | GPU PID Type Process name Usage | |=============================================================================| | No running processes found | +-----------------------------------------------------------------------------+
最后进入终极测试:在 Pod 中测试 GPU 可用性。先建立部署清单:
gpu-pod.yaml
apiVersion: v1 kind: Pod metadata: name: cuda-vector-add spec: restartPolicy: OnFailure containers: - name: cuda-vector-add image: "k8s.gcr.io/cuda-vector-add:v0.1" resources: limits: nvidia.com/gpu: 1
执行 kubectl apply -f ./gpu-pod.yaml
建立 Pod。使用 kubectl get pod
能够看到该 Pod 已经启动成功:
$ kubectl get pod NAME READY STATUS RESTARTS AGE cuda-vector-add 0/1 Completed 0 3s
查看 Pod 日志:
$ kubectl logs 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
能够看到成功运行。这也说明 Kubernetes 完成了对 GPU 资源的调用。须要注意的是,目前 Kubernetes 只支持卡级别的调度,而且显卡资源是独占,没法在多个容器之间分享。
Kubernetes 1.18.2 1.17.5 1.16.9 1.15.12离线安装包发布地址http://store.lameleg.com ,欢迎体验。 使用了最新的sealos v3.3.6版本。 做了主机名解析配置优化,lvscare 挂载/lib/module解决开机启动ipvs加载问题, 修复lvscare社区netlink与3.10内核不兼容问题,sealos生成百年证书等特性。更多特性 https://github.com/fanux/sealos 。欢迎扫描下方的二维码加入钉钉群 ,钉钉群已经集成sealos的机器人实时能够看到sealos的动态。