K8S项目实践(08): 在ECS、Docker、K8s 等环境中使用 GPU
1. 引言
本文主要分享在不同环境,例如ECS、Docker 和 Kubernetes 等环境中如何使用 GPU。 注:由于没有物理机裸机,在阿里云上申请ECS也可满足学习使用。
2. 规划
基于如下环境搭建:

查看worker节点GPU信息:
[root@k8s-worker1 ~]# lspci | grep -i nvidia
00:07.0 VGA compatible controller: NVIDIA Corporation TU104GL [Tesla T4] (rev a1)
[root@k8s-worker1 ~]#
说明该worker节点有1张NVIDIA Tesla T4的GPU卡。
3. 概述
仅以比较常见的 NVIDIA GPU 举例,系统为 Linux,对于其他厂家的 GPU 设备理论上流程都是一样的。
省流:
- 对于ECS环境,只需要安装对应的 GPU Driver(GPU计算型实例为Tesla驱动,GPU虚拟化型实例为GRID驱动) 以及 CUDA Toolkit 。
- 对应 Docker 环境,需要额外安装 nvidia-container-toolkit 并配置 docker 使用 nvidia runtime。
- 对应 k8s 环境,需要额外安装对应的 device-plugin 使得 kubelet 能够感知到节点上的 GPU 设备,以便 k8s 能够进行 GPU 管理。
注:一般在 k8s 中使用都会直接使用 gpu-operator 方式进行安装,本文主要为了搞清各个组件的作用,因此进行手动安装。
ps;下一篇分享下如何使用 gpu-operator 快速完成安装
4. ECS环境
裸机中要使用上 GPU 需要安装以下组件:
- GPU Driver
- CUDA Toolkit 二者的关系如 NVIDIA 官网上的这个图所示:

GPU Driver 包括了 GPU 驱动和 CUDA 驱动,CUDA Toolkit 则包含了 CUDA Runtime。
GPU 作为一个 PCIE 设备,只要安装好之后,在系统中就可以通过 lspci 命令查看到,先确认机器上是否有 GPU:
[root@k8s-worker1 ~]# lspci | grep -i nvidia
00:07.0 VGA compatible controller: NVIDIA Corporation TU104GL [Tesla T4] (rev a1)
[root@k8s-worker1 ~]#
说明该worker节点有1张NVIDIA Tesla T4的GPU卡。
4.1. 安装GRID驱动
由于主机规格是ecs.sgn6i-vws-m2.xlarge,是虚拟化型规格,不能安装Tesla驱动的,需要安装grid驱动。 安装Tesla驱动的话将会出现ERROR: Unable to load the kernel module ‘nvidia.ko’.错误安装失败。
安装步骤参考:在GPU虚拟化型实例中安装GRID驱动(Linux)
4.1.1. 准备安装脚本
install-grid.sh内容如下:
#!/bin/bash
if acs-plugin-manager --list --local | grep grid_driver_install > /dev/null 2>&1
then
acs-plugin-manager --remove --plugin grid_driver_install
fi
acs-plugin-manager --exec --plugin grid_driver_install
4.1.2. 安装grid
[root@k8s-worker1 ~]# sh install-grid.sh
RemovePlugin success, plugin[grid_driver_install]
INFO[0000] Starting environment pre-check
INFO[0000] environment pre-check done
INFO[0000] Check gpu device present
INFO[0000] Check gpu device present done
INFO[0000] current installed gird driver is, 470.239.06
INFO[0000] current installed gird driver is already SWL driver
[root@k8s-worker1 ~]#
4.1.3. 验证
root@k8s-worker1 ~]# nvidia-smi
运行成功,可看到有一张T4-2Q的GPU卡。

