编写 CDI 规格
目标
亲自编写 CDI(Container Device Interface)规范,验证其语法和存放位置,并准确使用 podman run --device 参数格式。
为什么重要
CDI 是一种厂商中立的标准,用于描述“要把该设备加入容器,需要哪些设备节点、库和环境变量”。与过去的运行时钩子方式相比,它更透明、可移植性更高,podman、containerd 和 CRI-O 均支持它。在实际工作中,通常由 nvidia-ctk cdi generate 自动生成规范;但驱动更新后 GPU 无法被识别的事故,大多源于遗漏了规范重新生成,因此你必须能够读懂规范内容。
此环境没有真实 GPU。因此,我们将检查规范的语法、结构、存放位置以及 --device 参数格式——这些正是现场最容易出错的地方。
步骤
- 创建
/etc/cdi目录,同时创建/root/cdi工作目录。 - 创建
/etc/cdi/nvidia.yaml。顶层必须包含cdiVersion: "0.6.0"和kind: nvidia.com/gpu,并且devices数组中必须有一个name: "0"的条目。该条目的containerEdits.deviceNodes中必须包含/dev/nvidia0、/dev/nvidiactl、/dev/nvidia-uvm三个路径。 - 将该文件解析为 YAML,并把顶层键列表保存到
/root/cdi/parsed.txt。必须能看到cdiVersion、kind、devices三个键。 - 在
devices数组中添加第二个条目,其值为name: "all"。该条目的deviceNodes中也必须至少包含两个路径。 - 在
name: "0"条目的containerEdits中添加mounts。hostPath和containerPath都应为/usr/lib/x86_64-linux-gnu/libnvidia-ml.so.550.90.07,且options中必须包含ro、nosuid、nodev、bind四个值。 - 在
name: "0"条目的containerEdits中添加hooks。hookName为createContainer,path为/usr/bin/nvidia-ctk,args为["nvidia-ctk", "hook", "update-ldcache"]。 - 编写
/root/cdi/run.sh。其中必须包含使用podman run请求nvidia.com/gpu=all设备的命令。--device参数值的格式必须准确。 - 创建包含以下 5 行的
/root/cdi/report.txt。各值必须通过解析你编写的规范获得。CDI_VERSION=0.6.0/KIND=nvidia.com/gpu/DEVICES=<devices 배열 길이>/NODES_DEV0=<name 이 "0" 인 장치의 deviceNodes 개수>/SPEC_PATH=/etc/cdi/nvidia.yaml
参考
- 可按
python3 -c "import yaml,sys;d=yaml.safe_load(open('/etc/cdi/nvidia.yaml'));print(list(d))"的形式解析 YAML。 --device的值采用<kind>=<장치이름>格式。- 在真实环境中,
nvidia-ctk cdi generate --output=/etc/cdi/nvidia.yaml会生成此文件。 - 常见错误 1:把
kind写成nvidia/gpu。厂商部分必须采用域名格式(nvidia.com)。 - 常见错误 2:设备名称
"0"未加引号,导致 YAML 将其解析为数字。它必须是字符串。
准备 CDI 目录
创建 /etc/cdi 目录,同时创建 /root/cdi 工作目录。
有两个标准路径。请选择用于存放持久规范的路径。
编写最小规范
创建 /etc/cdi/nvidia.yaml。顶层必须包含 cdiVersion: "0.6.0" 和 kind: nvidia.com/gpu,并且 devices 数组中必须有一个 name: "0" 的条目。该条目的 containerEdits.deviceNodes 中必须包含 /dev/nvidia0、/dev/nvidiactl、/dev/nvidia-uvm 三个路径。
顶层需要两个键以及 devices 数组。kind 使用斜杠连接域名格式的厂商和类别。
验证 YAML 语法
将该文件解析为 YAML,并把顶层键列表保存到 /root/cdi/parsed.txt。必须能看到 cdiVersion、kind、devices 三个键。
使用 python3 的 yaml 模块读取文件,语法错误会立即显现。请汇总并保存解析结果。
添加第二个设备
在 devices 数组中添加第二个条目,其值为 name: "all"。该条目的 deviceNodes 中也必须至少包含两个路径。
按照惯例,all 是表示所有设备的名称。请在 devices 数组中再添加一个条目。
添加库挂载
在 name: "0" 条目的 containerEdits 中添加 mounts。hostPath 和 containerPath 都应为 /usr/lib/x86_64-linux-gnu/libnvidia-ml.so.550.90.07,且 options 中必须包含 ro、nosuid、nodev、bind 四个值。
mounts 条目包含 hostPath、containerPath、options 三个键。options 是字符串数组。
添加钩子
在 name: "0" 条目的 containerEdits 中添加 hooks。hookName 为 createContainer,path 为 /usr/bin/nvidia-ctk,args 为 ["nvidia-ctk", "hook", "update-ldcache"]。
hooks 条目中包含 hookName、path、args。请使用容器创建时的钩子名称。
编写运行命令
编写 /root/cdi/run.sh。其中必须包含使用 podman run 请求 nvidia.com/gpu=all 设备的命令。--device 参数值的格式必须准确。
--device 的值由 kind 和设备名称以等号连接而成。请将其保存在脚本中。
规范验证报告
创建包含以下 5 行的 /root/cdi/report.txt。各值必须通过解析你编写的规范获得。
CDI_VERSION=0.6.0 / KIND=nvidia.com/gpu / DEVICES=<devices 배열 길이> / NODES_DEV0=<name 이 "0" 인 장치의 deviceNodes 개수> / SPEC_PATH=/etc/cdi/nvidia.yaml
各值必须通过解析实际编写的规范获得。数量即数组长度。