Kubernetes GPU 调度与设备插件排障实战:从 Device Plugin 到 CDI

KubernetesGPU调度Device Plugin
于 2026-10-01 05:31:13 修改
·本内容遵循CC 4.0 BY-SA版权协议

1. 从一张"显卡插上去却没人用"的工单说起

先说个真实场景。集群里新到了一批卡,物理机 lspci 能看到设备,nvidia-smi 也正常输出,但业务方提交的 Pod 死活起不来,事件里就一句 Insufficient nvidia.com/gpu。运维第一反应是"卡坏了",第二反应是"驱动没装",折腾半天发现卡好好的、驱动也好好的,问题出在 Kubernetes 压根不知道这张卡的存在。

这个场景几乎是我这几年处理 GPU 集群问题时遇到频率最高的一类。它背后牵扯的东西比想象中多:设备怎么被 K8s 发现、怎么被调度、怎么被容器真正拿到手里、驱动和运行时怎么配合、版本怎么对齐。任何一个环节断掉,表现都是"卡在,但用不了"。

这篇东西就是围绕这条链路展开的。我会从选型开始讲——到底该用原生 Device Plugin 还是直接上 GPU Operator,CDI 又是什么时候该引入;然后拆原理,把 kubelet 的 device manager、Allocate 接口、容器运行时这几层讲透;最后落到排障,把那些"看起来像驱动问题其实是调度问题""看起来像调度问题其实是 CDI 没开"的坑一个个摆出来。适合正在搭 GPU 集群、或者已经被 GPU 调度问题折磨过一轮的同行看,新手也能顺着链路建立完整认知。

需要提前说明的是,下面涉及的版本、参数、命令都基于我实际跑过的环境(K8s 1.26 到 1.29、NVIDIA 驱动 535/550 系列、containerd 1.7),不同版本细节会有差异,但排查思路是通用的。

2. 选型这件事:原生 Device Plugin、GPU Operator 与 CDI 的边界

2.1 原生 Device Plugin 方案适合什么样的团队

原生方案说白了就是:你自己装驱动、自己装 nvidia-container-toolkit、自己部署 nvidia-device-plugin 的 DaemonSet,然后配 RuntimeClass。它的优点是链路透明,每一层你都知道装了什么、版本是多少,出问题好定位。

我一般建议这几类团队走原生路线:集群规模不大(几十张卡以内)、驱动版本长期固定、有专人维护节点镜像、对"黑盒组件"比较警惕。因为 GPU Operator 会往集群里塞一堆 DaemonSet 和 CRD,一旦它自己出问题,排查成本反而更高。

原生方案的核心组件其实就三个:

  • 节点侧驱动:nvidia-driver,负责让内核认识卡。
  • 容器运行时钩子:nvidia-container-toolkit,负责在容器启动时把设备节点和驱动库注入进去。
  • K8s 侧插件:nvidia-device-plugin,负责把 GPU 作为扩展资源上报给 kubelet。

三者版本必须互相兼容,这是原生方案最容易翻车的地方。我见过驱动 550 配 toolkit 1.11 结果容器里 libcuda.so 找不到的案例,就是因为 toolkit 版本太老不认识新驱动的库路径。

2.2 GPU Operator 到底帮你做了什么

GPU Operator 本质是把上面那三个组件(外加 DCGM、Node Feature Discovery、MIG Manager 等)全部 Operator 化,用 CRD 声明式管理。你写一个 ClusterPolicy,它就自动在带 GPU 的节点上把驱动、toolkit、plugin 全装好。

它最大的价值不是"省事",而是版本矩阵被官方验证过。NVIDIA 会保证某个 Operator 版本对应的驱动、toolkit、plugin 组合是兼容的,这对没有专职 GPU 运维的团队来说是刚需。

但有几个坑必须提前知道:

  • Operator 默认会自己装驱动,如果你的节点镜像里已经有驱动,必须显式设置 driver.enabled=false,否则它会尝试覆盖,轻则报错重则把节点搞挂。
  • 它依赖 Node Feature Discovery 打标签,如果 NFD 没正常工作,Operator 会认为节点没有 GPU,什么都不部署。
  • 升级 Operator 版本时,它会滚动重启所有 GPU 相关 DaemonSet,正在跑训练的 Pod 可能被驱逐,务必配好 PDB 和升级窗口。

2.3 CDI 是什么,什么时候必须开

CDI(Container Device Interface)是容器设备注入的一套标准规范。在它出现之前,设备注入靠的是运行时钩子(nvidia-container-runtime)在容器创建时动态改 OCI spec。CDI 则把"这个设备需要哪些节点、哪些库、哪些环境变量"提前写成一份声明文件,运行时直接读。

为什么现在越来越强调 CDI?因为 K8s 1.26 之后,kubelet 的 Device Plugin 机制开始支持把设备信息以 CDI 形式传给运行时,链路更干净,也更容易和 MIG、时间片共享这些高级特性配合。

判断要不要开 CDI,我的经验是:

场景 是否建议开 CDI
单卡整卡分配,版本较老 可不开,传统钩子够用
需要 MIG 切分 强烈建议开
需要 GPU 时间片共享 必须开
containerd 1.7+ / CRI-O 1.25+ 建议开,原生支持好
集群里混用多种设备类型 建议开,声明式更清晰

开启方式不复杂,containerd 里在 enable_cdi = true 并配好 cdi_spec_dirs,然后 Device Plugin 侧加 --enable-cdi 参数即可。但要注意,开了 CDI 之后,原来依赖运行时钩子的老镜像可能行为变化,需要回归测试。

3. 拆开看:一张 GPU 从物理设备到 Pod 里可用,中间发生了什么

3.1 kubelet 的 Device Manager 是怎么记账的

很多人以为 GPU 调度是 scheduler 直接管设备,其实不是。scheduler 只认"扩展资源"这个数字,比如节点上报 nvidia.com/gpu: 4,它就当有 4 个可分配单位。真正决定"哪个 Pod 用哪张卡"的是 kubelet 的 Device Manager。

流程是这样的:Device Plugin 通过 gRPC 向 kubelet 注册,声明自己管理 nvidia.com/gpu 这个资源,并上报设备列表(每个设备有 ID 和健康状态)。kubelet 的 Device Manager 维护一张分配表,Pod 调度到节点后,kubelet 在 admit 阶段调用 Device Plugin 的 Allocate 接口,拿到"这个容器需要挂哪些设备节点、哪些环境变量"。

