docker使用GPU总结

在docker容器中使用显卡

一 docker19.03以前的事情

1.1 指定显卡硬件名

最初的容器中使用显卡,需要指定硬件名。经历了两种方式

1. 使用lxc驱动程序运行docker守护进程,以便能够修改配置并让容器访问显卡设备(非常麻烦,参考链接中最久远的回答)

2. Docker 0.9中放弃了lxc作为默认执行上下文,但是依然需要指定显卡的名字

(1)找到你的显卡设备

    ls -la /dev | grep nvidia
     
    crw-rw-rw-  1 root root    195,   0 Oct 25 19:37 nvidia0
    crw-rw-rw-  1 root root    195, 255 Oct 25 19:37 nvidiactl
    crw-rw-rw-  1 root root    251,   0 Oct 25 19:37 nvidia-uvm

(2)启动容器时,指定显卡设备

 sudo docker run -ti --device /dev/nvidia0:/dev/nvidia0 --device /dev/nvidiactl:/dev/nvidiactl --device /dev/nvidia-uvm:/dev/nvidia-uvm tleyden5iwx/ubuntu-cuda /bin/bash

1.2 nvidia-docker

英伟达公司开发了nvidia-docker,该软件是对docker的包装,使得容器能够看到并使用宿主机的nvidia显卡.
本质上,他们找到了一种方法来避免在容器中安装CUDA/GPU驱动程序,并让它与主机内核模块匹配。

 

 测试:

# Install nvidia-docker and nvidia-docker-plugin
wget -P /tmp https://github.com/NVIDIA/nvidia-docker/releases/download/v1.0.1/nvidia-docker_1.0.1-1_amd64.deb
sudo dpkg -i /tmp/nvidia-docker*.deb && rm /tmp/nvidia-docker*.deb
 
# Test nvidia-smi
nvidia-docker run --rm nvidia/cuda nvidia-smi

指定使用两张卡:

docker run --rm --gpus 2 nvidia/cuda nvidia-smi

更详细得得用法见:User Guide — NVIDIA Cloud Native Technologies documentation

另外要注意nvidia-docker包括nvidia-docker1 和 nvidia-docker2,两者命令有一定差异

二 docker 19.03

  感觉docker已是toB公司的必备吧,有了docker再也不用担心因客户环境问题导致程序各种bug,也大大省去了配置客户服务器的过程。
  很多机器学习项目要使用GPU,所以需要docker支持GPU,在docker19以前的版本都需要单独下载nvidia-docker1或nvidia-docker2来启动容器,自从升级了docker19后跑需要gpu的docker只需要加个参数–gpus all 即可(表示使用所有的gpu,如果要使用2个gpu:–gpus 2,也可直接指定哪几个卡:–gpus ‘“device=1,2”’,后面有详细介绍)。
  接着需要安装nvidia驱动,这需要根据自己显卡安装相应的驱动,网上有很多类似教程,此处不再介绍。
  不要以为这样就可以安心的使用gpu了,你的镜像还必须要有cuda才行,这也很简单,去dockerhub上找到和自己tensorflow相对应的cuda版本的镜像,再基于该镜像生成自己的镜像就可以轻松使用gpu了。这里需要额外多说一句,如果你的docker 本身就基于了某个镜像(例如基于本公司仓库的镜像),docker是不允许from两个镜像的,要想实现基于两个或多个,只能基于其中一个,其他的镜像通过各镜像的Dockerfile拼到新的Dockerfile上,但更多的镜像是没有Dockerfile的,可以通过docker history查看某镜像的生成过程,其实就是Dockerfile,nvidia/cuda官网本身就有Dockerfile,也可直接参考。

 

    小结:要想在容器内使用gpu,每一层需要做好的事情

     1、k8s:需要安装nvidia-device-plugin支持gpu调度。 详见https://www.cnblogs.com/linhaifeng/p/16111733.html

     2、容器内:需要有cuda库

     3、docker:安装docker19.03,低于此版本需要额外安装插件

     4、操作系统:安装cuda驱动程序

     5、硬件:插入gpu卡

