K8S调度GPU介绍
技术背景
在我们平时创建资源时,经常会这样配置:
yaml
resources:
requests:
cpu: "1"
memory: "1Gi"
limits:
cpu: "2"
memory: "2Gi"
其中每个节点有多少 CPU、多少内存,kubelet 可以直接获取,scheduler 也能根据这些资源,把 Pod 调度到合适的节点。
但 GPU 不一样。GPU 属于不同厂商提供的专用硬件,比如 NVIDIA、AMD、Intel,每家的驱动、设备发现方式、容器使用方式都不一样。
如果 Kubernetes 自己把所有厂商的 GPU 管理逻辑都写进去,不仅代码会非常复杂,以后每增加一种硬件都要修改 Kubernetes 本身,维护成本也会很高。
因此,Kubernetes 采用了"插件化"的设计:
- Kubernetes 只负责提供统一的 Device Plugin 接口。
- 每个硬件厂商负责开发自己的 Device Plugin。
- Device Plugin 运行在节点上,负责发现 GPU、管理 GPU,并把 GPU 信息注册给 kubelet。
- kubelet 再把 GPU 作为一种扩展资源上报给 Kubernetes。
- 最终,Pod 就可以像申请 CPU、内存一样,通过
resources.limits申请 GPU。
简单来说:
CPU、内存:Kubernetes 自带支持。
GPU:Kubernetes 不直接管理,而是由厂商提供插件接入。
对于 NVIDIA GPU 来说,这个插件就是 NVIDIA Device Plugin。
安装并运行 NVIDIA Device Plugin 之后,节点上才会出现类似下面的资源:
plain
nvidia.com/gpu
Pod 才能通过下面这种方式申请 GPU:
yaml
resources:
limits:
nvidia.com/gpu: 1
也就是说,在 Kubernetes 里使用 NVIDIA GPU,不能只看宿主机上有没有驱动,还要看 Kubernetes 能不能识别和调度这个 GPU 资源。
整个调用过程可以分为如下三层:硬件系统层、容器层、Kubernetes 层
硬件系统层
在物理机上使用 NVIDIA GPU,最核心的组件是 NVIDIA Driver(驱动程序)。Driver 的作用是让操作系统能够识别、管理并驱动 NVIDIA GPU 硬件。
对于大多数 GPU,只要安装好 NVIDIA Driver,就可以正常使用 GPU。而对于 A100、H100、H800 等支持 NVSwitch 的服务器级 GPU,通常还需要安装并启动 NVIDIA Fabric Manager。
Fabric Manager 负责管理 NVSwitch 拓扑和 GPU 之间的高速互联,保证多 GPU 能够正常通信。如果 Fabric Manager 未正常运行,在这类服务器上可能会出现 GPU 无法正常初始化、GPU 间通信异常,甚至 nvidia-smi 无法正常显示 GPU 信息等问题。
驱动及相关组件安装完成后,通常可以通过 nvidia-smi 命令检查 GPU 是否工作正常。如果能够正常输出 GPU 型号、Driver Version、CUDA Version、显存使用情况等信息,说明宿主机已经成功识别 GPU,相关组件工作正常。
需要注意的是,nvidia-smi 输出中的 CUDA Version 表示当前 Driver 所支持的最高 CUDA Runtime 版本,并不代表宿主机已经安装了 CUDA Toolkit。
如果只是运行已经打包好的 CUDA 应用(例如 Docker 容器中的 AI 推理服务),通常只需要保证 Driver 版本满足容器内 CUDA Runtime 的兼容要求即可,无需在宿主机安装 CUDA Toolkit。
而如果需要在宿主机上开发或编译 CUDA 程序,例如使用 nvcc 编译 CUDA 代码,则还需要安装 CUDA Toolkit。CUDA Toolkit 包含 CUDA 编译器(nvcc)、头文件、运行时库、数学库以及调试、性能分析等开发工具,是 CUDA 应用开发所必需的组件。
因此,物理机环境可以简单理解为:
plain
NVIDIA GPU 硬件
↓
NVIDIA Driver
↓
(部分服务器需要)NVIDIA Fabric Manager
↓
nvidia-smi / CUDA 应用
其中:
- NVIDIA Driver:负责让操作系统识别并驱动 GPU。
- NVIDIA Fabric Manager:仅部分支持 NVSwitch 的服务器需要,负责管理 GPU 之间的高速互联。
- CUDA Toolkit:仅在开发或编译 CUDA 程序时需要,运行已编译好的 CUDA 应用通常无需安装。
这一层解决的核心问题是:操作系统能否正确识别和驱动 GPU,并为上层应用提供 GPU 计算能力。
容器层
进入 Docker 或 containerd 等容器环境后,仅安装 NVIDIA Driver 还不够。
这是因为容器默认是隔离运行的。即使宿主机已经能够正常识别 GPU,也不意味着容器能够直接访问 GPU。
要让容器使用 GPU,需要解决以下几个问题:
- 如何将 GPU 设备文件(如
/dev/nvidia*)映射到容器中; - 如何将 NVIDIA Driver 相关的库文件挂载到容器中;
- 容器运行时如何识别当前容器需要使用 GPU;
- 容器启动时需要注入哪些 NVIDIA 相关环境变量和运行能力。
这些工作都由 NVIDIA Container Toolkit 完成。
可以将 NVIDIA Container Toolkit 理解为 连接 NVIDIA Driver 与容器运行时的桥梁。它为 Docker、containerd、CRI-O 等容器运行时提供 GPU 支持,使容器能够正常访问宿主机上的 GPU。
整个容器环境的关系可以简单理解为:
plain
NVIDIA GPU 硬件
↓
NVIDIA Driver
↓
NVIDIA Container Toolkit
↓
Docker / containerd / CRI-O
↓
GPU 容器(可使用 GPU)
当容器启动时,NVIDIA Container Toolkit 会自动完成 GPU 设备、驱动库以及相关运行环境的注入,使容器能够像在宿主机上一样使用 GPU。
如果宿主机执行 nvidia-smi 正常,但容器内执行 nvidia-smi 失败,通常说明宿主机 Driver 没有问题,应重点检查 NVIDIA Container Toolkit 是否安装正确,以及 Docker 或 containerd 的运行时配置是否正确。
例如,在 Docker 环境下,可以使用下面的命令进行验证:
plain
docker run --rm --gpus all \
nvidia/cuda:12.4.1-base-ubuntu22.04 \
nvidia-smi
如果能够正常输出 GPU 型号、Driver Version、CUDA Version 等信息,说明容器运行时已经能够正确访问宿主机 GPU,NVIDIA Container Toolkit 配置正常。
这一层解决的核心问题是:容器能否正常使用宿主机的 GPU。
Kubernetes 层
在 Docker 或 containerd 中,只需要解决容器如何使用 GPU 的问题;而在 Kubernetes 中,除了让容器能够使用 GPU,还需要解决GPU 如何被 Kubernetes 感知、管理和调度的问题。
Kubernetes 在调度 Pod 之前,需要知道:
- 当前哪些节点安装了 GPU;
- 每个节点有多少张 GPU;
- 每张 GPU 是否已经被分配;
- 当 Pod 申请 GPU 时,应该调度到哪个节点。
这些信息并不是 NVIDIA Driver 或 NVIDIA Container Toolkit 能够提供的。
- NVIDIA Driver 负责让宿主机识别和驱动 GPU;
- NVIDIA Container Toolkit 负责让容器运行时能够使用 GPU;
- NVIDIA Device Plugin 则负责将 GPU 注册给 Kubernetes,使 Kubernetes 能够识别、统计和调度 GPU 资源。
可以将 NVIDIA Device Plugin 理解为 连接 GPU 与 Kubernetes 的桥梁。它运行在每个 GPU 节点上,负责发现本机 GPU,并通过 Kubernetes 提供的 Device Plugin 接口,将 GPU 信息注册给 kubelet。
注册完成后,kubelet 会将 GPU 作为扩展资源(如 nvidia.com/gpu)上报给 Kubernetes,scheduler 便可以根据这些资源进行调度。当 Pod 声明需要 GPU 时,scheduler 会选择满足条件的节点,而容器启动时再由 NVIDIA Container Toolkit 将 GPU 设备注入到容器中。
整个 Kubernetes 环境的关系可以简单理解为:
plain
NVIDIA GPU 硬件
↓
NVIDIA Driver
↓
NVIDIA Container Toolkit
↓
NVIDIA Device Plugin
↓
kubelet 注册 nvidia.com/gpu
↓
scheduler 根据 GPU 资源调度 Pod
↓
GPU Pod 启动并使用 GPU
例如,一个 Pod 可以通过下面的配置申请一张 GPU:
yaml
resources:
limits:
nvidia.com/gpu: 1
当 Kubernetes 看到 nvidia.com/gpu: 1 时,会先由 scheduler 选择一台还有可用 GPU 的节点,再由 kubelet 和 NVIDIA Container Toolkit 完成 GPU 设备的挂载,最终使容器能够正常使用 GPU。
因此,这三类组件分别负责不同层面的工作:
- 物理机层:NVIDIA Driver,让操作系统能够识别和驱动 GPU。
- 容器层:NVIDIA Container Toolkit,让容器能够使用宿主机 GPU。
- Kubernetes 层:NVIDIA Device Plugin,让 Kubernetes 能够发现、管理和调度 GPU。
这一层解决的核心问题是:Kubernetes 能否识别 GPU,并将 GPU 正确调度给需要它的 Pod。
组件依赖关系

