裸机中要使用上 GPU 需要安装以下组件:
GPU Driver 包括了 GPU 驱动和 CUDA 驱动,CUDA Toolkit 则包含了 CUDA Runtime。
GPU 作为一个 PCIE 设备,只要安装好之后,在系统中就可以通过 lspci 命令查看到,先确认机器上是否有 GPU:
lspci|grepNVIDIA
可以看到,该设备有1张 Tesla V100 GPU。
首先到 NVIDIA 驱动下载 下载对应的显卡驱动:
复制下载链接
wgethttps://cn.download.nvidia.com/tesla/550.144.03/nvidia-driver-local-repo-ubuntu2204-550.144.03_1.0-1_amd64.deb
sudoaptupdate &&sudoaptupgrade -ysudoaptinstall-ybuild-essential dkmssudodpkg -invidia-driver-local-repo-ubuntu2204-550.144.03_1.0-1_amd64.deb
安装 NVIDIA 驱动:sudoaptinstall-ynvidia-driver-550nvidia-smi
至此,我们就安装好 GPU 驱动了,系统也能正常识别到 GPU。
这里显示的 CUDA 版本表示当前驱动最大支持的 CUDA 版本。
对于深度学习程序,一般都要依赖 CUDA 环境,因此需要在机器上安装 CUDA Toolkit。
也是到 NVIDIA CUDA Toolkit 下载 下载对应的安装包,选择操作系统和安装方式即可
wgethttps://developer.download.nvidia.com/compute/cuda/repos/ubuntu2204/x86_64/cuda-keyring_1.1-1_all.debsudo dpkg -icuda-keyring_1.1-1_all.debsudo apt-getupdatesudo apt-get-yinstallcuda-toolkit-12-4
配置下 PATH
整个调用链:
代码测试:
importtorchdef check_cuda_with_pytorch(): """检查 PyTorch CUDA 环境是否正常工作""" try: print("检查 PyTorch CUDA 环境:")iftorch.cuda.is_available(): print(f"CUDA 设备可用,当前 CUDA 版本是: { torch.version.cuda}")print(f"PyTorch 版本是: { torch.__version__}")print(f"检测到 { torch.cuda.device_count()} 个 CUDA 设备。")foriinrange(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()
调用链从 containerd --> runC 变成 containerd --> nvidia-container-runtime --> runC 。
nvidia-container-runtime 在中间拦截了容器 spec,就可以把 gpu 相关配置添加进去,再传给 runC 的 spec 里面就包含 gpu 信息了。
Ubuntu 上安装 Docker: 30sudoaptinstall-yapt-transport-https ca-certificates curlsoftware-properties-common 31curl-fsSLhttps://download.docker.com/linux/ubuntu/gpg |sudogpg --dearmor-o/usr/share/keyrings/docker-archive-keyring.gpg 32echo"deb [arch=amd64 signed-by=/usr/share/keyrings/docker-archive-keyring.gpg] https://download.docker.com/linux/ubuntu $(lsb_release -cs)stable"|sudotee/etc/apt/sources.list.d/docker.list >/dev/null 33aptupdate 34aptinstall-ydocker-ce docker-ce-cli containerd.io 35systemctl enabledocker
# 1. Configure the production repositorycurl-fsSLhttps://nvidia.github.io/libnvidia-container/gpgkey |sudogpg --dearmor-o/usr/share/keyrings/nvidia-container-toolkit-keyring.gpg \&&curl-s-Lhttps://nvidia.github.io/libnvidia-container/stable/deb/nvidia-container-toolkit.list |\sed's#deb https://#deb [signed-by=/usr/share/keyrings/nvidia-container-toolkit-keyring.gpg] https://#g'|\sudotee/etc/apt/sources.list.d/nvidia-container-toolkit.list# Optionally, configure the repository to use experimental packages sed-i-e'/experimental/ s/^#//g'/etc/apt/sources.list.d/nvidia-container-toolkit.list# 2. Update the packages list from the repositorysudoapt-getupdate# 3. Install the NVIDIA Container Toolkit packagessudoapt-getinstall-ynvidia-container-toolkit
支持 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 工具,执行以下命令即可一键配置:
sudonvidia-ctk runtime configure --runtime=docker
然后重启 Docker 即可
systemctl restart docker
Docker 环境中的 CUDA 调用:
从图中可以看到,CUDA Toolkit 跑到容器里了,因此宿主机上不需要再安装 CUDA Toolkit。
使用一个带 CUDA Toolkit 的镜像即可。
最后我们启动一个 Docker 容器进行测试,其中命令中增加 --gpu参数来指定要分配给容器的 GPU。
--gpu 参数可选值:--gpus all:表示将所有 GPU 都分配给该容器--gpus "device=<id>[,<id>...]":对于多 GPU 场景,可以通过 id 指定分配给容器的 GPU,例如 --gpu "device=0" 表示只分配 0 号 GPU 给该容器GPU 编号则是通过nvidia-smi 命令进行查看
这里我们直接使用一个带 cuda 的镜像来测试,启动该容器并执行nvidia-smi 命令
dockerrun --rm--gpusall nvidia/cuda:12.0.1-runtime-ubuntu22.04 nvidia-smi
正常情况下应该是可以打印出容器中的 GPU 信息:
在 k8s 环境中使用 GPU,则需要在集群中部署以下组件:
gpu-device-plugin用于管理 GPU,device-plugin 以 DaemonSet 方式运行到集群各个节点,以感知节点上的 GPU 设备,从而让 k8s 能够对节点上的 GPU 设备进行管理。
gpu-exporter:用于监控 GPU
device-plugin 一般由对应的 GPU 厂家提供,比如 NVIDIA 的 k8s-device-plugin
安装其实很简单,将对应的 yaml apply 到集群即可。
kubectl create -fhttps://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,就像这样:
root@test:~# k describe node test|grep Capacity -A7Capacity: cpu: 48ephemeral-storage: 460364840Ki hugepages-1Gi: 0hugepages-2Mi: 0memory: 98260824Ki nvidia.com/gpu: 2pods: 110
除了常见的 cpu、memory 之外,还有nvidia.com/gpu, 这个就是 GPU 资源
安装 DCCM exporter 结合 Prometheus 输出 GPU 资源监控信息。
helm repo addgpu-helm-charts \https://nvidia.github.io/dcgm-exporter/helm-charts helm repo update helm install\--generate-name \gpu-helm-charts/dcgm-exporter
查看 metrics
curl-sLhttp://127.0.0.1:8080/metrics# HELP DCGM_FI_DEV_SM_CLOCK SM clock frequency (in MHz).# TYPE DCGM_FI_DEV_SM_CLOCK gauge# HELP DCGM_FI_DEV_MEM_CLOCK Memory clock frequency (in MHz).# TYPE DCGM_FI_DEV_MEM_CLOCK gauge# HELP DCGM_FI_DEV_MEMORY_TEMP Memory temperature (in C).# TYPE DCGM_FI_DEV_MEMORY_TEMP gauge...DCGM_FI_DEV_SM_CLOCK{ gpu="0", UUID="GPU-604ac76c-d9cf-fef3-62e9-d92044ab6e52",container="",namespace="",pod=""}139DCGM_FI_DEV_MEM_CLOCK{ gpu="0", UUID="GPU-604ac76c-d9cf-fef3-62e9-d92044ab6e52",container="",namespace="",pod=""}405DCGM_FI_DEV_MEMORY_TEMP{ gpu="0", UUID="GPU-604ac76c-d9cf-fef3-62e9-d92044ab6e52",container="",namespace="",pod=""}9223372036854775794
…
测试
在 k8s 创建 Pod 要使用 GPU 资源很简单,和 cpu、memory 等常规资源一样,在 resource 中 申请即可。
比如,下面这个 yaml 里面我们就通过 resource.limits 申请了该 Pod 要使用 1 个 GPU。
apiVersion: v1kind: Podmetadata: name: gpu-podspec: restartPolicy: Never containers: - name: cuda-container image: nvcr.io/nvidia/k8s/cuda-sample:vectoradd-cuda10.2 resources: limits: nvidia.com/gpu: 1# requesting 1 GPU
这样 kueb-scheduler 在调度该 Pod 时就会考虑到这个情况,将其调度到有 GPU 资源的节点。
启动后,查看日志,正常应该会打印 测试通过的信息,k8s 环境中就可以使用 GPU 了。
kubectl logs gpu-pod[Vector addition of 50000elements]Copy input data from the hostmemory to the CUDA deviceCUDA kernel launch with 196blocks of 256threadsCopy output data from the CUDA device to the hostmemoryTest PASSEDDone