2.1 安装toolkit

关于配置docker19使用gpu,其实只用装官方提供的toolkit即可,把github上的搬下来:
Ubuntu 16.04/18.04, Debian Jessie/Stretch/Buster:

# Add the package repositories
$ distribution=$(. /etc/os-release;echo $ID$VERSION_ID)
$ curl -s -L https://nvidia.github.io/nvidia-docker/gpgkey | sudo apt-key add -
$ curl -s -L https://nvidia.github.io/nvidia-docker/$distribution/nvidia-docker.list | sudo tee /etc/apt/sources.list.d/nvidia-docker.list

$ sudo apt-get update && sudo apt-get install -y nvidia-container-toolkit
$ sudo systemctl restart docker

CentOS 7 (docker-ce), RHEL 7.4/7.5 (docker-ce), Amazon Linux 1/2

$ distribution=$(. /etc/os-release;echo $ID$VERSION_ID)
$ curl -s -L https://nvidia.github.io/nvidia-docker/$distribution/nvidia-docker.repo | sudo tee /etc/yum.repos.d/nvidia-docker.repo

$ sudo yum install -y nvidia-container-toolkit
$ sudo systemctl restart docker

2.2 测试安装是否成功

经过以上大部分linux系统的docker toolkit应该都能安装成功,如不能安装成功,可参考github官网,查看是否安装成功:
(1) 查看–gpus 参数是否安装成功:

$ docker run --help | grep -i gpus
      --gpus gpu-request               GPU devices to add to the container ('all' to pass all GPUs)

(2) 运行nvidia官网提供的镜像,并输入nvidia-smi命令,查看nvidia界面是否能够启动:

docker run --gpus all nvidia/cuda:9.0-base nvidia-smi

2.3 运行gpu的容器

从Docker 19.03开始,安装好docker之后,只需要使用 --gpus 即可指定容器使用显卡。

所有显卡都对容器可见:

docker run --gpus all --name 容器名 -d -t 镜像id

只有显卡1对容器可见:

docker run --gpus="1" --name 容器名 -d -t 镜像id

如果不指定 --gpus ,运行nvidia-smi 会提示Command not found

 

注意:

1. 显卡驱动在所有方式中,都要先安装好,容器是不会有显卡驱动的,一台物理机的显卡只对应一个显卡驱动,当显卡驱动安装好后(即使未安装cuda),也可以使用命令nvidia-smi

2. nvidia-smi显示的是显卡驱动对应的cuda版本,nvcc -V 显示的运行是cuda的版本
补充

启动容器时,容器如果想使用gpu,镜像里必须有cuda环境,就是说,针对想使用gpu的容器,镜像在制作时必须吧cuda环境打进去

 --gpus '"device=1,2"',这个的意思是,将物理机的第二块、第三块gpu卡映射给容器?

下面三个参数代表的都是是容器内可以使用物理机的所有gpu卡
 --gpus all
 NVIDIA_VISIBLE_DEVICES=all
 --runtime=nvida

  NVIDIA_VISIBLE_DEVICES=2 只公开两个gpu,容器内只能用两个gpu

 

 

举例如下:

# 使用所有GPU
$ docker run --gpus all nvidia/cuda:9.0-base nvidia-smi

# 使用两个GPU
$ docker run --gpus 2 nvidia/cuda:9.0-base nvidia-smi

# 指定GPU运行
$ docker run --gpus '"device=1,2"' nvidia/cuda:9.0-base nvidia-smi
$ docker run --gpus '"device=UUID-ABCDEF,1"' nvidia/cuda:9.0-base nvidia-smi

ok,可以开心愉快的使用gpu了!!

 