至此,我们就安装好 GPU 驱动了,系统也能正常识别到 GPU。
这里显示的 CUDA 版本表示当前驱动最大支持的 CUDA 版本。
4.2. 安装CUDA
4.2.1. 安装软件
wget https://developer.download.nvidia.com/compute/cuda/11.4.0/local_installers/cuda_11.4.0_470.42.01_linux.run
sudo sh cuda_11.4.0_470.42.01_linux.run
由于已安装了GRID驱动,需取消cuda自带的驱动安装:

01) 安装全部组件:

02) 输出:

03) 执行以下命令,重启GPU实例
reboot
04) 依次执行以下命令,配置CUDA环境变量。
echo 'export PATH=/usr/local/cuda/bin:$PATH' | sudo tee /etc/profile.d/cuda.sh
source /etc/profile
05) 检查CUDA是否成功安装。
a) 执行nvcc -V命令,检查CUDA安装版本是否正确。

b) 依次执行以下命令,测试CUDA Samples,验证CUDA是否安装成功。
[root@k8s-worker1 ~]# cd /usr/local/cuda-11.4/extras/demo_suite/
[root@k8s-worker1 demo_suite]# ./deviceQuery
如果返回结果显示Result=PASS,则表示CUDA安装成功。

06) 测试 我们使用一个简单的 Pytorch 程序来检测 GPU 和 CUDA 是否正常。
整个调用链大概是这样的:

使用下面代码来测试能够正常使用, check_cuda_pytorch.py 内容如下:
import torch
def check_cuda_with_pytorch():
"""检查 PyTorch CUDA 环境是否正常工作"""
try:
print("检查 PyTorch CUDA 环境:")
if torch.cuda.is_available():
print(f"CUDA 设备可用,当前 CUDA 版本是: {torch.version.cuda}")
print(f"PyTorch 版本是: {torch.__version__}")
print(f"检测到 {torch.cuda.device_count()} 个 CUDA 设备。")
for i in range(torch.cuda.device_count()):
print(f"设备 {i}: {torch.cuda.get_device_name(i)}")
print(f"设备 {i} 的显存总量: {torch.cuda.get_device_properties(i).total_memory / (1024 ** 3):.2f} GB")
print(f"设备 {i} 的显存当前使用量: {torch.cuda.memory_allocated(i) / (1024 ** 3):.2f} GB")
print(f"设备 {i} 的显存最大使用量: {torch.cuda.memory_reserved(i) / (1024 ** 3):.2f} GB")
else:
print("CUDA 设备不可用。")
except Exception as e:
print(f"检查 PyTorch CUDA 环境时出现错误: {e}")
if __name__ == "__main__":
check_cuda_with_pytorch()
先安装下 torch
python -m pip install torch
运行一下
python check_cuda_pytorch.py
正常输出应该是这样的:

4.3. 更新CUDA
由于有些应用需要更高级的版本的CUDA,需升级,如下升级为12.6版本。
sudo dnf config-manager --add-repo https://developer.download.nvidia.com/compute/cuda/repos/rhel8/x86_64/cuda-rhel8.repo
sudo dnf clean all
sudo dnf -y install cuda-toolkit-12-6

验证:

说明12.6版本安装成功。

