nvidia-container-runtime 相关逻辑

相关配置和内容

/etc/containerd/config.toml 中配置:

1
2
3
4
5
6
7
        [plugins."io.containerd.grpc.v1.cri".containerd.runtimes.nvidia]
          privileged_without_host_devices = false
          runtime_engine = ""
          runtime_root = ""
          runtime_type = "io.containerd.runc.v1"
          [plugins."io.containerd.grpc.v1.cri".containerd.runtimes.nvidia.options]
            BinaryName = "/usr/bin/nvidia-container-runtime"

代码中读取配置文件路径:/etc/nvidia-container-runtime/config.toml,配置文件内容示例:

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
#accept-nvidia-visible-devices-as-volume-mounts = false
#accept-nvidia-visible-devices-envvar-when-unprivileged = true
disable-require = false
supported-driver-capabilities = "compat32,compute,display,graphics,ngx,utility,video"
#swarm-resource = "DOCKER_RESOURCE_GPU"

[nvidia-container-cli]
#debug = "/var/log/nvidia-container-toolkit.log"
environment = []
#ldcache = "/etc/ld.so.cache"
ldconfig = "@/sbin/ldconfig"
load-kmods = true
#no-cgroups = false
#path = "/usr/bin/nvidia-container-cli"
#root = "/run/nvidia/driver"
#user = "root:video"

[nvidia-container-runtime]
debug = "/var/log/nvidia-container-runtime.log"
log-level = "trace"
mode = "auto"
runtimes = ["docker-runc", "runc", "crun"]

[nvidia-container-runtime.modes]

[nvidia-container-runtime.modes.cdi]
annotation-prefixes = ["cdi.k8s.io/"]
default-kind = "nvidia.com/gpu"
spec-dirs = ["/etc/cdi", "/var/run/cdi"]

[nvidia-container-runtime.modes.csv]
mount-spec-path = "/etc/nvidia-container-runtime/host-files-for-container.d"

[nvidia-container-runtime-hook]
path = "nvidia-container-runtime-hook"
skip-mode-detection = false

[nvidia-ctk]
path = "nvidia-ctk"

代码中打印的配置内容:

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
{
  "DisableRequire": false,
  "SwarmResource": "",
  "AcceptEnvvarUnprivileged": true,
  "AcceptDeviceListAsVolumeMounts": false,
  "SupportedDriverCapabilities": "compat32,compute,display,graphics,ngx,utility,video",
  "NVIDIAContainerCLIConfig": {
    "Root": "",
    "Path": "",
    "Environment": [],
    "Debug": "",
    "Ldcache": "",
    "LoadKmods": true,
    "NoPivot": false,
    "NoCgroups": false,
    "User": "",
    "Ldconfig": "@/sbin/ldconfig"
  },
  "NVIDIACTKConfig": {
    "Path": "/usr/bin/nvidia-ctk"
  },
  "NVIDIAContainerRuntimeConfig": {
    "DebugFilePath": "/var/log/nvidia-container-runtime.log",
    "LogLevel": "trace",
    "Runtimes": [
      "docker-runc",
      "runc",
      "crun"
    ],
    "Mode": "auto",
    "Modes": {
      "CSV": {
        "MountSpecPath": "/etc/nvidia-container-runtime/host-files-for-container.d"
      },
      "CDI": {
        "SpecDirs": [
          "/etc/cdi",
          "/var/run/cdi"
        ],
        "DefaultKind": "nvidia.com/gpu",
        "AnnotationPrefixes": [
          "cdi.k8s.io/"
        ]
      }
    }
  },
  "NVIDIAContainerRuntimeHookConfig": {
    "Path": "/usr/bin/nvidia-container-runtime-hook",
    "SkipModeDetection": false
  }
}

查看某个特定的容器的 containerd 日志信息:

1
2
3
4
5
# kubectl -ndemo get pods test-deploy0-6cdcc7659-66xlx -oyaml | grep containerID
#  - containerID: containerd://4bd59051851d84523f4b16b27b32ef529ba399098fa80560e2818bdc4a2be4d7
cat /var/run/containerd/io.containerd.runtime.v2.task/k8s.io/4bd59051851d84523f4b16b27b32ef529ba399098fa80560e2818bdc4a2be4d7/log.json
# 查看其 OCI spec 信息
cat /var/run/containerd/io.containerd.runtime.v2.task/k8s.io/4bd59051851d84523f4b16b27b32ef529ba399098fa80560e2818bdc4a2be4d7/config.json

