服务器主要的使用场景是科学计算,跑深度学习模型,有过单机配置训练环境的经历的人就知道,多版本CUDA共存有多不方便。
之前搭建服务器环境只是利用anaconda做了一个简单的环境控制,加上每个用户设置单独用户账号登录来管理自己的环境。后来当要复现一些老版本tensorflow代码的时候需要使用CUDA9,这时候之前搭建的环境就显得有点憨憨了,早就知道有个玩意叫docker,这次好好看了一下
并且通过学习寻陌千的博文 https://blog.csdn.net/hangvane123/article/details/88639279#comments
这篇博文,成功搭建了用nvidia-docker调度GPU资源的docker环境,以隔离开实验室成员之间不同的环境,这样通过不同的docker容器,使用者将不会面临环境冲突的问题,因为所有的环境都是独立的。
在安装完Ubuntu16.04后,跟换apt源
备份删除旧源
sudo mv /etc/apt/sources.list /etc/apt/sources.list.bak
写入新源
sudo vim /etc/apt/sources.list
将以下内容复制进去
deb https://mirrors.tuna.tsinghua.edu.cn/ubuntu/ xenial main restricted universe multiverse
# deb-src https://mirrors.tuna.tsinghua.edu.cn/ubuntu/ xenial main restricted universe multiverse
deb https://mirrors.tuna.tsinghua.edu.cn/ubuntu/ xenial-updates main restricted universe multiverse
# deb-src https://mirrors.tuna.tsinghua.edu.cn/ubuntu/ xenial-updates main restricted universe multiverse
deb https://mirrors.tuna.tsinghua.edu.cn/ubuntu/ xenial-backports main restricted universe multiverse
# deb-src https://mirrors.tuna.tsinghua.edu.cn/ubuntu/ xenial-backports main restricted universe multiverse
deb https://mirrors.tuna.tsinghua.edu.cn/ubuntu/ xenial-security main restricted universe multiverse
# deb-src https://mirrors.tuna.tsinghua.edu.cn/ubuntu/ xenial-security main restricted universe multiverse
保存退出后
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下载对应驱动,放到~目录下方便查找
然后卸载默认驱动(有可能没有卸载掉什么东西,但是不管就好)
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*(执行之前下载的nvidia驱动文件)
安装的时候会有一个32bit相关的警告不用理会,然后安装完后会提示是否更新X-windows配置要选yes
完毕后重启X-window
sudo service lightdm start
如果没有图像,按 Ctrl + Alt + F7 返回图形界面
测试熟悉的显卡信息
nvidia-smi
如果到这一步有错的话就只有重装驱动了
为了提高速度,通过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正确安装
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存储目录了
下载依赖镜像
docker pull rethinkdb
docker pull microbox/etcd
docker pull shipyard/docker-proxy
docker pull swarm
docker pull dockerclub/shipyard
将原先脚本修改为中文脚本
wget https://raw.githubusercontent.com/shipyard/shipyard-project.com/master/site/themes/shipyard/static/deploy
将官方脚本换成修改为中文版的脚本
grep -n shipyard:latest deploy
sed -i 's/shipyard\/shipyard:latest/dockerclub\/shipyard:latest/g' deploy
默认会用到8080端口和2375端口,如果不想使用这两个端口可以修改,这里我们改成18080与12375端口
vim deploy
运行安装脚本
sh deploy
安装成功如下
此时可以通过本机浏览器输入localhost:18080访问了
首先使用
docker pull nvidia/cuda:10.1-cudnn7-runtime-ubuntu16.04
来获取含有CUDA和CUDNN的镜像,上面只是一个例子,具体镜像可以访问
https://hub.docker.com/r/nvidia/cuda
[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-4jqXMBxC-1582775603721)(/images/pasted-18.png)]
选择合适的镜像进行pull,pull下来之后创建容器,由于我这里采用自己生产的镜像(镜像名为cuda-base:10.0,已包含pytorch1.3 tensorflow2 tensorflow1.14三个基础环境),代码为
NV_GPU=0 nvidia-docker run -dit --restart=on-failure -v /home/docker-common-dir:/home/common-dir -p30810:22 --name=newContainer -h=LAB_VM cuda-base:10.0 /home/startup.sh
其中 -p参数后面表示把容器22端口(也就是ssh端口)映射到宿主机的30810端口,此后可以直接用宿主机ip+端口的方式访问容器。 -h参数是指
[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-juVdDhTt-1582775603722)(/images/pasted-19.png)]这个显示的东西,可以不管或者个性化。 最后/home/startup.sh是表示使用这个startup.sh脚本。
由于之前我已经配置好一个包含pytorch1.3 tensorflow2 tensorflow1.14的基于CUDA10.0的镜像,需要的朋友可以直接去我的docker hub上pull,稍后给出链接
对于没有配置好的容器,参照以下配置方法可以很方便地配置好容器的基础环境。
容器内的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
在这里粘贴清华源的内容
# 默认注释了源码镜像以提高 apt update 速度,如有需要可自行取消注释
deb https://mirrors.tuna.tsinghua.edu.cn/ubuntu/ xenial main restricted universe multiverse
# deb-src https://mirrors.tuna.tsinghua.edu.cn/ubuntu/ xenial main restricted universe multiverse
deb https://mirrors.tuna.tsinghua.edu.cn/ubuntu/ xenial-updates main restricted universe multiverse
# deb-src https://mirrors.tuna.tsinghua.edu.cn/ubuntu/ xenial-updates main restricted universe multiverse
deb https://mirrors.tuna.tsinghua.edu.cn/ubuntu/ xenial-backports main restricted universe multiverse
# deb-src https://mirrors.tuna.tsinghua.edu.cn/ubuntu/ xenial-backports main restricted universe multiverse
deb https://mirrors.tuna.tsinghua.edu.cn/ubuntu/ xenial-security main restricted universe multiverse
# deb-src https://mirrors.tuna.tsinghua.edu.cn/ubuntu/ xenial-security main restricted universe multiverse
# 预发布软件源,不建议启用
# deb https://mirrors.tuna.tsinghua.edu.cn/ubuntu/ xenial-proposed main restricted universe multiverse
# deb-src https://mirrors.tuna.tsinghua.edu.cn/ubuntu/ xenial-proposed main restricted universe multiverse
然后更新源
sudo 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
这样基本的环境就配置好了
docker容器内出现无法输入中文,查看中文字符出现乱码情况,解决方法:在启动脚本中加入更换编码指令
vim /etc/profile
追加export LANG=C.UTF-8
保存退出
为了便于以后新建虚拟机,将容器作为镜像打包
nvidia-docker commit -m "说明" -a "作者" cuda1 cuda-base:10.0
其中cuda1
为容器的名字,cuda-base:10.0
为镜像的名字和tag
首先新建一个公共目录
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 -p30810:22 --name=newContainer -h=LAB_VM cuda-base:10.0 /home/startup.sh
其中NV_GPU环境变量是为了控制容器可访问的GPU,如果不加这个参数则容器可以访问全部的GPU。–restart=on-failure是为了设置容器随Docker自动启动。将宿主机的/home/docker-common-dir映射到了容器的/home/common-dir目录,便于和容器的文件传输,容器的文件存储以及容器之间的文件传输。最后跟的是启动脚本,如果不输入则每次容器启动都不会自动启动ssh服务。
如果一切正常的话,现在已经可以通过ssh客户端连接容器了。
写来提醒自己:利用本地镜像创建了容器过后如果无法通过ip:端口直接连接,需要先
docker exec -it 容器名 /bin/bash
从宿主机进入容器后,设置root密码
passwd root
设置密码后就可以访问了
在此特别感谢原博客博主寻陌千对我的一些问题提供了解答和帮助,原博客地址为
https://blog.csdn.net/hangvane123/article/details/88639279