后续

 参考资料:

  https://blog.csdn.net/qq_33547243/article/details/107433616

  https://www.cnblogs.com/shoufu/p/12904832.html

  https://github.com/NVIDIA/nvidia-docker/issues/533

  首先介绍几个事实:

  1. 最初的docker是不支持gpu的

  2. 为了让docker支持nvidia显卡,英伟达公司开发了nvidia-docker。该软件是对docker的包装,使得容器能够看到并使用宿主机的nvidia显卡。

  3. 根据网上的资料,从docker 19版本之后,nvidia-docker成为了过去式。不需要单独去下nvidia-docker这个独立的docker应用程序,只需要安装并配置一下nvidia-runtime,使用的时候用--gpus参数来控制。

  (P.S.:因为本实验室服务器的docker默认是支持nvidia的runtime的,所以我在这里没有过多纠结,读者假如从零开始安装docker软件的话可能要细心地保证docker是支持gpu的docker)

  然后我做了几个有代表性的实验:

  1. docker run 的时候不加 --gpus参数,典型代码:

docker run -it --name test --rm ubuntu:latest

  此时在容器内运行nvidia-smi会提示Command not found

  2. docker run 的时候加上 --gpus参数,典型代码:

docker run -it --rm --name test --gpus all ubuntu:latest

  此时在容器内运行nvidia-smi会有如下输出:

 

 从这两个实验我们可以得出结论,docker在启动容器的时候添加的--gpus参数确实是给容器添加了新东西的。比如/usr/bin/nvidia-smi这个可执行程序,如果你不添加--gpus参数是不会给你放到容器中的!此外可以推测,不加--gpus参数,宿主的gpu将对于容器不可见。

  还有一个需要注意的点是nvidia-smi的输出!CUDA Version: N/A

  首先,我的宿主机的CUDA是明确的11.0版本,宿主机的nvidia driver是明确的450.57版本(这一点宿主和容器一致)。那么为什么这里显示 N/A 呢?

  抱着nvidia-smi能用driver一定没问题的想法,我三下五除二地在docker中安装了pytorch。可是运行测试代码的时候傻眼了,测试代码:

import torch
torch.cuda.is_available()

输出报错结果如下:

  UserWarning: CUDA initialization: Found no NVIDIA driver on your system. Please check that you have an NVIDIA GPU and installed a driver from http://www.nvidia.com/Download/index.aspx (Triggered internally at /pytorch/c10/cuda/CUDAFunctions.cpp:100.)
  return torch._C._cuda_getDeviceCount() > 0

  为什么Pytorch找不到NVIDIA driver?? 我的driver哪里有问题?? nvidia-smi不是运行的好好的??

  尝试过在docker内重装多版本的cuda无果,尝试在docker内重装nvidia驱动反而导致nvidia-smi都无法运行。直到我在参考资料3中找到了解决方案,原来是环境变量的问题。

  最后,拉一个GPU docker的正确姿势:

docker run -itd --gpus all --name 容器名 -e NVIDIA_DRIVER_CAPABILITIES=compute,utility -e NVIDIA_VISIBLE_DEVICES=all 镜像名

 

     多出来的东西其实就是这个家伙:NVIDIA_DRIVER_CAPABILITIES=compute,utility

  也就是说,如果你不改这个环境变量,宿主机的nvidia driver在容器内是仅作为utility存在的,如果加上compute,宿主机的英伟达driver将对容器提供计算支持(所谓的计算支持也就是cuda支持)。

  docker exec进入容器,再次运行nvidia-smi

 

 和宿主机的输出就完全相同了。

  再次尝试pytorch的测试代码,输出为True。

  至此,你就获得了一个具有nvidia driver和cuda支持的docker。(需要注意的是,我的pytorch是直接用conda安装的,它的依赖cudatoolkits仅对conda可见,如果你需要cuda做更多事,可能还需要进一步的尝试。但是我猜想既然nvidia-smi的输出是好的,那么大概率没问题)

 

问题:容器内执行nvidia-smi不显示pid

解决方法:

# 安装包
apt-get install  psmisc

# 用这条命令进行查看
fuser -v /dev/nvidia*

 

 

注:本方法针对docker不显示pid而选择的另外一种间接查看方法

可以利用sudo kill -9 pid将其终止以释放显卡资源.

 

posted @ 2022-04-06 20:14  linhaifeng  阅读(44677)  评论(2编辑  收藏  举报