5. Docker环境
上一步中我们已经在裸机上安装了 GPU Driver,CUDA Toolkit 等工具,实现了在宿主机上使用 GPU。
现在希望在 Docker 容器中使用 GPU,需要怎么处理呢?
为了让 Docker 容器中也能使用 GPU,大致步骤如下:
- 安装docker,已有则跳过这步骤。
- 安装 nvidia-container-toolkit 组件
- docker 配置使用 nvidia-runtime
- 启动容器时增加 –gpu 参数
5.1. Docker安装
5.1.1. 安装必要的一些系统工具
sudo yum install -y yum-utils
5.1.2. 添加软件源信息
sudo yum install docker-ce docker-ce-cli containerd.io docker-buildx-plugin docker-compose-plugin
5.1.3. 安装Docker
sudo yum install docker-ce docker-ce-cli containerd.io docker-buildx-plugin docker-compose-plugin
5.1.4. 开启Docker服务
sudo service docker start
5.1.5. 验证
root@k8s-worker1 pytorch]# docker version
Client: Docker Engine - Community
Version: 26.1.3
API version: 1.45
Go version: go1.21.10
Git commit: b72abbb
Built: Thu May 16 08:34:39 2024
OS/Arch: linux/amd64
Context: default
Server: Docker Engine - Community
Engine:
Version: 26.1.3
API version: 1.45 (minimum version 1.24)
Go version: go1.21.10
Git commit: 8e96db1
Built: Thu May 16 08:33:34 2024
OS/Arch: linux/amd64
Experimental: false
containerd:
Version: 1.6.32
GitCommit: 8b3b7ca2e5ce38e8f31a34f35b2b68ceb8470d89
runc:
Version: 1.1.12
GitCommit: v1.1.12-0-g51d5e94
docker-init:
Version: 0.19.0
GitCommit: de40ad0
[root@k8s-worker1 pytorch]#
5.2. 安装 nvidia-container-toolkit
NVIDIA Container Toolkit 的主要作用是将 NVIDIA GPU 设备挂载到容器中。 >兼容生态系统中的任意容器运行时,docker、containerd、cri-o 等。
NVIDIA 官方安装文档:nvidia-container-toolkit-install-guide
ALIOS或centos安装命令如下:
# Configure the production repository:
curl -s -L https://nvidia.github.io/libnvidia-container/stable/rpm/nvidia-container-toolkit.repo | \
sudo tee /etc/yum.repos.d/nvidia-container-toolkit.repo
# Optionally, configure the repository to use experimental packages:
sudo yum-config-manager --enable nvidia-container-toolkit-experimental
#Install the NVIDIA Container Toolkit packages:
sudo yum install -y nvidia-container-toolkit
安装成功如下:

5.3. 配置使用该 runtime
支持 Docker, Containerd, CRI-O, Podman 等 CRI。 >具体见官方文档 container-toolkit#install-guide
这里以 Docker 为例进行配置: 旧版本需要手动在 /etc/docker/daemon.json 中增加配置,指定使用 nvidia 的 runtime。
"runtimes": {
"nvidia": {
"args": [],
"path": "nvidia-container-runtime"
}
}
新版 toolkit 带了一个nvidia-ctk 工具,执行以下命令即可一键配置然后重启docker:
sudo nvidia-ctk runtime configure --runtime=docker
sudo systemctl restart docker

5.4. 验证
安装nvidia-container-toolkit 后,整个调用链如下:

调用链从 containerd –> runC 变成 containerd –> nvidia-container-runtime –> runC 。
然后 nvidia-container-runtime 在中间拦截了容器 spec,就可以把 gpu 相关配置添加进去,再传给 runC 的 spec 里面就包含 gpu 信息了。
Docker 环境中的 CUDA 调用大概是这样的:

从图中可以看到,CUDA Toolkit 跑到容器里了,因此宿主机上不需要再安装 CUDA Toolkit。
使用一个带 CUDA Toolkit 的镜像即可。
最后我们启动一个 Docker 容器进行测试,其中命令中增加 –gpu参数来指定要分配给容器的 GPU。
gpu 参数可选值:
- gpus all:表示将所有 GPU 都分配给该容器
- gpus “device=
[, …]“:对于多 GPU 场景,可以通过 id 指定分配给容器的 GPU,例如 –gpu “device=0” 表示只分配 0 号 GPU 给该容器 GPU 编号则是通过nvidia-smi 命令进行查看
这里我们直接使用一个带 cuda 的镜像来测试,启动该容器并执行nvidia-smi 命令
[root@k8s-worker1 ~]# docker run --rm --gpus all nvcr.io/nvidia/cuda:11.0.3-runtime-ubuntu20.04 nvidia-smi

