1. 技术简介
docker本身并不原生支持GPU功能,但使用docker的设备映射功能可以对GPU的使用进行支持,比如通过--device来指定挂载的GPU设备,通过-v来将宿主机上的 nvidia gpu 的命令行工具和相关的依赖库挂载到容器。以下是docker容器使用gpu的示例:
docker run \
--device /dev/nvidia0:/dev/nvidia0 \
--device /dev/nvidiactl:/dev/nvidiactl \
--device /dev/nvidia-uvm:/dev/nvidia-uvm \
-v /usr/local/nvidia:/usr/local/nvidia \
-it --privileged nvidia/cuda
通过上述设备映射,在容器中就可以看到和使用宿主机上的GPU设备了,这种通过设备映射的方式使用不方便。
为了提高NVIDIA GPU在 docker 中的易用性,NVIDIA通过对原生docker的封装,提供了Container Toolkit工具,以实现在docker中使用GPU,该工具由以下3部分组成:
- libnvidia-container,提供了一个库和简单的CLI工具,以实现在容器当中支持使用GPU设备的目标。
- nvidia-container-toolkit,是一个实现了runC prestart hook接口的脚本,该脚本在runC创建一个容器之后,启动该容器之前调用,其主要作用就是修改与容器相关联的json,注入一些在容器中使用NVIDIA GPU设备所需要的一些信息(例如需要挂载哪些GPU设备到容器当中)。
- nvidia-container-runtime,主要用于将容器runC spec作为输入,然后将nvidia-container-toolkit脚本作为一个prestart hook注入到runC spec中,将修改后的runC spec交给runC处理。
使用Container Toolkit工具后创建容器流程为docker --> dockerd --> containerd --> containerd-shim --> nvidia-container-runtime --> nvidia-container-runtime-hook --> libnvidia-container --> runc --> container-process,当nvidia-container-runtime创建容器时,先通过nvidia-container-runtime-hook检查容器是否使用GPU,若使用则调用libnvidia-container将GPU提供给容器,否则走默认的runc逻辑。
从原理上看,docker使用GPU用的不是API Forwarding技术,而是通过设备挂载的方式给容器用,这种设备挂载的方式和虚拟化中GPU直通也不一样,GPU直通需要在guest里安装驱动,而docker挂载GPU设备的方式不需要在docker中安装驱动,而是共享宿主机上的GPU驱动。
2. 使用方法
首先需要在GPU节点上安装NVIDIA Container Toolkit,执行:
distribution=$(. /etc/os-release;echo $ID$VERSION_ID) \
&& curl -s -L https://nvidia.github.io/libnvidia-container/$distribution/libnvidia-container.repo | sudo tee /etc/yum.repos.d/nvidia-container-toolkit.repo
配置yum源:
yum-config-manager --enable libnvidia-container-experimental
安装nvidia-container-toolkit
sudo yum install -y nvidia-container-toolkit
配置docker daemon, 启用nvidia docker运行时:
sudo nvidia-ctk runtime configure --runtime=docker
重启docker daemon:
sudo systemctl restart docker
上述配置完成后,docker就可以使用节点上的GPU:
sudo docker run --rm --runtime=nvidia -e NVIDIA_VISIBLE_DEVICES=all nvidia/cuda:11.6.2-base-ubuntu20.04 nvidia-smi
其中,变量NVIDIA_VISIBLE_DEVICES表示使用节点上哪些GPU,all表示要使用节点上所有的GPU,也可以指定GPU的device id表示具体使用哪块GPU。