总结下在实验室的服务器上搭建深度学习环境的过程,并通过docker创建不同开发需求的环境,实现本地远程连接。
首先要给服务器安装Linux系统,这里安装的是Ubuntu 20.04,安装教程网上一大堆不做赘述了。安装完后要对系统进行一些配置:
sudo cp /etc/apt/sources.list /etc/apt/sources.list.backup
sudo vi /etc/apt/sources.list
# 默认注释了源码镜像以提高 apt update 速度,如有需要可自行取消注释
deb https://mirrors.tuna.tsinghua.edu.cn/ubuntu/ bionic main restricted universe multiverse
# deb-src https://mirrors.tuna.tsinghua.edu.cn/ubuntu/ bionic main restricted universe multiverse
deb https://mirrors.tuna.tsinghua.edu.cn/ubuntu/ bionic-updates main restricted universe multiverse
# deb-src https://mirrors.tuna.tsinghua.edu.cn/ubuntu/ bionic-updates main restricted universe multiverse
deb https://mirrors.tuna.tsinghua.edu.cn/ubuntu/ bionic-backports main restricted universe multiverse
# deb-src https://mirrors.tuna.tsinghua.edu.cn/ubuntu/ bionic-backports main restricted universe multiverse
deb https://mirrors.tuna.tsinghua.edu.cn/ubuntu/ bionic-security main restricted universe multiverse
# deb-src https://mirrors.tuna.tsinghua.edu.cn/ubuntu/ bionic-security main restricted universe multiverse
# 预发布软件源,不建议启用
# deb https://mirrors.tuna.tsinghua.edu.cn/ubuntu/ bionic-proposed main restricted universe multiverse
# deb-src https://mirrors.tuna.tsinghua.edu.cn/ubuntu/ bionic-proposed main restricted universe multiverse
sudo apt-get update
sudo apt-get upgrade
查看是否安装了ssh-server服务。默认只安装ssh-client服务。
dpkg -l | grep ssh
安装ssh-server服务
sudo apt-get install openssh-server
确认ssh-server是否启动了:
ps -e | grep ssh
如果没有可执行sudo service ssh start
,完成之后就可以SSH登录服务器(推荐使用MobaXterm)
服务器一般都有一块固态和一个大容量的机械硬盘,我在固态上安装系统,机械硬盘则用来存放大的文件比如数据集。
查看磁盘容量及分区状况(可以查看未挂载分区):sudo lsblk -f
将机械硬盘格式化为 ext4: sudo mkfs.ext4 /dev/sda
挂载硬盘:
sudo mkdir /home/用户名/hhd
sudo mount /dev/sda /home/用户名/hhd
df -Th # 磁盘容量及分区状况(不能查看未挂载分区)
/etc/fstab
,在其内容中追加/dev/sda /home/用户名/hhd ext4 defaults 0 0
lsblk -f
经常需要使用ssh工具传输文件,对挂载的目录添加写入权限:sudo chmod 777 目录名
。注意必须要精确到改目录下(改变其上级目录权限都不行)
通常实验室会有多人使用服务器,为此我们需要服务器能给每个用户分配一个干净的运行环境。
主流的工具是conda、virtualenv以及docker。相比较于前两者主要用来隔离python不同版本的虚拟环境;有时候我们的开发环境并不只是用到python,比如有的native库需要对应gcc版本的编译环境,或者进行交叉编译时会安装很多工具链等等。如果这些操作都在服务器本地上进行,那时间久了就会让服务器的文件系统非常杂乱,而且还会遇到各种软件版本冲突问题。这时候docker就可以发挥用场了,只需要在本机安装显卡驱动,其他的操作在docker镜像里已
禁用secure boot
联想的设备开机F2禁用BIOS的secure boot,即disable它,如果不关闭,使用第三方源安装显卡驱动会安装后不能使用。
禁用nouveau
打开终端,输入:
sudo vi /etc/modprobe.d/blacklist.conf
在blacklist.conf文件末尾加上这两行,并保存:
blacklist nouveau
options nouveau modeset=0
然后执行命令:
sudo update-initramfs -u //应用更改
安装驱动
这里我们通过命令行安装,需要使用到aptitude工具,首先进行安装:sudo apt-get install aptitude
输入ubuntu-drivers devices
查看当前机器支持的驱动,选择recommended那项执行安装,例如:
sudo aptitude install nvidia-driver-470 --without-recommends
使用–without-recommends可以只安装需要的东西,节省空间。
结束后输入nvidia-smi
即可查看显卡信息
为了在docker中支持GPU,NVidia之前是弄了个nvidia-docker2,现在升级为NVIDIA Container Toolkit了。
安装教程
Docker Hub 中提供了非常多的高质量的官方镜像,可以直接从上面选择你需要的镜像拉取到本地作为基础镜像 。国内从 Docker Hub 拉取镜像有时会遇到困难,需要配置docker镜像加速。
以下列举了docker常用的操作指令,更多运行指令可点击
docker ps -a # 查看所有的容器信息
docker ps # 查看所有运行的容器
docker stop <容器 ID> # 停止一个容器
docker start <容器 ID> / <容器名> # 重新启动已经停止的容器
快捷键ctrl + P + Q(必须是大写模式下):使容器不停止退出到宿主机的terminal界面。
docker attach <容器 ID> <容器名> # 附着到已经运行的容器,会沿用docker run命令时的参数
docker rm <容器 ID> # 删除一个容器
解决docker默认安装空间不足导致无法安装镜像
这里推荐使用deepo这样一款中国人做出来的深度学习镜像,包含了现在多数流行的深度学习框架。
在下载好deepo镜像后,输入以下命令创建一个容器:
sudo docker run -it --gpus all --ipc=host -p 6666:8888 -p 6022:22 -v /mnt/hhd:/workspace --name zhangwen_dp ufoym/deepo:all-jupyter-py36-cu111 /bin/bash
-it
:进入交互模式,启动bash--gpus all
:宿主机全部GPU可供容器使用--ipc=host
:容器共享宿主机内存-p 7777:8888 -p 8022:22
:端口映射,主要是两个目的:
-v /mnt/hhd:/workspace
:深度学习框架的docker镜像都默认带有/workspace
目录,可实现和宿主机的指定目录(我把它设置为之前机械硬盘挂载的目录)进行文件共享--name
:对容器命名设置 root
账户密码:
passwd root
很多镜像都不会默认安装 ssh,所以需要在容器内安装 ssh 服务:
apt update && apt install -y openssh-server
一般进入容器时使用的都是 root
账号,但是 ssh 默认是禁止 root
账号使用密码远程登录的,所以需要修改 ssh 配置文件使其允许:
vim /etc/ssh/sshd_config
# 修改如下两处地方,允许root用户以任何认证方式登录(用户名密码认证和公钥认证)
#PermitRootLogin without-password 改为 PermitRootLogin yes
#PasswordAuthentication yes 改为 PasswordAuthentication yes
需要注意的是由于ssh配置文件的权限是只读,vim编辑后,退出时需要输入:wq!强制保存更改
编辑完后确认ssh-server是否启动了:ps -e | grep ssh
。 如果没有可执行service ssh start
插件支持
jupyter lab支持许多插件,一般需要安装node.js才能使用:
# 安装nod.js 14.x版本
curl -fsSL https://deb.nodesource.com/setup_14.x | bash -
apt-get install -y nodejs
设置jupyter登录密码
# 生成配置文件
jupyter lab --generate-config
# 进入python或ipython,设置密码,并记录
from notebook.auth import passwd
passwd()
保存生成的密钥 'argon2:$argon2id$v=19$m=10240,t=10,p=8$VYZtIvepEs0vp85l5HUgDg$B3Kjge2nLIrlDxNY6gYRGw'
修改配置文件
vim /root/.jupyter/jupyter_lab_config.py
# 添加内容如下:
c.NotebookApp.password = 'argon2:$argon2id$v=19$m=10240,t=10,p=8$VYZtIvepEs0vp85l5HUgDg$B3Kjge2nLIrlDxNY6gYRGw' #秘钥
c.NotebookApp.ip='0.0.0.0' # *允许任何ip访问
c.NotebookApp.open_browser = False # 默认不打开浏览器
c.NotebookApp.allow_remote_access = True
c.NotebookApp.notebook_dir = '/mnt/hhd' # 修改为之前设置于宿主机共享的路径
在容器内启动:jupyter lab --allow-root
,然后在服务器的浏览器里打开映射端口:127.0.0.1:7777
输入密码就能访问。
正常退出不关闭容器,请按Ctrl+P+Q
ssh root@your-server-ip -p 8022
,这个 8022
就是启动容器的时候设置的映射端口。之后输入root账户密码即可,和正常的连接远程服务器一样。jupyter lab --allow-root
启动容器内的jupyter,在VsCode终端设置端口转发规则,即可把jupyter默认端口转发到本地指定端口打开。通常服务器是放在实验室的局域网的,如果我们在局域网外就没法进行访问了。为此可以使用frp之类的软件做反向代理来实现内网穿透,这个方案需要你先准备一台带公网IP的云服务器(我用的是阿里云的ECS),优点就是完全可控,自己想配置多少个端口的穿透都可以,速度跟你的云服务器带宽有关。
frp分为frps(server)和frpc(client)两个包 ,其中前者安装到我们的云服务器上,后者安装在需要被外网访问到的各个设备上,这里就是指我们的深度学习工作站。
在这里下载适合你服务器系统的frp软件,之后解压:
tar -zxvf frp_0.37.0_linux_amd64.tar.gz
解压之后的文件夹中既包含了服务端的文件又包括客户端的文件,这里所有 frpc 开头的文件都是客户端文件,强迫症可以全部删了,在云服务器只需要保留 frps 开头的文件。
修改frps.ini文件如下(注意删除中文注释):
[common]
# frp server的工作端口,默认7000,可以更改
bind_port = 7000
# http和https的端口定义
vhost_http_port = 80
vhost_https_port = 443
# dashboard图形管理页面使用端口
dashboard_port = 7500
# dashboard帐号
dashboard_user = admin
# dashboard登陆密码,可以自己修改,这里用admin
dashboard_pwd = admin
更多帮助见frp帮助文档:传送门
注意:以上端口都需要去阿里云控制台打开对应端口
[common]
server_addr = 101.201.71.144 # 填写自己的云服务器公网IP地址,有域名的读者也可以填写域名
server_port = 7000 # 云服务器设置的端口为7000,所以这里填7000
# token = 000000 # 与frps.ini设置的token一致,没设置则删去
[ssh]
type = tcp
local_ip = 127.0.0.1 # 计算机网络中,127.0.0.1代表本地地址
local_port = 22 # 需要映射出去的端口号,80为http默认端口号,此端口号必须被本机放行
remote_port = 20022 # 映射到云服务器上面的端口号,同理需要在阿里云的控制台开放
通过上述的设定,就把对于云服务器特定端口的访问给重定向到本地服务器的某个端口了,简单地讲就是:假如我用SSH客户端访问 [ECS 公网ip]:20022
,就可以经过反向代理直接访问到[本地的深度学习服务器ip]:22
sudo vim /lib/systemd/system/frps.service
写入以下内容[Unit]
Description=Frp Server
After=network.target syslog.target
Wants=network.target
[Service]
# frp启动时,网络可能还没准备好,导致frp启动失败,当frp服务启动失败时,时隔5秒后重新启动它
Restart=always
RestartSec=5
#启动服务的命令(此处写你的frps的实际安装目录,删除注释)
ExecStart=/frp_0.37.0_linux_amd64/frps -c /frp_0.37.0_linux_amd64/frps.ini
[Install]
WantedBy=multi-user.target
然后刷新配置
systemctl daemon-reload
启动frps
systemctl start frps
再打开自启动
systemctl enable frps
sudo systemctl restart frps
sudo systemctl stop frps
sudo systemctl status frps
sudo vim /etc/systemd/system/frpc.service
写入以下内容[Unit]
Description=Frp Client
After=network.target syslog.target
Wants=network.target
[Service]
# frp启动时,网络可能还没准备好,导致frp启动失败,当frp服务启动失败时,时隔5秒后重新启动它
Restart=always
RestartSec=5
#启动服务的命令(此处写你的frpc的实际安装目录,删除注释)
ExecStart=/home/yf703a/frp_0.37.0_linux_amd64/frpc -c /home/yf703a/frp_0.37.0_linux_amd64/frpc.ini
[Install]
WantedBy=multi-user.target
同理,刷新配置
systemctl daemon-reload
启动frpc
systemctl start frpc
再打开自启动
sudo systemctl enable frpc
完成这些配置后,现在可以通过ssh -p [端口] [用户名]@[公网IP]
,在任何网络下连接到内网的机器:
注意: 这里的用户名是内网主机的用户名,不是公网服务器的用户名,我就是掉这坑里了,端口号为设置的远程端口(即上面设置的20022)
如果需要使用内网穿透方式访问jupyter,我们可以把服务器的7777端口映射到阿里云服务器上,实现在公网访问jupyter。修改frps.ini文件如下(注意删除中文注释):
[jupyter]
type = tcp
local_ip = 127.0.0.1
local_port = 7777
remote_port = 27777 # 记得去阿里云开启端口