正常情况下应该是可以打印出容器中的 GPU 信息的。
注: 镜像需与grid驱动版本兼容,否则报错。
6. K8S环境
更进一步,在 k8s 环境中使用 GPU,则需要在集群中部署以下组件:
- gpu-device-plugin 用于管理 GPU,device-plugin 以 DaemonSet 方式运行到集群各个节点,以感知节点上的 GPU 设备,从而让 k8s 能够对节点上的 GPU 设备进行管理。
- gpu-exporter:用于监控 GPU
各组件关系如下图所示:

左图为手动安装的场景,只需要在集群中安装 device-plugin 和 监控即可使用。
右图为使用 gpu-operotar 安装场景,本篇暂时忽略
大致工作流程如下:
- 每个节点的 kubelet 组件维护该节点的 GPU 设备状态(哪些已用,哪些未用)并定时报告给调度器,调度器知道每一个节点有多少张 GPU 卡可用。
- 调度器为 pod 选择节点时,从符合条件的节点中选择一个节点。
- 当 pod 调度到节点上后,kubelet 组件为 pod 分配 GPU 设备 ID,并将这些 ID 作为参数传递给 NVIDIA Device Plugin
- NVIDIA Device Plugin 将分配给该 pod 的容器的 GPU 设备 ID 写入到容器的环境变量 NVIDIA_VISIBLE_DEVICES中,然后将信息返回给 kubelet。
- kubelet 启动容器。
- NVIDIA Container Toolkit 检测容器的 spec 中存在环境变量 NVIDIA_VISIBLE_DEVICES,然后根据环境变量的值将 GPU 设备挂载到容器中。 在 Docker 环境我们在启动容器时通过 –gpu 参数手动指定分配给容器的 GPU,k8s 环境则由 device-plugin 自行管理。
6.1. 集群环境

安装 device-plugin
device-plugin 一般由对应的 GPU 厂家提供,比如 NVIDIA 的 k8s-device-plugin
安装其实很简单,将对应的 yaml apply 到集群即可。
kubectl create -f https://raw.githubusercontent.com/NVIDIA/k8s-device-plugin/v0.15.0/deployments/static/nvidia-device-plugin.yml
就像这样

device-plugin 启动之后,会感知节点上的 GPU 设备并上报给 kubelet,最终由 kubelet 提交到 kube-apiserver。
因此我们可以在 Node 可分配资源中看到 GPU,就像这样:

可以看到,除了常见的 cpu、memory 之外,还有nvidia.com/gpu, 这个就是 GPU 资源,数量为 0,应该为1,错误原因待查。

安装 GPU 监控
除此之外,如果你需要监控集群 GPU 资源使用情况,你可能还需要安装 DCCM exporter 结合 Prometheus 输出 GPU 资源监控信息。
安装略。
小结
本文主要分享了在ECS、Docker 环境、k8s 环境中如何使用 GPU。
对于ECS环境,只需要安装对应的 GPU Driver 即可。
对应 Docker 环境,需要额外安装 nvidia-container-toolkit 并配置 docker 使用 nvidia runtime。
对应 k8s 环境,需要额外安装对应的 device-plugin 使得 kubelet 能够感知到节点上的 GPU 设备,以便 k8s 能够进行 GPU 管理。
现在一般都是在 k8s 环境中使用,为了简化安装步骤, NVIDIA 也提供了 gpu-operator来简化安装部署,后续分享一下如何使用 gpu-operator来快速安装。
7. 参考资料
【02】在GPU计算型实例中手动安装Tesla驱动(Linux)
【03】在GPU虚拟化型实例中安装GRID驱动(Linux)
8. FAQ
8.1. ERROR: Unable to load the kernel module ‘nvidia.ko’.

错误详情提示:

作者:mospan
微信关注:墨斯潘園
本文出处:http://mospany.github.io/2024/01/16/gpu-on-k8s/
文章版权归本人所有,欢迎转载,但未经作者同意必须保留此段声明,且在文章页面明显位置给出原文连接,否则保留追究法律责任的权利。
