LabHub
学习 学习路径 课程

Rootless Podman 运维

CDI 规格的读与写

在 LabHub 中继续学习

一句话总结

CDI 是一份用 YAML 描述“要把这个设备放进容器,需要做什么”的规范。它把 runtime hook 这个黑盒变成了标准文件。

概念图: 用 YAML 描述“要把这个设备放进容器,需要做什么”的规范 · runtime hook · 外部无法知道它做了什么。 · 每个厂商都制作自己的 hook。

为什么需要它

过去要在 Docker 中使用 GPU,必须插入名为 nvidia-container-runtimeruntime hook。容器启动前,hook 会挂载驱动库并添加设备节点。它虽然能工作,却存在问题。

CDI 把它改成了声明式规范。只要在 /etc/cdi/*.yaml 中写明“请求这个设备名时,添加这些设备节点、挂载和环境变量”,支持 CDI 的 runtime(podman、containerd、CRI-O)就会照此执行。

它如何工作

规范结构

cdiVersion: "0.6.0"
kind: nvidia.com/gpu

devices:
  - name: "0"
    containerEdits:
      deviceNodes:
        - path: /dev/nvidia0
        - path: /dev/nvidiactl
        - path: /dev/nvidia-uvm
      mounts:
        - hostPath: /usr/lib/x86_64-linux-gnu/libnvidia-ml.so.550.90.07
          containerPath: /usr/lib/x86_64-linux-gnu/libnvidia-ml.so.550.90.07
          options: ["ro", "nosuid", "nodev", "bind"]
      env:
        - NVIDIA_VISIBLE_DEVICES=0
      hooks:
        - hookName: createContainer
          path: /usr/bin/nvidia-ctk
          args: ["nvidia-ctk", "hook", "update-ldcache"]

  - name: all
    containerEdits:
      deviceNodes:
        - path: /dev/nvidia0
        - path: /dev/nvidiactl

核心规则如下。

实际使用

# 스펙 생성 (실제 GPU 가 있는 호스트에서)
sudo nvidia-ctk cdi generate --output=/etc/cdi/nvidia.yaml

# 등록된 장치 확인
nvidia-ctk cdi list
# nvidia.com/gpu=0
# nvidia.com/gpu=all

# 컨테이너에서 사용
podman run --rm --device nvidia.com/gpu=all nvidia/cuda:12.4.1-base nvidia-smi

Docker 的 --gpus all 对应 --device nvidia.com/gpu=all。新版 podman 也把 --gpus 作为兼容 flag 接受,但 CDI 写法才是正式格式

**rootless 也能使用 GPU。**GPU 驱动在内核空间运行,因此容器权限级别不影响性能。能够读取系统级 /etc/cdi/nvidia.yaml 时可直接使用;否则可在用户空间生成 spec 并指定该目录。

在 containerd 中注册

Kubernetes 中由 containerd 读取 CDI。config.toml 需要启用相应设置,而单独注册 runtime 的旧方式仍在使用。

[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"
  SystemdCgroup = true

使用该 runtime 的 workload 通过 RuntimeClass 选择它。

apiVersion: node.k8s.io/v1
kind: RuntimeClass
metadata:
  name: nvidia
handler: nvidia

诀窍是不要把 default_runtime_name 改为 nvidia,否则不用 GPU 的 Pod 也会经过该 runtime。使用 RuntimeClass 只指定需要的 workload 更安全。

实际工作中的表现

更新驱动后无法识别 GPU。十有八九是忘了重新生成 CDI specnvidia-ctk cdi generate)。spec 中包含带版本号的库文件路径,驱动升级后旧路径就会消失。

**容器内 nvidia-smi 正常,但 CUDA 程序失败。**这通常是只挂载了部分所需库,应检查 spec 的 mounts 列表。

下一项实践将做什么

/etc/cdi/ 中直接编写 CDI spec。由于没有真实 GPU,评分将检查规范语法、放置位置以及 --device 参数格式,这正是现场容易出错的地方。