这里有个关键点:Device Manager 的分配是节点本地行为,scheduler 不参与。所以如果你看到 Pod 被调度到某节点却起不来,问题大概率在 Device Manager 到 Plugin 这一段,而不是调度器。

3.2 Allocate 接口返回的到底是什么

Allocate 返回的是一组 ContainerAllocateResponse,里面包含:

  • 设备节点路径:比如 /dev/nvidia0、/dev/nvidiactl、/dev/nvidia-uvm。
  • 环境变量:比如 NVIDIA_VISIBLE_DEVICES=0。
  • 挂载点:驱动库目录,比如 /usr/lib/x86_64-linux-gnu/libcuda.so。

传统模式下,这些信息由 kubelet 传给容器运行时,运行时再调用 nvidia-container-runtime 钩子去实际注入。CDI 模式下,Plugin 会把这些信息写成 CDI spec 文件,运行时直接读文件,不再走钩子。

理解这一点非常重要,因为排障时你要判断的正是"信息有没有正确传到运行时"。如果 Allocate 返回正常但容器里没设备,问题就在运行时侧;如果 Allocate 根本没被调用,问题在 Device Manager 或 Plugin 注册环节。

3.3 容器运行时这一层最容易出什么岔子

运行时这层的典型故障有三类:

第一类是 RuntimeClass 没配对。如果你用的是 nvidia 这个 RuntimeClass,但 containerd 配置里对应的 runtime 名字写错了,容器会用默认 runc 启动,结果就是设备节点没注入,容器里 nvidia-smi 报"command not found"或"no devices found"。

第二类是 toolkit 版本与驱动不匹配。toolkit 负责告诉运行时"驱动库在哪",如果它内置的路径列表和实际驱动安装路径对不上,就会出现容器里找不到 libnvidia-ml.so 的情况。这个错误很隐蔽,因为节点上一切正常。

第三类是 CDI spec 目录权限问题。CDI 文件通常放在 /etc/cdi 或 /var/run/cdi,如果 containerd 进程没有读权限,它会静默忽略这些文件,表现就是"CDI 开了但没生效"。

我一般排查运行时这层,会先看 containerd 日志里有没有 CDI 或 nvidia 相关报错,再进容器 ls /dev/nvidia* 确认设备节点在不在,最后 ldconfig -p | grep nvidia 看库能不能找到。三步基本能定位到具体是哪一类。

4. 排障实战:那些"看起来是 A 其实是 B"的经典案例

4.1 案例一:Pod 一直 Pending,事件说资源不足

这是最经典的一类。表面看是"节点没卡了",但实际可能有好几种原因。

排查链路:

  1. 先 kubectl describe node <node> 看 Allocatable 里有没有 nvidia.com/gpu。如果没有,说明 Device Plugin 没上报成功。
  2. 看 Device Plugin 的 Pod 日志,有没有 Registered device plugin 字样。没有的话,检查它和 kubelet 的 socket 路径是否一致(默认 /var/lib/kubelet/device-plugins)。
  3. 如果上报了但数量不对,检查是不是有卡处于 unhealthy 状态。Plugin 会把不健康的卡排除,导致可分配数变少。
  4. 如果数量对但 Pod 还是 Pending,看是不是有别的 Pod 占着但没释放。这种情况常见于 Pod 卡在 Terminating,Device Manager 的分配表没回收。

我遇到过一次特别隐蔽的:节点上报了 4 张卡,但实际只有 3 张能用,第 4 张因为 ECC 错误被标记 unhealthy。业务方申请 4 卡的任务永远 Pending,而 nvidia-smi 看四张卡都在。最后是靠 Plugin 日志里的 unhealthy device 关键字才定位到。

4.2 案例二:容器起来了,但 nvidia-smi 报 "No devices were found"

这个报错和上一个完全不同,Pod 是 Running 的,只是容器里看不到卡。

根因通常有三个:

  • RuntimeClass 没指定或指定错。Pod spec 里漏了 runtimeClassName: nvidia,容器用默认运行时启动,自然没设备。
  • CDI 和钩子冲突。同时开了 CDI 又保留了老钩子,两者注入逻辑打架,结果设备节点挂了一半。
  • 设备节点权限问题。容器以非 root 运行,而 /dev/nvidia* 权限是 660 root:root,非 root 用户读不到。这种情况要么调整设备权限,要么在 Pod 里配 securityContext。

我个人的经验是,遇到这个报错先别急着查驱动,先 kubectl get pod -o yaml | grep runtimeClassName,十有八九是这里的问题。确认没问题再进容器 ls -l /dev/nvidia* 看节点在不在、权限对不对。

4.3 案例三:MIG 模式下资源数量对不上

MIG(Multi-Instance GPU)是把一张物理卡切成多个实例。开了 MIG 之后,节点上报的资源名会变成 nvidia.com/mig-1g.5gb 这种带 profile 的形式,数量也不再是物理卡数。

常见坑是:MIG 配置改了但 Plugin 没重启。MIG 的切分是在节点侧用 nvidia-smi mig 做的,Plugin 启动时读取当前 MIG 布局并上报。如果你改了切分但没重启 Plugin,它上报的还是旧布局,调度就会错乱。

另一个坑是 MIG 和 CDI 的配合。MIG 实例的设备节点路径和整卡不同,必须靠 CDI 才能正确注入。如果没开 CDI,容器里拿到的可能是整卡而不是 MIG 实例,隔离就失效了。

排查 MIG 问题,我一般按这个顺序:nvidia-smi -L 看物理卡,nvidia-smi mig -lgip 看支持的 profile,nvidia-smi mig -lgi 看当前实例,然后对比 kubectl describe node 里的资源名和数量。三者对不上,就是配置和上报不同步。

4.4 案例四:升级驱动后集群集体失灵

这个坑杀伤力最大。驱动升级后,节点重启,nvidia-smi 正常,但所有 GPU Pod 起不来。

原因通常是 toolkit 和 plugin 还是旧版本,不认识新驱动的库路径或设备节点命名。NVIDIA 驱动大版本升级有时会改 libnvidia-* 的路径或新增设备节点,老 toolkit 的注入规则就失效了。

我的做法是:驱动升级必须和 toolkit、plugin、Operator 版本一起规划,参考官方的兼容矩阵,不要单独升驱动。升级顺序也有讲究——先升 toolkit 和 plugin,再升驱动,最后重启节点。反过来做,中间会有一段所有 GPU Pod 都不可用的窗口。

