实验室已有一台GPU服务器由学长管理,BOSS新购了一台服务器并希望能够像已有的那个服务器一样,让多人共同使用GPU资源而不相互干扰,同时系统资源分配比较灵活。经过一番考虑和踩坑,终于完美搭建GPU平台,记录下以供后人参考。
/
,2T机械挂载点为/home
。/home
,之后将docker存储设置到/home
里就可以充分利用机械盘。本文详细记述了从安装系统到最后实际运行的全过程,主要包括:
记得勾选安装第三方软件
在安装选项那里选择自定义安装,全部设置为主分区,硬盘具体分区为:
硬盘 | 大小 | 格式 | 挂载点 |
---|---|---|---|
固态 | 550M | EFI | - |
固态 | 4G | SWAP | - |
固态 | 900G+ | EXT4 | / |
机械 | 2T | EXT4 | /home |
安装过程比较简单,但估计是因为从MBR格式转为GPT格式的问题,安装过程一直失败,最后经过一次全默认安装后再自定义安装就可以了。
接下来使用vim
命令,直接在本机显示器上操作的可以将下面带vim
的指令替换为gedit
,在本机打开文本编辑器更好操作。
备份删除旧源
sudo mv /etc/apt/sources.list
写入新源
sudo vim /etc/apt/sources.list
粘贴进去保存退出
清华源的链接参考https://mirrors.tuna.tsinghua.edu.cn/help/ubuntu/
vim的使用方法:(按 I 进入insert模式,粘贴后按 ESC退出insert模式,再输入
wq!
回车)
更新
sudo apt-get update
查看已安装的内核
sudo dpkg --get-selections | grep linux
禁止更新内核
sudo apt-mark hold linux-image-x.xx.x-xx-generic
以后如需要恢复更新
sudo apt-mark unhold linux-image-x.xx.x-xx-generic
参考
去官网 https://www.nvidia.cn/Download/index.aspx?lang=cn 下载合适驱动.run文件,放到~
或其他目录下
卸载原有驱动(可能由于2080Ti没有默认驱动,我执行后并没有卸载掉什么包)
sudo apt-get purge nvidia*
禁用nouveau
sudo vim /etc/modprobe.d/blacklist-nouveau.conf
内容写上
blacklist nouveau
options nouveau modeset=0
更新
sudo update-initramfs -u
结束X-window服务
sudo service lightdm stop
按Ctrl + Alt + F4进入tty4控制台
安装驱动
cd ~
sudo sh NVIDIA*
这里开始会有个警告不用管他,安装完后会提示是否更新X-windows配置要选yes
重启X-window
sudo service lightdm start
如果没有图像,按 Ctrl + Alt + F7 返回图形界面
检查能否读取到显卡信息
nvidia-smi
如果安装不成功需要卸载重来,或重启后偶尔出现找不到显卡,运行 nvidia-smi
提示 NVIDIA-SMI has failed because it couldn't communicate with the NVIDIA driver.
的情况下,需要重装驱动
sudo sh NVIDIA* --uninstall
参考
和官网教程一致,主要是改为了国内源改善安装速度
通过https,允许apt使用repository安装软件包
sudo apt-get install -y \
apt-transport-https \
ca-certificates \
curl \
software-properties-common
添加Docker官方GPG key
curl -fsSL https://mirrors.aliyun.com/docker-ce/linux/ubuntu/gpg | apt-key add -
验证key的指纹
apt-key fingerprint 0EBFCD88
添加稳定版repository
add-apt-repository \
"deb [arch=amd64] https://mirrors.aliyun.com/docker-ce/linux/ubuntu \
$(lsb_release -cs) \
stable"
更新apt包索引
apt-get update
安装最新版本的Docker CE
apt-get install -y docker-ce
验证Docker CE正确安装(可选,之后更换存储位置后建议将默认位置/var/lib/docker删除)
docker run hello-world
之后不要急着配置Docker,因为安装nvidia-docker会覆盖daemon.json。
参考
添加repositories
curl -s -L https://nvidia.github.io/nvidia-docker/gpgkey | \
sudo apt-key add -
curl -s -L https://nvidia.github.io/nvidia-docker/ubuntu16.04/amd64/nvidia-docker.list | \
sudo tee /etc/apt/sources.list.d/nvidia-docker.list
sudo apt-get update
安装nvidia-docker2并重新载入daemon.json
sudo apt-get install -y nvidia-docker2
加入docker组,以允许非root用户免sudo
执行docker
命令
sudo gpasswd -a 用户名 docker
如果不重启并重连ssh客户端的话,需要手动重启服务并刷新docker组成员
sudo service docker restart
newgrp - docker
备份daemon.json
sudo cp /etc/docker/daemon.json /etc/docker/daemon.json.bak
修改daemon.json
sudo vim /etc/docker/daemon.json
安装完nvidia-docker后默认应该是这样的配置
{
"runtimes": {
"nvidia": {
"path": "nvidia-container-runtime",
"runtimeArgs": []
}
}
}
修改默认运行时为nvidia-docker,添加国内源,修改存储位置为/home/docker
,限制日志大小后daemon.json为
{
"default-runtime": "nvidia",
"runtimes": {
"nvidia": {
"path": "nvidia-container-runtime",
"runtimeArgs": []
}
},
"registry-mirrors":[
"https://kfwkfulq.mirror.aliyuncs.com",
"https://2lqq34jg.mirror.aliyuncs.com",
"https://pee6w651.mirror.aliyuncs.com",
"https://registry.docker-cn.com",
"http://hub-mirror.c.163.com"
],
"data-root": "/home/docker",
"log-opts": { "max-size": "50m", "max-file": "1"}
}
保存退出,并在/home下建立docker文件夹
cd /home
mkdir docker
在重启前,建议一并更改下网络设置,否则使用bridge模式连接的Docker容器可能无法访问外网
禁用dnsmasq
vim /etc/NetworkManager/NetworkManager.conf
加#号注释掉dns=dnsmasq
如果不重启电脑的话需要重启服务以完成更改,不过还是连着Docker一并重启电脑吧
sudo restart network-manager
sudo restart docker
重启后使用docker info
查看是否修改成功
...
Docker Root Dir: /home/docker
...
Registry Mirrors:
https://kfwkfulq.mirror.aliyuncs.com/
https://2lqq34jg.mirror.aliyuncs.com/
https://pee6w651.mirror.aliyuncs.com/
https://registry.docker-cn.com/
http://hub-mirror.c.163.com/
...
可以删除之前的docker存储目录了。
官网脚本链接已失效,下载github缓存的脚本文件
wget https://raw.githubusercontent.com/shipyard/shipyard-project.com/master/site/themes/shipyard/static/deploy
修改脚本
vim deploy
将deploy脚本中IMAGE=${IMAGE:-dockerclub/shipyard:latest}
修改为 IMAGE=${IMAGE:-shipyard/shipyard:latest}
即可切换为Docker Hub中的中文版镜像源
修改SHIPYARD_PORT=${PORT:-7777}
中的端口号可以自定义Shipyard的Web访问端口
修改完成后保存执行
sudo bash deploy
有选择的话默认即可
安装完成后等待docker容器启动完毕即可通过localhost:port
访问到Web控制台,默认用户名admin
,密码shipyard
。
由于运行容器需要nvidia-docker run
而不是docker run
才能正确初始化使用GPU的容器,接下来还是采用命令行执行。当容器使用nvidia-docker run
正确启动后,就可再使用Docker或Shipyard进行管理了。
在 daemon.json
中修改了 default-runtime
后,运行容器可以直接使用Shipyard或者Docker进行初始化run
了。但是注意经测试用于控制GPU可见性的NV_GPU
环境变量依然需要使用命令行nvidia-docker run
才能正确设置给容器,如果使用docker
指令,则应该使用docker run
的-e NVIDIA_VISIBLE_DEVICES=1
来控制GPU的可见性。
接下来是手动创建Docker模板容器的过程,为了简化过程笔者已经将容器打包上传Dockerhub,不想自己动手创建容器的读者的可以直接跳转文末下载笔者制作好的镜像【附:实验室使用的最新版镜像】
下载有CUDA和CUDNN环境的镜像
docker pull nvidia/cuda:10.1-cudnn7-runtime-ubuntu16.04
这里如果直接pull nvidia/cuda
的话拉取的是latest版本的镜像,系统为ubuntu18.04,因此我们手动指定版本为CUDA:10.1,CUDNN:7,Ubuntu:16.04的镜像。更多版本的镜像可以通过 https://hub.docker.com/r/nvidia/cuda/tags 查看。下面是以Ubuntu16.04为实例进行配置。
创建容器
nvidia-docker run -dit -p2345:22 --name=cuda1 -h=LAB_VM nvidia/cuda:10.1-cudnn7-runtime-ubuntu16.04
参数 | 含义 |
---|---|
-dit | 容器保持后台运行 |
-p2345:22 | 容器22端口映射到宿主机2345端口 |
–net=host | 使用主机模式,区别于默认的–net=bridge通过网桥连接宿主机网络,host模式直接使用宿主机网络空间,此模式下无法使用-p参数映射端口 |
–name=cuda1 | 命名容器 |
-h=LAB_VM | 命名机器 |
–privileged | 以特权模式启动,容器内能访问操作宿主机设备,如mininet等需要控制网卡等类似的应用需要 |
-v /home/docker-common-dir:/home/common-dir | 将宿主机/home/docker-common-dir映射到容器/home/common-dir,一般用于共享目录 |
进入容器
docker exec -it cuda1 /bin/bash
查看GPU是否能正常访问
nvidia-smi
注:这里使用的主要是交互式教程,可以参考结尾给出的Dockerfile使用非交互式指令配置容器
容器内的Ubuntu是一个非常精简的系统,缺乏包括ping
vim
等一系列常用指令,需要按照以下方式配置
更新apt源
apt-get update
如果一直卡在connect这里进行不下去,说明容器内无法连接外网,此时需要配置
退出容器命令行
exit
设置Linux内核允许IP转发
sudo sysctl net.ipv4.conf.all.forwarding=1
将iptables FORWARD 的值更从DROP更改为ACCEPT:
sudo iptables -P FORWARD ACCEPT
资料显示这里的两个配置不会持久化,每次重启都需要重新配置,需要将它们添加到start-up stript,但是笔者实测不需要重新配置
之后重新进入容器控制台执行apt-get update
,应该可以执行成功了,如果又卡在一半的地方是在更新NVIDIA的源,需要检查网络环境是否能够连通NVIDIA的网站
安装vim
apt-get install vim
更换apt源
cp /etc/apt/sources.list /etc/apt/sources.list.bak
rm /etc/apt/sources.list
vim /etc/apt/sources.list
粘贴入16.04的清华源内容https://mirrors.tuna.tsinghua.edu.cn/help/ubuntu/
这里如果意外设置成18.04的源不会马上报错,但是接下来会出现各种问题,一定要看好
更新apt源
apt-get update
安装ssh
apt-get install openssh-server
允许root远程连接
vim /etc/ssh/sshd_config
把PermitRootLogin prohibit-password
修改为PermitRootLogin yes
为root设置密码
passwd root
如果是宿主机Ubuntu16.04,安装ssh服务应该会自行启动并且已经加入自启项,但是在容器内安装则不会自动启动,而且一般设置自启项的方法对Docker容器不起作用 ,需要按照如下方法设置启动脚本
启动ssh服务(此时可以通过ssh://root:密码@宿主机IP -p2345
连接容器了)
service ssh start
创建启动脚本
cd /home
vim startup.sh
输入启动脚本内容
#!/bin/bash
service ssh start
/bin/bash
/bin/bash
的作用是保持Docker容器的后台运行,使用-dit
参数的时候会附加执行这个命令,但是当设置了启动脚本后就不会附加执行了,需要手动执行。
附加执行权限
chmod 777 shartup.sh
这样基本的环境就配置好了,接下来还可以再安装些常用的库如ping
等等,如果需要安装Anaconda的话会提示缺少一个库,通过apt-get install bzip2
即可安装。还可以修改下ubuntu的ssh连接欢迎文字,下一步就开始打包了。
下面列举几个容器中缺少但常用的库
库 | 作用 |
---|---|
vim | 强大的Linux文本编辑库 |
openssh-server | ssh远程连接库 |
net-tools | 包含ifconfig,netstat等指令 |
iputils-ping | 包含ping指令 |
wget | 下载文件指令 |
curl | 网络请求指令 |
git | 版本控制 |
bzip2 | conda的依赖 |
iptables | 包过滤防火墙,可以控制转发策略 |
command-not-found | 在你输入一个未安装的指令时提示安装 |
docker容器内出现无法输入中文,查看中文字符出现乱码情况,解决方法:在启动脚本中加入更换编码指令
vim /etc/profile
追加export LANG=C.UTF-8
保存退出
为了便于以后新建虚拟机,将容器作为镜像打包
nvidia-docker commit -m "一些说明" -a "作者" cuda1 cuda-base:1.0
其中cuda1
为容器的名字,cuda-base:1.0
为镜像的名字和tag。
上述方法如果出现了误操作则需要重新构建,为此我将相关指令编写为Dockerfile
FROM nvidia/cuda:10.1-cudnn7-runtime-ubuntu16.04
MAINTAINER author<[email protected]>
RUN echo "export LANG=C.UTF-8" >>/etc/profile \
&& cp /etc/apt/sources.list /etc/apt/sources.list.bak \
&& echo "deb https://mirrors.tuna.tsinghua.edu.cn/ubuntu/ xenial main restricted universe multiverse\n\
deb https://mirrors.tuna.tsinghua.edu.cn/ubuntu/ xenial-updates main restricted universe multiverse\n\
deb https://mirrors.tuna.tsinghua.edu.cn/ubuntu/ xenial-backports main restricted universe multiverse\n\
deb https://mirrors.tuna.tsinghua.edu.cn/ubuntu/ xenial-security main restricted universe multiverse" >/etc/apt/sources.list \
&& apt-get update \
&& apt-get install vim openssh-server iputils-ping wget curl -y \
&& sed -i 's/PermitRootLogin prohibit-password/PermitRootLogin yes/g' /etc/ssh/sshd_config \
&& echo "root:rootpassword" | chpasswd \
&& echo "#!/bin/bash\n\
service ssh start\n\
/bin/bash" >/home/startup.sh \
&& chmod 777 /home/startup.sh \
&& echo "\
printf '\\\n'\n\
printf '\\\033[0;34m'\n\
printf ' 欢迎使用GPU服务器\\\n'\n\
printf '\\\033[0m'\n\
printf '\\\n'\n\
" >>/etc/update-motd.d/10-help-text
ENTRYPOINT /home/startup.sh
镜像打包指令,注意要在有 Dockerfile
文件的目录下执行
nvidia-docker image build -t cuda-base:1.0 .
新建公共目录
cd /home
sudo mkdir docker-common-dir
新建两个容器
NV_GPU=0 nvidia-docker run -dit --restart=on-failure -v /home/docker-common-dir:/home/common-dir -p6001:22 --name=vm1 -h=LAB_VM cuda-base:1.0 /home/startup.sh
NV_GPU=1 nvidia-docker run -dit --restart=on-failure -v /home/docker-common-dir:/home/common-dir -p6002:22 --name=vm2 -h=LAB_VM cuda-base:1.0 /home/startup.sh
其中NV_GPU
环境变量是为了控制容器可访问的GPU,如果不加这个参数则容器可以访问全部的GPU。--restart=on-failure
是为了设置容器随Docker自动启动。将宿主机的/home/docker-common-dir
映射到了容器的/home/common-dir
目录,便于和容器的文件传输,容器的文件存储以及容器之间的文件传输。最后跟的是启动脚本,如果不输入则每次容器启动都不会自动启动ssh服务。
如果一切正常的话,现在已经可以通过ssh客户端连接两个容器了。
此版本的镜像迎合实验室的需求,配置了Miniconda和一个py37的默认环境并换清华源。设置了ENTRYPOINT
,创建容器时无需指定启动脚本。启动容器时可通过SSH_PORT
控制容器的SSH端口(指容器内部端口,默认为22)。
Docker Hub主页:https://hub.docker.com/r/hangvane/cuda-conda-desktop
Github主页:https://github.com/hangvane/cuda-conda-desktop
拉取镜像:
docker pull hangvane/cuda-conda-desktop:ubuntu16.04
创建容器:
NV_GPU=0 nvidia-docker run -dit -p6009:22 --name=vm -h=LAB_VM -e SSH_PORT=22 hangvane/cuda-conda-desktop:ubuntu16.04
容器启动完成后,就可以使用Shipyard进行容器和镜像的可视化管理了,和不使用nvidia-docker一样。也可以给老师和同学们分配Shipyard的账户让他们自行管理,但是建立账户还是需要在宿主机的终端执行nvidia-docker run
命令。
建议不要删除模板容器cuda1
,以后更新cuda-base
镜像还需要这个容器,如果再通过cuda-base
镜像创建容器更新的话就会有一连串镜像依赖。
目前每次系统重启后,无法找到显卡,表现为nvidia-smi
命令报错,之前使用nvidia-docker
命令启动的容器无法启动。暂时的解决方法是卸载重装驱动。