时效性
本篇撰写时间为2021.11.19,由于计算机技术日新月异,博客中所有内容都有时效和版本限制,具体做法不一定总行得通,链接可能改动失效,各种软件的用法可能有修改。但是其中透露的思想往往是值得学习的。
本篇前置:

Docker

Docker 是一个开源的应用容器引擎,让开发者可以打包他们的应用以及依赖包到一个可移植的镜像中,然后发布到任何流行的 Linux或Windows操作系统的机器上,也可以实现虚拟化。(百度百科)

主要是可移植。因此deepo这种配置好了的镜像我们可以直接拿来用。以后配置环境也可以配好一次到处运行。
我们ssh登上服务器,然后参考
https://docs.docker.com/engine/install/ubuntu/#installation-methods
安装docker
注:参照该教程安装的过程中,这条

sudo apt-get install \
    ca-certificates \
    curl \
    gnupg \
    lsb-release

命令可能造成重启某些重要服务,因此会在终端给出提示。按提示操作即可。

  • 过程中碰到一个小问题,当etc/hostname中的name没有出现在etc/hosts中时,sudo相关的一些命令将显示sudo: unable to resolve ....
    StackExchange中找到解决方法:在/etc/hosts中加入127.0.0.1 <name>这样的行即可。

跟随教程成功看到
Hello from Docker! This message shows that your installation appears to be working correctly.
之后的post-installation steps可做参考。不过此处可以暂时不管。

制作镜像

时效性:截至2021.11.19,由于英伟达闭源驱动问题很多,经常导致黑屏,甚至无法进入恢复模式。所以我们一定要先制作镜像。(这个镜像和docker的镜像是两个意思)
image
我们在MobaXterm用Ctrl + D断开连接,再关机。制作镜像。
image

nvidia驱动

docker一千个好,就是不能把驱动也容器化。
所以需要在开始配置deepo之前装好驱动和nvidia-docker
下图来自deepo的github页面
image
服务器终端使用命令lspci | grep nouveau,确认没有任何输出,防止兼容性问题。之后再

sudo apt install ubuntu-drivers-common
ubuntu-drivers devices

按照其recommended版本安装
image
注:时至2021.11.19,英伟达官方查询的版本仍然有时装了会黑屏,还不如Ubuntu的推荐。属实屑了。
nvidia-smi,可以看到输出了
image
注:此时可以(在金山云控制台)重启一下,确认运行正常。我实在是被nvidia搞怕了。
image

nvidia-docker

https://github.com/NVIDIA/nvidia-docker
(可能需梯子。无梯子可参考“总结与问答练习”。下同)
当然,github上不了也可以直接上官网
https://docs.nvidia.com/datacenter/cloud-native/container-toolkit/install-guide.html#docker
注意我们已经装了docker,所以不需要运行他给的这一行命令

curl https://get.docker.com | sh \
  && sudo systemctl --now enable docker

(有警告的)
image
后面的按照官网给出命令安装即可。

deepo

https://github.com/ufoym/deepo#GPU
(可能需梯子)
按照其指示pull即可。
docker pull ufoym/deepo

For users in China who may suffer from slow speeds when pulling the image from the public Docker registry, you can pull deepo images from the China registry mirror by specifying the full path, including the registry, in your docker pull command, for example:

docker pull registry.docker-cn.com/ufoym/deepo
也可以把deepo改为deepo:<tag>,其中<tag>参考官网,可能是pytorch, tensorflow等。就可以不需要全部下载。
使用方法也直接看官网。
正常配置后
docker run --gpus all --rm ufoym/deepo nvidia-smi
能输出nvidia-smi相应内容,而
docker run --gpus all -it ufoym/deepo bash
则可进入bash命令行
image
注:有趣的是,从MobaXterm, ssh再到docker容器,我们已经套了三层命令行了。
(此处再python就套了第四层)