5. 版本矩阵与配置清单:一份可以直接抄的对照表

5.1 组件兼容性对照

下面这张表是我根据实际跑过的组合整理的,不是官方矩阵的照搬,而是"我验证过能跑"的组合:

K8s 版本 containerd 驱动 toolkit device-plugin 是否开 CDI
1.26 1.6.x 535 1.13 0.14 否
1.27 1.7.x 535 1.14 0.14 可选
1.28 1.7.x 550 1.15 0.15 建议
1.29 1.7.x 550 1.16 0.15 建议

需要强调的是,驱动版本和 CUDA 版本是两回事。驱动向下兼容多个 CUDA 版本,但容器里的 CUDA 版本由镜像决定。所以选型时先确定业务需要的 CUDA 版本,再反推最低驱动版本,最后选 toolkit 和 plugin。

5.2 关键配置项清单

containerd 侧需要确认的配置:

TOML
[plugins."io.containerd.grpc.v1.cri".containerd]
default_runtime_name = "runc"
 
[plugins."io.containerd.grpc.v1.cri".containerd.runtimes.nvidia]
runtime_type = "io.containerd.runc.v2"
[plugins."io.containerd.grpc.v1.cri".containerd.runtimes.nvidia.options]
BinaryName = "/usr/bin/nvidia-container-runtime"
 
[plugins."io.containerd.grpc.v1.cri"]
enable_cdi = true
cdi_spec_dirs = ["/etc/cdi", "/var/run/cdi"]

Device Plugin 侧的关键参数:

  • --enable-cdi=true:开启 CDI 模式。
  • --fail-on-init-error=true:初始化失败直接退出,避免"假装正常"。
  • --pass-device-specs=true:把设备 spec 透传给运行时,CDI 模式下需要。

Pod 侧的最小配置:

YAML
apiVersion: v1
kind: Pod
metadata:
name: gpu-test
spec:
runtimeClassName: nvidia
containers:
- name: cuda
image: nvidia/cuda:12.2.0-base-ubuntu22.04
command: ["nvidia-smi"]
resources:
limits:
nvidia.com/gpu: 1

注意 resources.limits 里写 GPU 是必须的,写在 requests 里不生效——这是 K8s 扩展资源的规则,requests 会被自动设成和 limits 相同。

6. 几个我踩过之后才明白的细节

6.1 关于时间片共享的取舍

GPU 时间片共享(time-slicing)能让多个 Pod 共用一张卡,配置上是在 Device Plugin 的 ConfigMap 里声明 sharing.timeSlicing.resources。听起来很美,但有几个现实问题:

  • 没有显存隔离。多个 Pod 共享同一张卡的显存,一个 Pod 显存爆了会拖垮其他 Pod。
  • 没有算力隔离。时间片是轮转调度,一个重负载 Pod 会明显影响同卡其他 Pod 的延迟。
  • 监控变复杂。DCGM 上报的指标是整卡维度,很难拆到单个 Pod。

我的建议是:时间片共享只适合推理类、负载轻、对延迟不敏感的场景。训练任务千万别用,一个任务跑飞全卡遭殃。真要做隔离,上 MIG,虽然切分粒度粗,但隔离是硬件级的。

6.2 关于节点标签和污点

GPU 节点通常要打污点,防止普通 Pod 调度上去占资源。但污点配置有个细节:如果你用 NoSchedule,已经调度上去的 Pod 不受影响;用 NoExecute 会驱逐现有 Pod。生产环境我一般用 NoSchedule,配合节点亲和性让 GPU Pod 显式声明。

标签方面,除了 K8s 自带的 nvidia.com/gpu.present,我习惯再加几个自定义标签,比如 gpu-type=a100、gpu-mig=enabled,方便业务方用 nodeSelector 精确选节点。这比让业务方去猜资源名要友好得多。

6.3 关于监控和告警

GPU 集群不监控等于裸奔。我一般会部署 DCGM Exporter,把 GPU 利用率、显存、温度、ECC 错误、XID 错误都采集到 Prometheus。

几个必须配的告警:

  • XID 错误:这是驱动层报的硬件/驱动异常,出现就要关注,某些 XID 码意味着卡要挂了。
  • ECC 双比特错误:不可纠正错误,出现基本要换卡。
  • 显存使用率持续 100%:可能是显存泄漏。
  • GPU 利用率长期为 0 但 Pod 在跑:可能是任务卡死或没真正用上 GPU。

我踩过一次坑:业务方反馈任务慢,查了半天发现容器里根本没拿到 GPU,任务在 CPU 上跑。如果当时有"Pod 声明了 GPU 但 GPU 利用率为 0"的告警,五分钟就能定位。

6.4 关于镜像里的 CUDA 版本

容器里的 CUDA 版本由镜像决定,和节点驱动是解耦的。但有个约束:驱动版本必须 >= 镜像 CUDA 版本要求的最低驱动。比如 CUDA 12.2 要求驱动至少 535,如果你节点是 525,容器里就会报 "CUDA driver version is insufficient"。

这个报错经常被误判成"驱动没装",其实是版本不够。排查时先 nvidia-smi 看节点驱动版本,再看镜像的 CUDA 版本,对照 NVIDIA 的兼容表确认。

7. 写在最后的一点个人体会

GPU 集群这套东西,难的不是装,是"装完之后怎么知道它真的在工作"。我见过太多集群,nvidia-smi 一切正常,但业务方实际用不上卡,或者用上了但性能只有一半。根因往往不在某个组件坏了,而在组件之间的衔接没对齐。

我的习惯是,每搭完一个 GPU 集群,必做三件事:跑一个最小 CUDA 容器验证设备可见,跑一个多卡任务验证 NCCL 通信,跑一个长时间任务观察显存和利用率曲线。这三件事过了,才算真正交付。

另外,版本管理一定要做台账。驱动、toolkit、plugin、Operator、CUDA、K8s,六个版本记清楚,升级前先查兼容矩阵。GPU 这套生态的版本耦合比普通中间件紧得多,凭感觉升级迟早出事。

至于 CDI,我的态度是:新集群直接开,老集群评估后再开。它是趋势,早用早省心,但迁移时一定要做回归测试,别在生产窗口里第一次验证。