|"① 强依赖
版本必须严格匹配驱动"| DRV
TOOLKIT -->|"② 依赖<br/>注入宿主机驱动库到容器"| DRV
DOCKER -->|"③ 依赖<br/>通过 runtime hook 实现 GPU 透传"| TOOLKIT
DP -->|"④ 依赖 NVML<br/>探测 GPU 数量/状态"| DRV
DP -->|"⑤ 依赖<br/>容器运行 + GPU 注入"| DOCKER
classDef base fill:#742a2a,stroke:#e53e3e,color:#fff,stroke-width:2px
classDef mid fill:#744210,stroke:#dd6b20,color:#fff,stroke-width:2px
classDef cont fill:#1a365d,stroke:#3182ce,color:#fff,stroke-width:2px
classDef k8s fill:#22543d,stroke:#38a169,color:#fff,stroke-width:2px
class DRV base
class FM mid
class TOOLKIT,DOCKER cont
class DP k8s
-->
调用链
启动阶段(初始化):
- 宿主机加载 GPU 驱动内核模块。
- (NVSwitch 机型)nvidia-fabricmanager 守护进程启动,调用驱动完成 NVSwitch/NVLink 拓扑初始化。没有这一步,多卡之间无法通过 NVLink 通信,甚至
nvidia-smi都会报错。 - k8s-device-plugin(通常以 DaemonSet 形式运行)启动,通过驱动的 NVML 库 (
libnvidia-ml.so) 探测本机有几块 GPU,然后通过 gRPC 向 kubelet 注册资源nvidia.com/gpu并上报数量。
调度阶段(创建 Pod):
- 用户提交一个请求
nvidia.com/gpu: 1的 Pod。 - K8s 调度器把 Pod 调度到有空闲 GPU 的节点。
- kubelet 通过 Device Plugin API 调用 k8s-device-plugin 的
Allocate方法,device-plugin 返回应该挂载哪些 GPU 设备、设置哪些环境变量(如NVIDIA_VISIBLE_DEVICES)。 - kubelet 把这些信息传给容器运行时(containerd/Docker)。
- 容器运行时在创建容器时触发 nvidia-container-toolkit 的 hook (
nvidia-container-runtime-hook)。 - toolkit 根据
NVIDIA_VISIBLE_DEVICES,通过libnvidia-container把宿主机的 GPU 设备节点(/dev/nvidia*)和驱动用户态库注入到容器的 namespace 中。 - 容器内的 CUDA 应用此时就能通过注入进来的
libcuda.so访问 GPU 了。
了解了各个组件的作用及它们之间的调用关系后,接下来通过实际操作,逐步完成 GPU 环境的搭建,并验证各个组件的工作流程,加深对整个 GPU 使用链路的理解。
GPU 节点配置
安装GPU驱动
开始之前,请确保您没有任何现有的 NVIDIA 驱动程序,可以使用以下命令卸载它们,并重新启动服务器。
bash
# 删除所有nvidia包
sudo apt purge '^nvidia-.*'
sudo apt purge '^libnvidia-.*'
sudo apt purge '^cuda-.*'
sudo apt purge '^libcuda.*'
sudo apt autoremove --purge
# 删除残留配置
sudo rm -rf /etc/modprobe.d/nvidia*
sudo rm -rf /etc/modules-load.d/nvidia*
sudo rm -rf /usr/local/cuda*
sudo rm -rf /var/lib/dkms/nvidia*
# 更新 initramfs
sudo update-initramfs -u
也可以使用官方提供的卸载脚本卸载(仅限之前通过官方.run 文件安装的驱动)
bash
/usr/bin/nvidia-uninstall
dpkg -r nvidia-fabricmanager-550
dpkg --purge nvidia-fabricmanager-550
dpkg -l | grep nvidia-fabricmanager
浏览官网https://www.nvidia.com/en-us/drivers/unix/,下载合适版本的驱动。
bash
wget https://download.nvidia.com/XFree86/Linux-x86_64/550.163.01/NVIDIA-Linux-x86_64-550.163.01.run
chmod +x NVIDIA-Linux-x86_64-550.163.01.run
./NVIDIA-Linux-x86_64-550.163.01.run -no-x-check -no-nouveau-check -no-opengl-files
重启并通过运行以下命令确保驱动程序正常工作:
bash
# nvidia-smi
Wed Oct 16 14:56:01 2024
+-----------------------------------------------------------------------------------------+
| NVIDIA-SMI 550.54.14 Driver Version: 550.54.14 CUDA Version: 12.4 |
|-----------------------------------------+------------------------+----------------------+
| GPU Name Persistence-M | Bus-Id Disp.A | Volatile Uncorr. ECC |
| Fan Temp Perf Pwr:Usage/Cap | Memory-Usage | GPU-Util Compute M. |
| | | MIG M. |
|=========================================+========================+======================|
| 0 NVIDIA A100-SXM4-80GB On | 00000000:3F:00.0 Off | 0 |
| N/A 32C P0 54W / 400W | 0MiB / 81920MiB | 0% Default |
| | | Disabled
安装nvidia-fabricmanager
专门用于管理多 GPU 系统中的 GPU 间通信优化,对于 A100、H100、H800 等支持 NVSwitch 的服务器级 GPU,确保GPU间的连接和通信的稳定性。
浏览官网:https://developer.download.nvidia.cn/compute/cuda/repos/,下载合适版本的软件包,以 ubuntu22.04 为例:
bash
wget https://developer.download.nvidia.cn/compute/cuda/repos/ubuntu2204/x86_64/nvidia-fabricmanager-550_550.163.01-1_amd64.deb
apt --fix-broken install -y
apt-get install ./nvidia-fabricmanager-550_550.163.01-1_amd64.deb
systemctl enable nvidia-fabricmanager
systemctl restart nvidia-fabricmanager
systemctl status nvidia-fabricmanager
安装容器工具包
容器环境使用 GPU 需要配置 NVIDIA runtime,具体可参考文档:https://docs.nvidia.com/datacenter/cloud-native/container-toolkit/latest/install-guide.html
我们首先配置容器工具包软件仓库
bash
curl -fsSL https://nvidia.github.io/libnvidia-container/gpgkey | sudo gpg --dearmor -o /usr/share/keyrings/nvidia-container-toolkit-keyring.gpg \
&& curl -s -L https://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' | \
sudo tee /etc/apt/sources.list.d/nvidia-container-toolkit.list
安装nvidia-container-toolkit
bash
apt-get update
apt-get install nvidia-container-toolkit -y
配置 containerd 运行时环境
备份现有的containerd配置,以防接下来的步骤出错
bash
sudo cp /etc/containerd/config.toml /etc/containerd/config.toml.bak
然后,我们可以根据k8s-device-plugin 自述文件手动配置containerd,或者运行
bash
sudo nvidia-ctk runtime configure --runtime=containerd
来将nvidia-container-runtime设置为containerd的默认底层运行时环境。
配置 docker 运行时环境
bash
# 配置 nvidia runtime
nvidia-ctk runtime configure --runtime=docker
# 重启 Docker
systemctl restart docker
验证是否成功
bash
docker run --rm --gpus all docker.io/nvidia/cuda:12.4.0-base-ubuntu22.04 nvidia-smi
k8s配置
要想让 kubelet 能够感知到节点上的 GPU 设备,以便进行 GPU 资源调度和管理,需要安装 k8s-device-plugin,具体可参考文档:https://github.com/NVIDIA/k8s-device-plugin
安装NVIDIA 设备插件
GPU 节点添加标签
bash
kubectl label nodes ${node} nvidia.com/gpu.present=true
安装工作的 CUDA 驱动程序、设置 NVIDIA 容器工具包和将 containerd 配置为使用 NVIDIA 运行时环境,我们现在可以使用其 Helm chart 来应用 NVIDIA 设备插件。
bash
helm repo add nvdp https://nvidia.github.io/k8s-device-plugin
helm repo update
helm search repo nvdp --devel
helm upgrade -i nvdp nvdp/nvidia-device-plugin \
--namespace nvidia-device-plugin \
--create-namespace \
--version 0.19.3
查看是否已经识别 gpu 资源
bash
# kubectl describe node | grep nvidia.com/gpu
nvidia.com/gpu.present=true
management.cattle.io/pod-limits: {"cpu":"22890m","ephemeral-storage":"8Gi","memory":"75780Mi","nvidia.com/gpu":"1"}
management.cattle.io/pod-requests: {"cpu":"11842m","ephemeral-storage":"200Mi","memory":"39990Mi","nvidia.com/gpu":"1","pods":"24"}
nvidia.com/gpu: 8
nvidia.com/gpu: 8
nvidia.com/gpu 0 0
测试验证
通过启动一个请求 GPU 资源的 pod 来使用 GPU。
yaml
apiVersion: v1
kind: Pod
metadata:
name: gpu-pod
spec:
restartPolicy: Never
containers:
- name: cuda-container
image: nvcr.io/nvidia/k8s/cuda-sample:vectoradd-cuda12.5.0
resources:
limits:
nvidia.com/gpu: "1" # 需要一张1GPU显卡资源
tolerations:
- key: nvidia.com/gpu
operator: Exists
effect: NoSchedule
kubectl apply -f cuda-vectoradd.yaml
如果一切顺利,工作负载的日志应该显示:
plain
kubectl logs -n cuda-test cuda-vectoradd
[Vector addition of 50000 elements]
... Test PASSED
查看请求 GPU 资源的 pod 内部,我们也会发现两个与 NVIDIA 相关的环境变量:
bash
kubectl exec -it <pod> -- env | grep NVIDIA
NVIDIA_DRIVER_CAPABILITIES=compute,video,utility
NVIDIA_VISIBLE_DEVICES=GPU-<UUID>
这表明我们在 pod 中有可用的 GPU 加速计算和视频编码/解码。
GPU 共享访问
NVIDIA 设备插件的默认行为是将整个 GPU 分配给单个 pod,这意味着如果有多个 pod 请求 GPU 时间,每次只会调度一个 pod。NVIDIA 设备插件通过其配置文件中一组扩展选项允许 GPU 的超额分配。有两种可用的共享方式:时间切片和 MPS,具体可参考文档:https://github.com/NVIDIA/k8s-device-plugin?tab=readme-ov-file#shared-access-to-gpus。
CUDA 时间切片和 MPS 的使用是互斥的。
- 在时间切片的情况下,CUDA 时间切片用于允许共享 GPU 的工作负载相互交错。然而,并未采取特殊措施来隔离从同一底层 GPU 获得副本的工作负载,每个工作负载都可以访问 GPU 内存,并在与其他所有工作负载相同的故障域中运行(这意味着如果一个工作负载崩溃,它们全部都会崩溃)。
- 在 MPS 的情况下,使用控制守护程序来管理对共享 GPU 的访问。与时间切片相反,MPS 进行空间分区,并允许内存和计算资源被显式地分区,并对每个工作负载强制执行这些限制。
两者对比如下:
| 维度 | CUDA timeslice | MPS(Multi-Process Service) |
|---|---|---|
| 原理 | GPU 在多个进程间按时间片轮转,同一时刻只有一个进程在跑 | 多个进程的 kernel 同时并发在 GPU 上跑(空间共享) |
| 上下文切换 | 有,频繁切换有开销 | 无,共享一个 CUDA context |
| 算力分配 | 轮流,无配额 | 可设每个客户端算力百分比上限(active thread percentage) |
| 显存限制 | 无 | 可限制每个客户端显存上限 (CUDA_MPS_PINNED_DEVICE_MEM_LIMIT) |
| 故障隔离 | 无 | 无(一个进程崩可能拖垮 MPS daemon 影响全部) |
| 延迟 | 时间片切换有抖动 | 并发执行,延迟更稳定、吞吐更高 |
使用 CUDA timeslice
首先创建一个ConfigMap,配置最大 10 个副本来配置时间切片。也就是说将一个 GPU 显卡拆分成了 10 个资源,假设一台服务器原本是 8 张 GPU 显卡,则现在可以使用的资源为 80 个。
yaml
# cm-time-slicing.yaml
apiVersion: v1
kind: ConfigMap
metadata:
name: cm-time-slicing
namespace: nvidia-device-plugin
data:
time-slicing: |-
version: v1
sharing:
timeSlicing:
resources:
- name: nvidia.com/gpu
replicas: 10
然后应用ConfigMap,并更新nvidia-device-plugin使用它。
bash
kubectl apply -f cm-time-slicing.yaml
helm upgrade nvdp nvdp/nvidia-device-plugin \
--reuse-values \
--set config.name=cm-time-slicing \
--set config.default=time-slicing
通过运行下面的命令看到每个节点每个 GPU 有 10 个nvidia.com/gpu的容量:
bash
kubectl get node -o 'jsonpath={.items[*].status.capacity}' | jq
{
...
"nvidia.com/gpu": "10",
...
}
请注意,工作负载从同一 GPU 获取副本,每个工作负载都可以访问相同的 GPU 内存,并在同一故障域中运行,这意味着如果一个工作负载崩溃,它们都会崩溃。
有关配置设备插件的更多详细信息,请参阅GitHub 上的自述文件。
使用 CUDA MPS
目前在启用了 MIG 的设备上不支持使用 MPS 进行共享
- 创建配置文件
yaml
cat << EOF > mps-config.yaml
version: v1
sharing:
mps:
resources:
- name: nvidia.com/gpu
replicas: 10
EOF
如果将此配置应用于具有 8 个 GPU 的节点,则该插件现在将向nvidia.com/gpuKubernetes 通告 80 个资源,而不是 8 个。每块卡会按照 10 分之一的资源来作为 nvidia.com/gpu: 1 受用。
- 添加节点标签
yaml
kubectl label nodes ${node} nvidia.com/mps.capable=true
- 更新 NVIDIA-K8s-Device-Plugin插件
bash
helm upgrade nvidia-device-plugin nvdp/nvidia-device-plugin \
--namespace nvidia-device-plugin \
--create-namespace \
--set-file config.map.config=mps-config.yaml
- 验证
bash
kubectl describe node miaohua-a-w-69 | grep nvidia.com/gpu
nvidia.com/gpu.present=true
management.cattle.io/pod-limits: {"cpu":"35270m","memory":"341212Mi","nvidia.com/gpu":"0"}
management.cattle.io/pod-requests: {"cpu":"35212m","memory":"341242Mi","nvidia.com/gpu":"0","pods":"15"}
nvidia.com/gpu: 80
nvidia.com/gpu: 80
nvidia.com/gpu 0 0
CUDA MIG
功能介绍
多实例GPU(MIG)功能允许将NVIDIA A卡或者H卡安全地划分为多个独立的GPU实例,供CUDA应用程序使用。例如,NVIDIA A100支持最多七个独立的GPU实例。
MIG为多个用户提供了独立的GPU资源,以实现最佳的GPU利用率。该功能对于未能充分利用GPU计算能力的工作负载特别有益,因此用户可能希望并行运行不同的工作负载,以最大化资源的利用。
技术对比
| 特性 | Time-Slicing | MPS | MIG |
|---|---|---|---|
| 资源分配方式 | 按时间动态分配 | 动态共享 | 静态划分 |
| 资源隔离 | 无资源隔离 | 无资源隔离 | 硬件级资源隔离 |
| 性能开销 | 上下文切换开销 | 较小(减少上下文切换) | 无上下文切换开销 |
| 硬件支持 | 所有 CUDA GPU | 所有 CUDA GPU | 仅支持 MIG 的 GPU |
| 适用任务 | 非关键任务 | 高性能计算、多进程任务 | 多租户环境、实时推理任务 |
| 配置复杂度 | 无需配置,默认启用 | 需要配置 MPS 服务 | 需要显式创建 MIG 实例 |
部署MIG
启用 MIG 模式
在宿主机上运行以下命令来启用 MIG 模式,如果启用失败多半是因为资源占用,可以停止相关 gpu 资源然后执行 nvidia-smi -r或者重启服务器。
bash
# nvidia-smi -mig 1
Enabled MIG Mode for GPU 00000000:3F:00.0
Enabled MIG Mode for GPU 00000000:44:00.0
Enabled MIG Mode for GPU 00000000:62:00.0
Enabled MIG Mode for GPU 00000000:68:00.0
Enabled MIG Mode for GPU 00000000:A9:00.0
Enabled MIG Mode for GPU 00000000:AD:00.0
Enabled MIG Mode for GPU 00000000:D2:00.0
Enabled MIG Mode for GPU 00000000:D5:00.0
All done.
除了将所有显卡都启用 mig 模式外,也可以指定显卡启用 mig,例如只开启 GPU 0 的 mig。
bash
# nvidia-smi -i 0 -mig 1
创建GI实例
启用 MIG 模式后,你需要为每个 GPU 创建 MIG 实例,创建GI实例,即我们所需要的子GPU,首先我们产看一下可以创建些什么样的子GPU
查看 0 号 GPU 显卡支持的 MIG 规格
bash
# nvidia-smi mig -i 0 -lgip
+-----------------------------------------------------------------------------+
| GPU instance profiles: |
| GPU Name ID Instances Memory P2P SM DEC ENC |
| Free/Total GiB CE JPEG OFA |
|=============================================================================|
| 0 MIG 1g.10gb 19 0/7 9.50 No 14 0 0 |
| 1 0 0 |
+-----------------------------------------------------------------------------+
| 0 MIG 1g.10gb+me 20 0/1 9.50 No 14 1 0 |
| 1 1 1 |
+-----------------------------------------------------------------------------+
| 0 MIG 1g.20gb 15 0/4 19.50 No 14 1 0 |
| 1 0 0 |
+-----------------------------------------------------------------------------+
| 0 MIG 2g.20gb 14 0/3 19.50 No 28 1 0 |
| 2 0 0 |
+-----------------------------------------------------------------------------+
| 0 MIG 3g.40gb 9 0/2 39.25 No 42 2 0 |
| 3 0 0 |
+-----------------------------------------------------------------------------+
| 0 MIG 4g.40gb 5 0/1 39.25 No 56 2 0 |
| 4 0 0 |
+-----------------------------------------------------------------------------+
| 0 MIG 7g.80gb 0 0/1 78.75 No 98 5 0 |
| 7 1 1 |
+-----------------------------------------------------------------------------+
创建 GI 实例
可以看到 0 号显卡最多支持 7g.80gb 资源,我们可以对资源进行拆分,只要总和不超过这个最大值既可。
例如在第 0 块显卡创建 GPU 的计算核心数量为 3g,显存 40gb 的资源和一个计算核心 4g,显存为 40gb 的资源。
bash
# nvidia-smi mig -cgi 3g.40gb,4g.40gb -i 0
Successfully created GPU instance ID 1 on GPU 0 using profile MIG 3g.40gb (ID 9)
Successfully created GPU instance ID 2 on GPU 0 using profile MIG 4g.40gb (ID 5)
验证实例创建情况:
bash
# nvidia-smi mig -lgi
+-------------------------------------------------------+
| GPU instances: |
| GPU Name Profile Instance Placement |
| ID ID Start:Size |
|=======================================================|
| 0 MIG 3g.40gb 9 1 4:4 |
+-------------------------------------------------------+
| 0 MIG 4g.40gb 5 2 0:4 |
+-------------------------------------------------------+
如需清除创建的 mig 实例
bash
# nvidia-smi mig -dgi -i 0 # 删除GPU0上的所有 GPU 实例
创建CI实例
上述操作只创建了GI,这些GI并不能直接使用,
查看物理卡的状态
bash
# nvidia-smi -i 0
Tue Jan 7 13:31:24 2025
+-----------------------------------------------------------------------------------------+
| NVIDIA-SMI 550.54.14 Driver Version: 550.54.14 CUDA Version: 12.4 |
|-----------------------------------------+------------------------+----------------------+
| GPU Name Persistence-M | Bus-Id Disp.A | Volatile Uncorr. ECC |
| Fan Temp Perf Pwr:Usage/Cap | Memory-Usage | GPU-Util Compute M. |
| | | MIG M. |
|=========================================+========================+======================|
| 0 NVIDIA A100-SXM4-80GB On | 00000000:3F:00.0 Off | On |
| N/A 28C P0 53W / 400W | 87MiB / 81920MiB | N/A Default |
| | | Enabled |
+-----------------------------------------+------------------------+----------------------+
+-----------------------------------------------------------------------------------------+
| MIG devices: |
+------------------+----------------------------------+-----------+-----------------------+
| GPU GI CI MIG | Memory-Usage | Vol| Shared |
| ID ID Dev | BAR1-Usage | SM Unc| CE ENC DEC OFA JPG |
| | | ECC| |
|==================+==================================+===========+=======================|
| No MIG devices found |
+-----------------------------------------------------------------------------------------+
+-----------------------------------------------------------------------------------------+
| Processes: |
| GPU GI CI PID Type Process name GPU Memory |
| ID ID Usage |
|=========================================================================================|
| No running processes found |
+-----------------------------------------------------------------------------------------+
显示No MIG devices found,因为它没有创建对应的计算实例CI,因此还需要创建 CI。
查看CI的profile 信息
bash
# nvidia-smi mig -i 0 -lcip
+--------------------------------------------------------------------------------------+
| Compute instance profiles: |
| GPU GPU Name Profile Instances Exclusive Shared |
| Instance ID Free/Total SM DEC ENC OFA |
| ID CE JPEG |
|======================================================================================|
| 0 1 MIG 1c.3g.40gb 0 3/3 14 2 0 0 |
| 3 0 |
+--------------------------------------------------------------------------------------+
| 0 1 MIG 2c.3g.40gb 1 1/1 28 2 0 0 |
| 3 0 |
+--------------------------------------------------------------------------------------+
| 0 1 MIG 3g.40gb 2* 1/1 42 2 0 0 |
| 3 0 |
+--------------------------------------------------------------------------------------+
| 0 2 MIG 1c.4g.40gb 0 4/4 14 2 0 0 |
| 4 0 |
+--------------------------------------------------------------------------------------+
| 0 2 MIG 2c.4g.40gb 1 2/2 28 2 0 0 |
| 4 0 |
+--------------------------------------------------------------------------------------+
| 0 2 MIG 4g.40gb 3* 1/1 56 2 0 0 |
| 4 0 |
+--------------------------------------------------------------------------------------+
在 GPU 0 的 GPU Instance 1 和 2 上分别创建 Compute Instances(CI),指定了两个 CI Profiles:0 和 1。 也就是1c.3g.40gb 和2c.3g.40gb
bash
# nvidia-smi mig -i 0 -cci 0,1 -gi 1
Successfully created compute instance ID 0 on GPU 0 GPU instance ID 1 using profile MIG 1c.3g.40gb (ID 0)
Successfully created compute instance ID 1 on GPU 0 GPU instance ID 1 using profile MIG 2c.3g.40gb (ID 1)
# nvidia-smi mig -i 0 -cci 0,1 -gi 2
Successfully created compute instance ID 0 on GPU 0 GPU instance ID 2 using profile MIG 1c.4g.40gb (ID 0)
Successfully created compute instance ID 1 on GPU 0 GPU instance ID 2 using profile MIG 2c.4g.40gb (ID 1)
查看创建的设备信息
bash
# nvidia-smi -i 0
Tue Jan 7 13:45:24 2025
+-----------------------------------------------------------------------------------------+
| NVIDIA-SMI 550.54.14 Driver Version: 550.54.14 CUDA Version: 12.4 |
|-----------------------------------------+------------------------+----------------------+
| GPU Name Persistence-M | Bus-Id Disp.A | Volatile Uncorr. ECC |
| Fan Temp Perf Pwr:Usage/Cap | Memory-Usage | GPU-Util Compute M. |
| | | MIG M. |
|=========================================+========================+======================|
| 0 NVIDIA A100-SXM4-80GB On | 00000000:3F:00.0 Off | On |
| N/A 28C P0 53W / 400W | 87MiB / 81920MiB | N/A Default |
| | | Enabled |
+-----------------------------------------+------------------------+----------------------+
+-----------------------------------------------------------------------------------------+
| MIG devices: |
+------------------+----------------------------------+-----------+-----------------------+
| GPU GI CI MIG | Memory-Usage | Vol| Shared |
| ID ID Dev | BAR1-Usage | SM Unc| CE ENC DEC OFA JPG |
| | | ECC| |
|==================+==================================+===========+=======================|
| 0 1 0 0 | 37MiB / 40192MiB | 14 0 | 3 0 2 0 0 |
| | 0MiB / 65535MiB | | |
+------------------+ +-----------+-----------------------+
| 0 1 1 1 | | 28 0 | 3 0 2 0 0 |
| | | | |
+------------------+----------------------------------+-----------+-----------------------+
| 0 2 0 2 | 49MiB / 40192MiB | 14 0 | 4 0 2 0 0 |
| | 0MiB / 65535MiB | | |
+------------------+ +-----------+-----------------------+
| 0 2 1 3 | | 28 0 | 4 0 2 0 0 |
| | | | |
+------------------+----------------------------------+-----------+-----------------------+
+-----------------------------------------------------------------------------------------+
| Processes: |
| GPU GI CI PID Type Process name GPU Memory |
| ID ID Usage |
|=========================================================================================|
| No running processes found |
+-----------------------------------------------------------------------------------------+
查看资源规格列表
bash
# nvidia-smi -L
GPU 0: NVIDIA A100-SXM4-80GB (UUID: GPU-59227d3b-92c1-9394-2694-e5d2d09d7ca6)
MIG 1c.3g.40gb Device 0: (UUID: MIG-ea8d189c-bcdb-519a-a97e-8a2e7848bc1c)
MIG 2c.3g.40gb Device 1: (UUID: MIG-28722365-8992-5bc1-bc81-c8bd010e507c)
MIG 1c.4g.40gb Device 2: (UUID: MIG-54f0f6f3-0c7c-5087-b810-9770732e8591)
MIG 2c.4g.40gb Device 3: (UUID: MIG-b8753643-33b5-589f-bc5f-da5995b5674c)
如需清除创建的 ci 实例
bash
# nvidia-smi mig -dci -i 0 # 删除GPU0上的所有CI实例
同时创建 CI+GI 实例
如果要直接创建一个子GPU 并且将其可用的运算单元都挂载上,在创建GI的时候添加-C参数即可完成。
bash
# nvidia-smi mig -i 1 -cgi 2g.20gb,2g.20gb,1g.10gb -C
Successfully created GPU instance ID 3 on GPU 1 using profile MIG 2g.20gb (ID 14)
Successfully created compute instance ID 0 on GPU 1 GPU instance ID 3 using profile MIG 2g.20gb (ID 1)
Successfully created GPU instance ID 5 on GPU 1 using profile MIG 2g.20gb (ID 14)
Successfully created compute instance ID 0 on GPU 1 GPU instance ID 5 using profile MIG 2g.20gb (ID 1)
Successfully created GPU instance ID 9 on GPU 1 using profile MIG 1g.10gb (ID 19)
Successfully created compute instance ID 0 on GPU 1 GPU instance ID 9 using profile MIG 1g.10gb (ID 0)
查看资源规格列表
bash
# nvidia-smi -L
GPU 0: NVIDIA A100-SXM4-80GB (UUID: GPU-59227d3b-92c1-9394-2694-e5d2d09d7ca6)
MIG 1c.3g.40gb Device 0: (UUID: MIG-ea8d189c-bcdb-519a-a97e-8a2e7848bc1c)
MIG 2c.3g.40gb Device 1: (UUID: MIG-28722365-8992-5bc1-bc81-c8bd010e507c)
MIG 1c.4g.40gb Device 2: (UUID: MIG-54f0f6f3-0c7c-5087-b810-9770732e8591)
MIG 2c.4g.40gb Device 3: (UUID: MIG-b8753643-33b5-589f-bc5f-da5995b5674c)
GPU 1: NVIDIA A100-SXM4-80GB (UUID: GPU-13d510f6-4f49-f720-697a-91908f12e2d6)
MIG 2g.20gb Device 0: (UUID: MIG-593bb78a-c62d-51f5-970b-5056771ec6fb)
MIG 2g.20gb Device 1: (UUID: MIG-658e3359-4288-54e8-bb01-98ae7c9448ea)
MIG 1g.10gb Device 2: (UUID: MIG-6b765df0-e1a2-54ab-9525-224e8d14ce0a)
更新 nvidia-device-plugin 配置
migStrategy策略分为以下几种:
none策略禁用 MIG
single策略 每个 GPU 只能创建一个 MIG 实例。
mixed策略 允许创建多个不同的 MIG 实例。
bash
# helm upgrade nvdp -n nvidia-device-plugin . -f values.yaml --set migStrategy=mixed
验证 Kubernetes识别 MIG 实例
执行以下命令,确认 Kubernetes 节点上已经注册了 GPU 资源,如果数据未更新,可重启nvidia-device-plugin 后再次查看。
bash
# kubectl describe node gpu-1 | grep mig
nvidia.com/mig-1g.10gb: 1
nvidia.com/mig-2g.20gb: 2
nvidia.com/mig-3g.40gb: 2
nvidia.com/mig-4g.40gb: 2
nvidia.com/mig-1g.10gb: 1
nvidia.com/mig-2g.20gb: 2
nvidia.com/mig-3g.40gb: 2
nvidia.com/mig-4g.40gb: 2
配置 Pod 使用 MIG 实例
编写一个 Pod 配置文件来使用 MIG 资源:
yaml
apiVersion: v1
kind: Pod
metadata:
name: mig-demo-pod
spec:
containers:
- name: cuda-container
image: nvidia/cuda:11.8.0-base
resources:
limits:
nvidia.com/mig-3g.40gb: 1
command: ["nvidia-smi"]
DCGM exporter 部署
参考文档:https://github.com/NVIDIA/dcgm-exporter
安装 exporter
helm 部署 exporter
bash
# helm repo add gpu-helm-charts https://nvidia.github.io/dcgm-exporter/helm-charts
# helm pull gpu-helm-charts/dcgm-exporter --untar
# cd dcgm-exporter/
# vim values.yaml
nodeSelector: # 添加nvidia节点标签调度
nvidia.com/gpu.present: "true"
kubernetes: # 包含pod标签和uuid
enablePodLabels: true
enablePodUID: true
# helm install dcgm-exporter -n nvidia-device-plugin . -f values.yaml
NAME: dcgm-exporter
LAST DEPLOYED: Wed Aug 27 15:33:29 2025
NAMESPACE: nvidia-device-plugin
STATUS: deployed
REVISION: 1
TEST SUITE: None
NOTES:
1. Get the application URL by running these commands:
export POD_NAME=$(kubectl get pods -n nvidia-device-plugin -l "app.kubernetes.io/name=dcgm-exporter,app.kubernetes.io/instance=dcgm-exporter" -o jsonpath="{.items[0].metadata.name}")
kubectl -n nvidia-device-plugin port-forward $POD_NAME 8080:9400 &
echo "Visit http://127.0.0.1:8080/metrics to use your application"
查看验证
bash
# kubectl get pod -n nvidia-device-plugin
NAME READY STATUS RESTARTS AGE
nvdp-nvidia-device-plugin-6mnv4 1/1 Running 0 20m
dcgm-exporter-8d2db 1/1 Running 0 2m53s
# kubectl get svc -n nvidia-device-plugin
NAME TYPE CLUSTER-IP EXTERNAL-IP PORT(S) AGE
dcgm-exporter ClusterIP 10.107.116.236 <none> 9400/TCP 36s
创建ServiceMonitor
yaml
apiVersion: monitoring.coreos.com/v1
kind: ServiceMonitor
metadata:
name: dcgm-exporter
namespace: monitoring
spec:
jobLabel: dcgm-exporter
endpoints:
- interval: 30s
port: metrics
path: /metrics
scheme: http
relabelings: # 新增ip标签方便关联查询
- action: replace
regex: (.*)
replacement: $1
sourceLabels:
- __meta_kubernetes_pod_host_ip
targetLabel: ip
selector: # svc标签选择器,匹配service的labels
matchLabels:
app.kubernetes.io/component: dcgm-exporter
app.kubernetes.io/instance: dcgm-exporter
app.kubernetes.io/name: dcgm-exporter
namespaceSelector: # namespace选择
matchNames:
- nvidia-device-plugin
查看 prometheus targets