nvidia-container-runtime 逻辑

1、从命令行参数 bundle 获取 OCI 配置所在文件夹路径,并从文件 config.json 读取 OCI 配置。调用的命令示例如下:

1
/usr/bin/nvidia-container-runtime --root /run/containerd/runc/k8s.io --log /var/run/containerd/io.containerd.runtime.v2.task/k8s.io/4bd59051851d84523f4b16b27b32ef529ba399098fa80560e2818bdc4a2be4d7/log.json --log-format json create --bundle /var/run/containerd/io.containerd.runtime.v2.task/k8s.io/4bd59051851d84523f4b16b27b32ef529ba399098fa80560e2818bdc4a2be4d7 --pid-file /var/run/containerd/io.containerd.runtime.v2.task/k8s.io/4bd59051851d84523f4b16b27b32ef529ba399098fa80560e2818bdc4a2be4d7/init.pid 4bd59051851d84523f4b16b27b32ef529ba399098fa80560e2818bdc4a2be4d7

2、里面会从环境变量 NVIDIA_VISIBLE_DEVICES 或者挂载路径中获取信息,判断是否为 CDI 模式,如果是 CDI 模式则直接返回。否则使用 go-nvlib 和 go-nvml 库获取平台信息,如果平台为 nvml 或者 wsl 则返回,否则返回 legacy 模式,如果平台为 tegra,则返回 csv 模式。

3、nvidia-container-runtime:根据模式,返回对应的 Modifier,legacy 返回 NewStableRuntimeModifier, 里面会添加:nvidiaContainerRuntimeHookPath 配置路径,最后在 OCI 配置中添加 prestart hook 路径,然后转回到底层 runtime 执行。添加的 hook 配置如下:

1
2
3
4
5
6
	"hooks": {
		"prestart": [{
			"path": "/usr/bin/nvidia-container-runtime-hook",
			"args": ["nvidia-container-runtime-hook", "prestart"]
		}]
	},

4、runc:底层运行时 runc 执行时,根据 OCI 规范,执行 prestart hook。 5、nvidia-container-runtime-hook:执行 prestart 命令。里面是调用到/usr/bin/nvidia-container-cli(在 third_party/libnvidia-container 中,提供二进制文件给 hook 使用)来执行。

containerd 和 device plugin 逻辑

1、请求 Device Plugin 获取 GPU 设备:Kubelet 首先会与 Device Plugin 通信,以获取可用的 GPU 设备。Device Plugin 是一个守护进程,负责向 Kubelet 报告节点上的可用设备,并管理设备的分配。

2、请求 containerd 创建容器:在获取到可用的 GPU 设备后,Kubelet 会将这些设备信息包含在创建容器的请求中,并通过 CRI 向 containerd 发送请求,要求创建容器,将允许容器访问的特定设备节点设置到 OCI 配置文件的 device 字段中。

3、runc 创建容器:runc 会根据 OCI 配置文件中的设备信息,将这些设备节点挂载到容器内部。

modify 逻辑

graphicsModifier

NVIDIA_DRIVER_CAPABILITIES:控制哪些驱动库/二进制文件将被挂载到容器内部,值可为:

  • compute,video 或 graphics,utility
  • all
  • 空或未设置

流程: 1、获取是否存在环境变量 NVIDIA_VISIBLE_DEVICES,否则不需要创建。 2、从环境变量 NVIDIA_DRIVER_CAPABILITIES,获取需要的驱动能力,并判断是否含有“graphics”和“display”能力,否则不需要创建。 3、获取nvidia-ctk 路径,然后挂载图形相关的so文件到容器内部。

featureGatedModifier

根据可选的特征创建modifier,目前支持的特征有:

  • NVIDIA_GDS:GDS(GPUDirect Storage)是 NVIDIA 提供的一种技术,允许 GPU 直接访问存储设备,从而提高数据传输速度和效率。
  • NVIDIA_MOFED:MOFED(Mellanox OpenFabrics Enterprise Distribution)是 Mellanox 提供的高性能网络驱动程序和库,通常用于高性能计算(HPC)和数据中心环境
  • NVIDIA_NVSWITCH:NVSwitch 是 NVIDIA 提供的一种高带宽互连技术,用于连接多个 GPU,从而实现更高的计算性能和扩展性。
  • NVIDIA_GDRCOPY:GDRCopy 是一种用于 GPU 直接内存访问(DMA)传输的库,通常用于高性能计算和数据传输场景。