Kubernetes GPU 调度和 Device Plugin、CDI、NFD、GPU Operator 概述
随着人工智能和机器学习发展,GPU成Kubernetes重要资源,但Kubernetes原调度机制未对其原生支持。本文以GPU调度为例,介绍了Kubernetes引入的Device Plugin、Container Device Interface、Node Feature Discovery和GPU Operator等扩展机制的工作原理和应用,展示了GPU资源管理和调度流程。
凌虚NPG
1234
NVIDIA k8s-device-plugin源码分析与安装部署
本文以nvidia管理GPU的开源项目k8s-device-plugin为例,介绍设备插件侧实现。先回顾Kubernetes Device Plugin逻辑,接着深入解读k8s-device-plugin源码,包括main、startPlugins等函数。还阐述Allocate方法实现GPU资源多维度适配。最后给出部署实践,含环境配置、安装工具及验证k8s调度GPU功能。
nuczzz
2902
NVIDIA k8s-device-plugin完全指南:Kubernetes GPU管理终极解决方案
本文详细介绍NVIDIA k8s-device-plugin在Kubernetes中管理GPU资源的完整方案,涵盖安装部署、配置选项、资源共享、监控诊断及生产最佳实践,适用于AI训练与大规模计算场景。
荣钧群
1275
kubernetes Device Plugin原理与源码分析
本文深入剖析Kubernetes Device Plugin,介绍其诞生背景、核心架构、注册与上报流程。对kubelet设备管理核心流程进行源码分析,包括初始化、注册、资源上报等。同时指出Device Plugin架构局限性,对比CDI方案优势与挑战,还提及未来混合模式、原生支持等演进方向。
nuczzz
2422
开发指南:NVIDIA k8s-device-plugin源码解析与二次开发入门
本文深入解析NVIDIA k8s-device-plugin的核心架构与源码实现,涵盖插件管理、资源调度、gRPC通信等关键模块,提供二次开发入门指南,包括自定义设备发现、新增资源配置、CDI集成及性能优化建议,助力开发者高效扩展GPU资源管理能力。
邹娇振Marvin
721
【NVIDIA】NVIDIA k8s-device-plugin v0.19.3 系统级架构分析
本文深入剖析NVIDIA k8s-device-plugin v0.19.3的系统级架构,涵盖DaemonSet部署模式、gRPC Device Plugin协议实现、多后端设备发现(NVML/Tegra/WSL)、MIG/vGPU/CDI等核心模块设计,以及工厂模式、策略模式等架构决策。重点解析资源管理、Allocate/ListAndWatch流程、健康检查机制及CDI规范生成,支撑Kubernetes中GPU资源的可调度性与云原生AI工作负载部署。
张忠琳
506
【中阶·云原生】GPU 感知调度与设备插件机制深度解析:从 Device Plugin 到 DRA 的架构演进
本文深度解析Kubernetes GPU调度架构演进,重点对比Device Plugin与Dynamic Resource Allocation(DRA)机制,涵盖DRA核心API对象(DeviceClass/ResourceClaim)、CEL表达式过滤、拓扑约束能力;同时介绍NVIDIA GPU Operator全栈管理、MIG/MPS/Time-slicing共享模式及KAI Scheduler的Gang调度与层级队列机制,支撑AI工作负载的生产级GPU集群部署。
AI智能专家
757
深度解析NVIDIA k8s-device-plugin源码:从注册到Allocate的GPU调度全链路
本文深入剖析NVIDIA官方k8s-device-plugin源码,覆盖从插件启动注册、ListAndWatch设备发现与健康监控,到Allocate资源注入的完整GPU调度链路。重点解析设备上报机制、UUID标识、MIG多实例支持、CDI集成及常见故障根因,强调插件与NVIDIA Container Toolkit协同工作的必要性,并给出大规模GPU集群下的工程实践建议。
谈国平
282
【NVIDIA】k8s-device-plugin v0.19.3 NVIDIA k8s-device-plugin v0.19.3 核心插件模块深度分析之一
本文深度剖析NVIDIA k8s-device-plugin v0.19.3核心插件模块,涵盖其在Kubernetes中的定位与职责:GPU/MIG设备发现、资源注册、Allocate分配逻辑、健康监控、CDI支持及MPS共享机制;详细解析模块启动流程、gRPC服务生命周期、ListAndWatch事件驱动模型、Option配置模式、设备ID策略(UUID/Index)、DeviceSpecs生成规则及崩溃退避等健壮性设计,聚焦云原生GPU调度关键技术实现。
张忠琳
224
【NVIDIA】k8s-device-plugin v0.19.3 — CDI / MIG / vGPU 模块超深度代码分析之五
本文深度分析NVIDIA k8s-device-plugin v0.19.3中CDI、MIG和vGPU三大核心模块的实现机制。CDI模块基于Container Device Interface规范生成设备Spec文件并提供Qualified Name;MIG模块通过NVML枚举多实例GPU设备,并借助/proc/driver/nvidia/mig-capabilities映射设备节点路径;vGPU模块通过PCI配置空间Vendor Specific Capability(ID=0x09)识别VF签名及解析宿主机驱动信息。三者协同支撑Kubernetes GPU资源调度与容器化注入。
张忠琳
446
NVIDIA k8s-device-plugin源码级尽调:从main.go到Allocate
本文对NVIDIA k8s-device-plugin(v0.14.x基线)进行静态源码尽调,聚焦其在Kubernetes GPU调度中的核心作用。详细拆解main.go入口、NVML初始化、gRPC服务注册、ListAndWatch设备同步机制及Allocate资源分配逻辑,涵盖MIG多实例支持、CDI设备注入路径、健康检查实现与版本兼容性要点,为GPU集群运维、容器平台开发及K8s面试提供可落地的源码级理解。
飞翔的十号
236
kubernetes深度分析 cdi nvidia-device
本文深入剖析 Kubernetes 中 CDI(Container Device Interface)与 NVIDIA Device Plugin 协同实现 GPU 设备纳管的工作机制:包括 device plugin 注册、kubelet 资源同步、容器调度时的 GPU 分配、nvidia-container-runtime 及其 hook 流程、OCI config 注入 UUID、GPU 设备挂载与权限控制(基于 cgroup v2/BPF)。重点覆盖设备感知、运行时集成及容器内验证等关键技术环节。
铜锣湾的代码仔
114
K8S调度管理GPU资源
本文围绕Kubernetes调度管理GPU资源展开。首先指出GPU管理面临硬件强依赖性、资源不可分割性和异构性与拓扑三大挑战。接着介绍了Kubernetes GPU管理架构的三个阶段,包括原生基础支持、虚拟化与共享、动态资源分配与容器设备接口,阐述各阶段技术方案、原理、优缺点及演进方向。
9命怪猫
1519
k8s-vgpu-scheduler设备插件内核解读:从NVML到自定义分配策略的完整实现
本文深入剖析k8s-vgpu-scheduler(HAMi)vGPU设备插件的内核实现,涵盖NVML设备探测、Kubelet注册机制、基于Pod Annotation的自定义分配策略,以及显存/算力软硬限制机制。重点解读Allocate流程中Annotation解析、请求校验、环境变量注入与libvgpu.so挂载等关键技术环节,揭示其在Kubernetes中实现GPU共享与显存超分的核心原理。
孙泽忱
997
海光DCU接入Kubernetes:从Device Plugin到vDCU虚拟化与DeepSeek推理
本文详解海光DCU适配Kubernetes的完整技术路径:基于Device Plugin实现DCU资源注册与整卡调度;深入对比显存分片型与算力切分型vDCU虚拟化机制,分析其隔离性、适用场景及配置要点;并落地DeepSeek蒸馏模型(7B/14B/32B)在vLLM+ROCm栈上的容器化推理服务,覆盖驱动、DTK、CDI、CubeStudio平台集成及典型排障链。
徐小疼
79
Kubernetes+vLLM大模型推理服务部署实战:从GPU调度到弹性扩缩容
本文详解Kubernetes与vLLM协同部署大模型推理服务的完整生产实践,涵盖GPU设备插件配置、时间切片/MIG显卡共享、vLLM核心参数调优(continuous batching、max-num-seqs、max-model-len、量化策略)、基于Prometheus指标的HPA弹性扩缩容、模型文件高效加载方案,以及常见OOM、排队延迟、多卡未生效等典型问题排查方法。
weixin_34211761
551
【NVIDIA】NVIDIA 云原生文档:Kubernetes 与 NVIDIA GPU
本文档系统介绍 NVIDIA GPU Operator 在 Kubernetes 中的部署与管理,涵盖 GPU 驱动自动化、设备插件、CDI/NRI 设备注入、GPU 共享(Time-Slicing/MIG)、GPUDirect RDMA/Storage、Kata Containers 与 KubeVirt GPU 直通支持,以及 DCGM 监控和多版本驱动 CRD 管理等核心云原生 GPU 能力。
张忠琳
464
Kubernetes GPU调度全解析:从设备插件到CDI的完整链路
本文系统梳理Kubernetes中GPU调度的完整技术链路:从节点驱动、CUDA与Container Toolkit部署,到device-plugin注册nvidia.com/gpu扩展资源;从调度器仅选节点、kubelet设备管理器二次分配设备ID,到CDI与NVIDIA Container Toolkit协同完成容器内设备注入;并涵盖MIG、时间片、显存共享等高级调度模式及典型排错路径。聚焦GPU在K8s中不可压缩、非线性、需硬件协同的本质特性。
谈国平
65
NixOS 上为 k3s 集群启用 NVIDIA GPU 支持:从驱动安装到 GPU Pod 调度完整指南
本文详细阐述在NixOS系统上为k3s集群配置NVIDIA GPU支持的全流程:包括启用开源NVIDIA内核驱动、部署NVIDIA Container Toolkit生成CDI规范、配置k3s containerd运行时与RuntimeClass、部署CDI插件DaemonSet、打节点标签及调度GPU Pod。重点覆盖NixOS模块机制(nvidia.nix、cdi-generate.nix)、containerd模板定制、CDI设备注册与kubelet集成等核心技术环节。
徐耘馨
141
从Device Plugin到DRA:手把手教你迁移K8s异构资源管理方案
本文详解从Kubernetes Device Plugin向动态资源分配(DRA)迁移的全过程,涵盖范式转变(计数→声明)、环境检查、DeviceClass与ResourceClaim配置、碎片化治理及监控适配。重点突出DRA如何通过结构化参数、ResourceSlice、CEL过滤和CDI集成,提升GPU/FPGA等异构资源的调度精度、利用率与可观测性,适用于AI/云原生生产集群。
Respect yourself
312
setting up CDI devices: unresolvable CDI devices nvidia.com/gpu=all
本文详细介绍了在Kubernetes环境中设置NVIDIA GPU设备时遇到的CDI设备无法解析的问题,并提供了详细的解决步骤。包括确保节点上已安装NVIDIA驱动、安装NVIDIA Container Toolkit、配置容器运行时、安装NVIDIA Kubernetes设备插件、验证节点上的GPU资源以及使用GPU运行Pod等。
心态好点
cdi:容器设备接口-用于Linux容器的设备
CDI(容器设备接口)是一种专为Linux容器设计的标准化规范,旨在解决现代容器化环境中第三方设备集成的复杂性问题。随着云计算、边缘计算以及AI/ML等高性能计算场景的快速发展,越来越多的专用硬件设备(如GPU、FPGA、TPU、智能网卡、加密加速器等)被引入到容器运行环境中。传统的容器技术虽然能够通过简单的设备节点挂载方式将硬件暴露给容器,但在面对复杂的设备管理需求时显得力不从心。CDI正是在这样的背景下应运而生,提供了一种灵活、可扩展且标准化的方式来实现容器对各类设备的感知与使用。CDI的核心设计理念是“关注点分离”:它并不试图去管理设备资源的分配或调度,而是专注于如何让容器运行时正确地将设备配置并暴露给容器。这种设计借鉴了CNI(容器网络接口)的成功经验——CNI也仅负责网络命名空间的配置和网络设备的设置,而不涉及IP地址分配或服务发现等上层逻辑。同样,CDI将资源管理、调度决策等职责留给编排系统(如Kubernetes),自身则专注于设备注入的具体执行过程,从而实现了轻量化、模块化和高可移植性。在实际应用中,CDI通过定义一组标准的JSON格式的设备规范文件来描述设备的能力和配置要求。这些文件通常由设备供应商提供,并安装在宿主机的特定目录下(例如 `/etc/cdi` 或 `/var/run/cdi`)。每个CDI设备规范包含设备类型、设备ID、设备节点路径、所需挂载的文件或目录、环境变量设置、hook脚本(用于执行预处理或后处理操作)等内容。当用户在容器启动请求中引用某个CDI设备时(例如通过 `cdi.dev/k8s.io=vendor.com/device-name:1` 这样的注解),容器运行时会解析对应的CDI规范,并根据其中的指令自动完成设备节点的创建、文件系统的挂载、命名空间的调整以及其他必要的运行时操作。CDI的一个关键优势在于其支持多设备协同工作的能力。许多现代硬件设备并非单一的设备节点,而是由多个相关的设备文件、控制接口和固件组成。例如,一个NVIDIA GPU可能需要暴露 `/dev/nvidia0`、`/dev/nvidiactl`、`/dev/nvidia-uvm` 等多个设备节点,同时还需加载特定的内核模块、挂载驱动库目录,并设置适当的环境变量。传统方法需要手动编写复杂的启动脚本或依赖特定运行时的插件机制,而CDI可以通过一个统一的设备规范文件自动完成所有这些步骤,极大地简化了部署流程并提高了可靠性。此外,CDI还支持运行时级别的兼容性检查。这意味着在容器启动前,CDI插件可以验证当前宿主机是否具备所需的硬件支持、驱动版本是否匹配、固件是否已正确加载等条件。如果检测到不兼容的情况,CDI可以提前报错,避免容器因缺少必要设备而失败运行。这对于保障生产环境的稳定性具有重要意义。同时,CDI的设计允许根据不同类型的运行时(如runc、gVisor、Kata Containers等)执行不同的操作策略。例如,在基于虚拟机的轻量级容器运行时中,可能需要通过VirtIO等方式透传设备,而在原生Linux容器中则可以直接挂载设备节点,CDI可以根据上下文动态选择最合适的处理方式。CDI的另一个重要特性是其良好的生态系统集成能力。尽管该存储库已被标记为弃用,后续开发已迁移到新的项目地址,但CDI已经被广泛应用于主流容器平台中,尤其是与Kubernetes的设备插件框架紧密结合。通过CDI,Kubernetes可以在Pod调度完成后,由kubelet调用CDI运行时插件来完成设备注入,整个过程对用户透明且高度自动化。这不仅提升了用户体验,也为设备供应商提供了统一的发布渠道——他们只需维护一份CDI规范文件即可支持多种容器运行时和编排系统。综上所述,CDI作为一项面向未来的容器设备集成标准,填补了传统容器技术在设备管理方面的空白。它以简洁的接口、强大的表达能力和出色的可扩展性,成为连接硬件厂商、容器运行时开发者和云原生应用开发者之间的重要桥梁。随着异构计算架构的普及和专用加速器的广泛应用,CDI将在推动容器技术向更深层次硬件集成方向发展方面发挥越来越重要的作用。未来,我们可以预见CDI将进一步完善安全隔离机制、支持热插拔设备、增强对Windows容器的支持,并与其他云原生组件(如Device Plugin API、Node Feature Discovery等)深度融合,构建更加完整和智能的设备管理生态体系。
高晖云
CDI-v1.48.0的yaml文件
CDI(Container Device Interface,容器设备接口)是 Kubernetes 生态中用于标准化容器与宿主机硬件设备(尤其是加速器类设备,如 GPU、FPGA、ASIC、NVMe SSD、智能网卡等)之间交互的关键基础设施规范。CDI-v1.48.0 是该规范在 2024 年前后发布的稳定版本,代表了当前生产环境中广泛采用的成熟实现标准。其核心 YAML 文件(即本压缩包中的 `cdi-v1.48.0` 文件)并非单一配置文件,而是一套结构化、可扩展、符合 OCI(Open Container Initiative)兼容原则的设备描述定义集合,通常以 `.yaml` 格式组织,用于声明设备能力、生命周期语义、运行时注入机制及安全上下文约束。从技术本质来看,CDI YAML 文件是 Kubernetes 设备插件(Device Plugin)体系的上层抽象补充。Kubernetes 原生 Device Plugin 仅提供粗粒度的设备发现与分配能力(如 `nvidia.com/gpu: 2`),但无法表达设备的细粒度属性(如显存大小、计算能力代际、是否支持 MIG 切分、是否启用 SR-IOV VF、PCIe 拓扑位置、NUMA 绑定亲和性、驱动版本依赖、固件校验哈希、甚至功耗阈值或温度监控接口)。CDI 正是为弥补这一空白而设计:它通过声明式的 YAML 清单,将物理/虚拟设备建模为“设备配置”(Device Configuration),每个配置包含 `name`(全局唯一标识)、`containerEdits`(定义如何修改容器 runtime spec)、`hostPaths`(宿主机路径映射)、`env`(环境变量注入)、`devices`(设备节点路径与权限)、`hooks`(预启动/后终止钩子脚本)等关键字段。例如,一个支持 CUDA 12.3 和 TensorRT 8.6 的 A100-40GB GPU 配置,可通过 CDI YAML 精确指定 `/dev/nvidia0`、`/usr/lib/x86_64-linux-gnu/libcuda.so.1`、`/opt/nvidia/nvidia_driver/535.129.03` 等多层级资源绑定,并自动注入 `NVIDIA_VISIBLE_DEVICES=0` 和 `NVIDIA_DRIVER_CAPABILITIES=compute,utility` 等环境变量,从而确保容器内应用无需感知底层驱动差异即可调用加速能力。CDI v1.48.0 版本在兼容性、安全性与扩展性方面有显著增强。首先,它完全兼容 Kubernetes v1.25+ 的 Pod Scheduling Readiness 机制,支持通过 `cdi.k8s.io/v1alpha1` CRD 注册设备配置,并与 Kubelet 的 Device Manager 协同完成“设备就绪性检查”——即只有当对应 CDI 配置所依赖的驱动模块已加载、设备节点已创建、固件版本满足要求时,Pod 才会被调度到该节点。其次,v1.48.0 强化了 OCI 运行时集成能力:不仅支持 runc,还原生适配 crun、kata-containers 等轻量级/安全沙箱运行时,通过 `containerEdits.linux.devices` 和 `containerEdits.linux.seccomp` 字段实现设备节点安全挂载与系统调用白名单控制,有效防范容器逃逸风险。再者,在 GPU 虚拟化场景中,v1.48.0 明确定义了 MIG(Multi-Instance GPU)实例的拓扑描述语法,允许用户以 `nvidia.com/mig-1g.5gb` 这类细粒度资源请求方式,结合 CDI YAML 中对 `mig-devices` 和 `mig-config` 的声明,实现单卡多租户隔离;同时支持 NVIDIA vGPU、AMD MxGPU、Intel GVT-g 等异构虚拟 GPU 抽象,统一建模为 `vendor.com/vgpu-type` 形式的设备类型,极大提升跨厂商 GPU 资源编排的一致性。此外,CDI YAML 文件还深度融入容器编排全链路:在 Helm Chart 中可作为 `values.yaml` 的 deviceProfiles 引用;在 Operator 开发中可被 ClusterPolicy Controller 动态生成并下发;在 CI/CD 流水线中可作为 IaC(Infrastructure as Code)资产纳入 GitOps 管控,配合 Flux 或 Argo CD 实现设备策略的版本化、审计化与回滚能力。标签中提及的“硬件加速”不仅限于 AI 训练推理,还包括视频转码(VA-API/VDPAU)、密码学加速(Intel QAT)、网络卸载(DPDK/AF_XDP)、存储压缩(ZSTD FPGA 加速)等场景,CDI v1.48.0 均通过标准化字段支持其设备描述与容器注入逻辑。尤为关键的是,该版本引入了 `deviceClass` 分类机制与 `compatibility` 兼容性矩阵声明,使不同代际硬件(如 Ampere vs Hopper 架构 GPU)可在同一集群中共存管理,且调度器可根据工作负载需求自动匹配最优设备实例。综上所述,CDI-v1.48.0 YAML 文件是现代云原生基础设施中连接硬件加速能力与容器化工作负载的核心契约载体,是构建高性能、高可靠、高安全 AI/HTC/HPC 平台不可或缺的底层规范基石。
闫利朋
Kubernetes DRA实战:如何用ResourceClaim精确调度GPU资源(含NVIDIA驱动配置)
吴雄辉
Kubernetes GPU调度实战:MIG拓扑感知与显存精细化管理
Timecompanion
从Device Plugin到DRA:图解Kubernetes硬件管理演进史(附性能对比测试)
Rongrong姐
请注释每一行程序:// k8s-device-plugin/internal/rm/nvml_manager.go// CheckHealth performs health checks on a set of devices, writing to the 'unhealthy' channel with any unhealthy devicesfunc (r *nvmlResourceManager) CheckHealth(stop <-chan interface{}, unhealthy chan<- *Device) error { return r.checkHealth(stop, r.devices, unhealthy)}// k8s-device-plugin/internal/rm/health.gofunc (r *nvmlResourceManager) checkHealth(stop <-chan interface{}, devices Devices, unhealthy chan<- *Device) error { ... eventSet, ret := r.nvml.EventSetCreate() ... for { select { case <-stop: return nil default: } e, ret := eventSet.Wait(5000) if ret == nvml.ERROR_TIMEOUT { continue } if ret != nvml.SUCCESS { klog.Infof("Error waiting for event: %v; Marking all devices as unhealthy", ret) for _, d := range devices { unhealthy <- d } continue } if e.EventType != nvml.EventTypeXidCriticalError { klog.Infof("Skipping non-nvmlEventTypeXidCriticalError event: %+v", e) continue } if skippedXids[e.EventData] { klog.Infof("Skipping event %+v", e) continue } klog.Infof("Processing event %+v", e) eventUUID, ret := e.Device.GetUUID() if ret != nvml.SUCCESS { // If we cannot reliably determine the device UUID, we mark all devices as unhealthy. klog.Infof("Failed to determine uuid for event %v: %v; Marking all devices as unhealthy.", e, ret) for _, d := range devices { unhealthy <- d } continue } d, exists := parentToDeviceMap[eventUUID] if !exists { klog.Infof("Ignoring event for unexpected device: %v", eventUUID) continue } if d.IsMigDevice() && e.GpuInstanceId != 0xFFFFFFFF && e.Comp
本文档提供了对Kubernetes设备插件Go代码的逐行注释,旨在帮助用户理解代码的功能和逻辑。注释详细易懂,覆盖了设备插件的基本概念、关键函数和结构体,以及代码中的关键点,如健康检查、设备列表更新和资源分配逻辑。同时,注释还关注了错误处理和资源清理,以及用户可能的疑问点,如插件注册流程、gRPC接口实现和设备标识管理。
qq_42997560
krd:Kubernetes参考部署
Kubernetes参考部署(KRD)是一个面向生产环境与大规模基础设施演进需求而设计的综合性、模块化、可扩展的Kubernetes集群部署框架,其核心目标是为开发者、SRE工程师、云平台架构师及边缘计算/电信NFV场景下的系统集成人员提供一套经过严格验证、覆盖多硬件形态与网络拓扑的“开箱即用型”部署范式。它不仅是一组Ansible剧本或Shell脚本的集合,更是一套融合了现代云原生最佳实践、硬件加速感知能力、异构网络抽象机制与智能节点特征管理的完整技术栈参考实现。首先,从部署形态维度看,KRD明确支持裸金属(Bare-metal)与虚拟机(VM)双路径部署模式,这使其具备极强的场景适应性:在裸金属场景下,KRD直接接管物理服务器资源,规避虚拟化层性能损耗,适用于对延迟敏感的高性能计算(HPC)、实时数据处理、5G UPF用户面功能等关键业务;而在虚拟机路径中,KRD通过统一抽象层兼容libvirt(基于KVM/QEMU)与VirtualBox两大主流开源虚拟化后端,使得开发测试、CI/CD集成、教学演示等轻量级场景得以快速构建隔离、可复现的Kubernetes沙箱环境。尤为关键的是,其setup.sh脚本并非简单依赖安装器,而是集成了完整的依赖解析、内核模块加载(如vfio-pci、i40e)、固件校验、安全策略配置(SELinux/AppArmor适配)、时间同步(chrony/NTP)、容器运行时预检(containerd/CRI-O版本与配置合规性)等数十项前置检查与自动化修复逻辑,显著降低跨Linux发行版(Ubuntu 16.04–20.04、CentOS 7/8、openSUSE Tumbleweed)部署的碎片化门槛。在核心组件层面,KRD远超基础Kubernetes安装范畴,深度整合了多项面向云边协同与智能基础设施的关键扩展能力。其中,SR-IOV插件的“已实施”状态意味着KRD原生支持PCIe设备直通,可将网卡(如Intel X710、Mellanox ConnectX系列)的物理功能(PF)拆分为多个虚拟功能(VF),并以Device Plugin机制注册至Kubernetes调度器,使Pod可独占低延迟、高吞吐的硬件网卡队列,广泛应用于DPDK加速转发、vRAN基站虚拟化等场景;QAT(QuickAssist Technology)插件则进一步将Intel CPU内置的加密与压缩硬件单元暴露为Kubernetes可调度资源,通过专用Device Plugin与用户态驱动(qat_containers),使TLS卸载、AES-GCM加解密、gzip压缩等CPU密集型操作实现纳秒级加速,极大提升服务网格(Istio)mTLS性能与API网关吞吐。而Multi-NIC(多网卡)支持并非仅指绑定多张物理网卡,而是依托Multus CNI构建多网络平面——主CNI(如Calico/Flannel)承载Pod间东西向流量,Secondary Network(如SR-IOV VF、Macvlan、IPvlan)则专用于南北向接入、存储网络(RoCE/iWARP)、管理网络隔离或NFV数据面分流,真正实现网络平面语义化分层。此外,Node Feature Discovery(NFD)的集成标志着KRD具备动态感知底层硬件特性的智能调度能力:NFD Operator持续扫描节点CPU微架构(AVX-512/SSE4.2)、GPU型号、FPGA存在性、NUMA拓扑、内存带宽、QAT/SR-IOV设备可用性等数百项指标,并自动注入Label/Annotation至Node对象,配合Kubernetes原生Taints & Tolerations或自定义Scheduler Extender,即可实现“将QAT加速任务调度至含QAT设备的节点”、“将DPDK应用强制绑定至NUMA-local SR-IOV VF”等精细化调度策略。而Memory(持久内存)CSI驱动的“已实施”,则打通了Intel Optane Persistent Memory(PMem)与Kubernetes存储生态——通过pmem-csi-driver将PMem设备格式化为LVM或Direct Access(DAX)模式,暴露出支持POSIX语义的块设备或文件系统卷,使Redis、MySQL等内存数据库获得TB级低延迟、断电不丢失的“超大内存池”,彻底重构传统内存-存储边界。Istio服务网格的“经过测试”状态,表明KRD已验证Sidecar注入、mTLS双向认证、流量镜像、金丝雀发布、可观测性(Prometheus+Grafana+Jaeger)全链路集成,并针对SR-IOV网络优化了Envoy代理的socket绑定与零拷贝路径;KubeVirt与Kubevirt(应为KubeVirt)的并列存在,则体现其对虚拟机与容器混合编排的原生支持——KubeVirt将VM作为一等公民纳入Kubernetes API,配合CDI(Containerized Data Importer)实现镜像热迁移,使传统VM负载(如Windows ERP、遗留数据库)无缝融入云原生运维体系。最后,“krd-master”压缩包名称暗示其采用Git分支化工程管理,master分支代表稳定基线,辅以feature/*分支承载SR-IOV QoS增强、NFD Topology Manager联动、OpenShift兼容适配等前沿特性,形成可持续演进的技术资产库。综上,KRD本质是云原生基础设施的“参考架构蓝图”,其价值不仅在于部署效率,更在于为构建安全、高效、智能、可审计的企业级Kubernetes平台提供了经生产验证的设计模式、组件选型指南与集成接口规范。
有道理的同桌
排查命名空间的时候,没有什么问题,但是这个pod出现了问题:qsl@qsl:~$ sudo kubectl get pods -n nvidia-device-pluginNAME READY STATUS RESTARTS AGEnvdp-nvidia-device-plugin-wbmxt 0/1 Error 3 (40s ago) 50sqsl@qsl:~$,并且日志是:qsl@qsl:~$ sudo kubectl logs nvdp-nvidia-device-plugin-48j2w -n nvidia-device-pluginI1029 07:42:37.753487 1 main.go:239] "Starting NVIDIA Device Plugin" version=< 3c9ffca9 commit: 3c9ffca9491f0d2d362a7064138dfcd71bb57592 >I1029 07:42:37.753524 1 main.go:242] Starting FS watcher for /var/lib/kubelet/device-pluginsI1029 07:42:37.753597 1 main.go:249] Starting OS watcher.I1029 07:42:37.753907 1 main.go:264] Starting Plugins.I1029 07:42:37.753927 1 main.go:321] Loading configuration.I1029 07:42:37.754183 1 main.go:346] Updating config with default resource matching patterns.I1029 07:42:37.754322 1 main.go:357]Running with config:{ "version": "v1", "flags": { "migStrategy": "none", "failOnInitError": true, "mpsRoot": "/run/nvidia/mps", "nvidiaDriverRoot": "/", "nvidiaDevRoot": "/", "gdrcopyEnabled": false, "gdsEnabled": false, "mofedEnabled": false, "useNodeFeatureAPI": null, "deviceDiscoveryStrategy": "auto", "plugin": { "passDeviceSpecs": false, "deviceListStrategy": [ "envvar" ], "deviceIDStrategy": "uuid", "cdiAnnotationPrefix": "cdi.k8s.io/", "nvidiaCTKPath": "/usr/bin/nvidia-ctk", "containerDriverRoot": "/driver-root" } }, "resources": { "gpus": [ { "pattern": "*", "name": "nvidia.com/gpu" } ] }, "sharing": { "timeSlicing": {} }, "imex": {}}I1029 07:42:37.754334 1 main.go:360] Retrieving plugins.E1029 07:42:37.754387 1 factory.go:113] Incompatible strategy detected autoE1029 07:42:37.754409 1 factory.go:114] If this is a GPU node, did you configure the NVIDIA Container Toolkit?E1029 07:42:37.754412 1 factory.go:115] You can check the prerequisites at: https://github.com/NVIDIA/k8s-device-plugin#prerequisitesE1029 07:42:37.754414 1 factory.go:116] You can learn how to set the runtime at: https://github.com/NVIDIA/k8s-device-plugin#quick-startE1029 07:42:37.754416 1 factory.go:117] If this is not a GPU node, you should set up a toleration or nodeSelector to only deploy this plugin on GPU nodesE1029 07:42:37.754518 1 main.go:177] error starting plugins: error getting plugins: unable to create plugins: failed to construct resource managers: invalid device discovery strategy,而且我还尝试过删除这个pod让他自己重建,但也没有成功。
SilasChun
K8s调度OpenClaw推理任务的Helm Chart工业级实践:GPU资源request_limit硬隔离、initContainer预检nvidia-container-cli健康状态
SW_孙维