导入 dashboard
参考 dashboard:https://grafana.com/grafana/dashboards/12239-nvidia-dcgm-exporter-dashboard/

常用 promql
GPU 常用指标可参考文档:https://help.aliyun.com/zh/ack/ack-managed-and-ack-dedicated/user-guide/introduction-to-metrics#section-ts3-5l7-lwm
- 总 GPU 数
bash
count(DCGM_FI_DEV_DEC_UTIL)
- 空闲 GPU 数
bash
DCGM_FI_DEV_DEC_UTIL{exported_namespace=""}
- 各 deployment 资源使用量
bash
count(DCGM_FI_DEV_DEC_UTIL{})by(exported_namespace)
- 各 deployment 资源使用率
bash
avg by (exported_namespace, deployment) (
label_replace(
DCGM_FI_DEV_GPU_UTIL{},
"deployment",
"$1",
"exported_pod",
"^(.*)-[^-]+-[^-]+$"
)
)
禁用GPU
如果单个 GPU 硬件出现故障,为了避免将资源调度到异常 GPU 运行,可以将故障 GPU 禁用。
bash
1. 查询 GPU 的编号
# nvidia-smi
2. 将指定的 GPU(0000:D0:00.0)设置为排空状态,并在 1 秒内完成该操作。
# nvidia-smi drain -p 0000:D0:00.0 -m 1
3. 此命令将指定的 PCI 设备(0000:d0:00.0)从系统中移除。
echo "1" | sudo tee /sys/bus/pci/devices/0000:d0:00.0/remove
3. 启用指定的 PCI 设备(0000:d0:00.0)。重新启用设备并恢复其工作状态。
echo "0" | sudo tee /sys/bus/pci/devices/0000:d0:00.0/enable
4. 将指定的 PCI 设备(0000:d0:00.0)从 NVIDIA 驱动程序中解绑。
echo -n "0000:d0:00.0" | sudo tee /sys/bus/pci/drivers/nvidia/unbind