>>> import torch
>>> torch.cuda.is_available()
True
>>> torch.cuda.device_count()
4
>>> torch.cuda.current_device()
0
>>> a = torch.tensor(1.)
>>> a
tensor(1.)
>>> a.cuda()
tensor(1., device='cuda:0')
>>> from torch.backends import cudnn
>>> cudnn.is_available()
True
>>> cudnn.is_acceptable(a.cuda())
True
>>> cudnn.is_acceptable(a)
False

顺利成功。

总结和问答练习

  1. Q: 解说命令
curl -fsSL https://download.docker.com/linux/ubuntu/gpg | sudo gpg --dearmor -o /usr/share/keyrings/docker-archive-keyring.gpg
echo \
  "deb [arch=$(dpkg --print-architecture) signed-by=/usr/share/keyrings/docker-archive-keyring.gpg] https://download.docker.com/linux/ubuntu \
  $(lsb_release -cs) stable" | sudo tee /etc/apt/sources.list.d/docker.list > /dev/null

A:
第一条命令:把docker的公钥写到文件中。
curl -fsSL是访问URL.
-fsSL分别是失败时不显示HTTP错误,静默模式,显示错误,跟踪重定向。
注:尝试浏览器直接访问https://download.docker.com/linux/ubuntu/gpg
也可以看到-----BEGIN PGP PUBLIC KEY BLOCK-----和之后的一串公钥。
|是管道符号,直接把前面的一串公钥给了后面的命令作为参数。
gpg命令参数含义可以参见https://www.gnupg.org/documentation/manuals/gnupg/Operational-GPG-Commands.html
其中-o加文件名就把相应内容输出给了文件。
第二条命令:把软件源相关信息写到docker.list
echo就是直接输出一段字符串。
$()表示把其结果作为字符串“填入”相应位置。你可以尝试

  • 运行dpkg --print-architecture,输出amd64
  • 运行$(dpkg --print-architecture),输出amd64: command not found. 因为这相当于直接运行命令amd64(没有这个命令)
  • 运行echo $(dpkg --print-architecture),则还是输出amd64

总之,我们其实是调用dpkg --print-architecturelsb_release -cs命令,定制出符合当前系统的一行内容,用引号包裹,用echo输出
即:

echo \
  "deb [arch=$(dpkg --print-architecture) signed-by=/usr/share/keyrings/docker-archive-keyring.gpg] https://download.docker.com/linux/ubuntu \
  $(lsb_release -cs) stable"

其实就是输出
deb [arch=amd64 signed-by=/usr/share/keyrings/docker-archive-keyring.gpg] https://download.docker.com/linux/ubuntu bionic stable
用管道符号,直接把该输出作为tee的输入。tee可以把字符串同时写给一至多个文件和标准输出。使用sudo是因为我们写的文件需要sudo权限才能写。
为了看到tee> /dev/null(用于丢弃不需要的输出流)的互动可以尝试

  • touch hello.txt
  • ls
  • echo hello | tee hello.txt
  • cat hello.txt
  • echo bye | tee hello.txt > /dev/null
  • cat hello.txt

有趣的是,尝试tee hello hello.txt,发现并不是把hello写给hello.txt. 而是会等待你的输入。你输入东西并回车后会被同时写到两个文件,分别名为hellohello.txt
且,输入一个字符串,按回车,他会输出同样的字符串。因为tee除了写给文件还写给标准输出。
最后,我们可以cd /etc/apt/sources.list.d/,看看里面有哪些list,以及对应内容是什么。

  1. Q: 现在暂时不需要管docker的post-installation steps(主要是用户权限管理相关内容,即是否可以让非root用户使用docker),那什么时候需要管了?
    A: 例如:组里钦定你管这台服务器,有些组里新人要用。你说我一个普通本科砖工,怎么就……我当时就弄了两个用户组,叫做……
  2. Q: 没有梯子,那文中涉及github的部分怎么办?
    A: gitee等网站可能有镜像。
    image