GPU服务器的多人环境搭建
环境
CPU: Intel(R) Xeon(R) Gold 6154 2
Momery: 128G GPU: 3080TI 2
Disk: 16T HD & 512 SSD
System: Ubuntu 22.04 Server
前言
因为最近团队对于GPU的需求量增加,但之前都是在工作电脑上直接使用GPU进行训练和使用,而几个人中只有一两台电脑有显卡,所以后期就更新了服务器。 随之而来的就会产生一个问题,大家直接用账号密码链接上去每个人的环境、配置都会造成环境、冲突,甚至导致系统出错,所有就有必要通过容器的解决方案让每个人都隔离,相互不影响,并且不能直接操作到宿主机,以保证所有人操作都在容器进行而不影响到宿主机,除此之外也需要给每一个容器映射显卡。 在这个基础上有三个相关的技术,分别为Docker、LXC、虚拟机(PVE、ESXI等)。首先排除掉Docker,Docker比较适用应用级的层面上,不符合需求。虚拟机虽然可以直通显卡等,但直通单张显卡后,其他虚拟机无法使用。所以最后就锁定到了LXD,LXD由Canonical有限公司发起,是一个类容器管理系统,而底层则基于LXC容器,额外提供了更加方便的API接口、分布式、网络管理、储存管理等,同时Ubuntu 22.04自集成了LXD,所以这里部署也是通过LXD来管理LXC容器。
准备
- 16T的机械盘,分为两个分区(分区可以使用fdisk),分1T用于给LXC作储存池,剩余的15T用于挂载到宿主机下的/data目录,后期映射到每个容器的/data目录下,用于所有容器之间的数据互传和数据存储(因为相互之间的数据不涉及隐私,所以可以共用),这样的好处在于大家都将重要的数据放置/data,即使容器出现了问题,也不会影响到数据的丢失问题。
- 显卡驱动可以直接通过Ubuntu的GPU驱动安装,如果你没有安装显卡驱动,你可以直接输入nvidia-smi,会得到相关的提示,而不用安装网上的教程去设置,因为非常麻烦。
- 使用apt安装zfsutils-linux,前者用于安装LXD的储存池驱动,LXD支持多种储存池,这用于储存LXD、LXC相关的数据。
- 使用apt安装bridge-utils,该工具是用于管理和创建网桥设备所需要的工具和程序。
初始化LXD
通过命令执行sudo lxd init,就会得到如下的问题:
- LXD Clustering:用于集群配置,单节点不需要,默认为no,回车即可
- new storage pool:需要创建一个存储池,输入yes
- Name of storage pool:给存储池命名,默认为default,回车即可
- storage backend:存储后端,默认使用zfs,回车即可
- Create a new ZFS pool:需要创建一个ZFS池,默认为no,输入yes
- use an existing block device:使用现有的块设备(硬盘),输入yes
- Path to block device:输入现有的硬盘,比如我的为sda1,那么就输入/dev/sda1
- MAAS server:MAAS是一个用于将物理机视为云服务器的集群服务,默认为no,回车即可
- new local network bridge:是否创建一个新的桥接网络,输入yes
- new bridge be called:命名新的网桥名称,默认即可
- IPv4:IPv4相关配置,默认为auto,回车即可
- IPv6:IPv6相关配置,默认为auto,回车即可
- would you like lxd to be available over the network:使用想通过网络访问LXD,默认为no,回车即可
- would you like stale cached images to be updated automatically:默认yes,回车即可
- YAML printed:是否打印出lxd init的配置信息,默认为no,回车即可
创建容器模板
创建容器模板的意义在于你可以设置一个基础配置的容器,然后基于这个容器进行复制出多个容器出来,而不用再针对每个容器进行重复的基础设置。 在使用前需要下载一个已打包的容器镜像,因为需要下载,所以可以使用清华大学的国内镜像用于提升下载镜像的速度。 添加清华大学镜像源:
sudo lxc remote add tuna-images https://mirrors.tuna.tsinghua.edu.cn/lxc-images/ --protocol=simplestreams --public
通过查找镜像列表,找到对应镜像的ID:
sudo lxc image list tuna-images: | grep "ubuntu/18"
获取到列表后,选择对应的版本,这里我选择了id为2c44d2a68b29的ubuntu/18.04 (7 more)镜像,这是因为该版本标识了类型为容器CONTAINER。 确定好后远程的容器镜像id后,将其下载到本地并启动:
#origin为源,这里使用上面添加的清华源,FINGERPRINT代表该源下载容器镜像id,ContainerName为创建的容器名称
sudo lxc launch origin:<FINGERPRINT> <ContainerName>
#我这里直接使用
sudo lxc launch tuna-images:2c44d2a68b29 gpuTemplate
查看是否启动成功容器可以使用sudo lxc list
。
创建公共目录
在准备阶段中宿主机的/data目录已挂载好了15T的分区,需要将其添加到上面创建的容器中:
sudo lxc config device add <ContainerName> <ShareName> disk source=<host_dir_path> path=<Container_dir_path>
#实例:
sudo lxc config device add gpuTemplate share_dir disk source=/data path=/data
容器配置
因为将该容器作为基础模板,所以需要配置一些常用的依赖以及切换为国内apt源。 通过以下命令进入到容器内部:
sudo lxc exec <ContainerName> bash
然后修改容器内部的apt源:
vi /etc/apt/sources.list
然后将国内源写入该文件后,运行apt update更新列表即可。 安装vim、gcc、g++、make、cmake、python、lspci:
apt install vim gcc g++ make cmake python3.10 pciutils
安装Python后,将可执行文件放在/usr/bin/python3.10,所以直接需要将python3.10可执行文件软连接到当前目录为python,这样直接可以使用python命令。
ln -s /usr/bin/python3.10 /usr/bin/python
添加GPU设备到容器中
为容器添加所有GPU:
sudo lxc config device add <ContainerName> gpu gpu
添加指定GPU:
sudo lxc config device add <ContainerName> gpu0 gpu id=0
安装GPU驱动,网上教程中的GPU驱动安装比较麻烦,所以可以在宿主机中安装ubuntu-drivers:
apt install ubuntu-drivers-common
安装完成后使用以下命令,会得到显卡型号、推荐的显卡驱动:
ubuntu-drivers devices
#返回
== /sys/devices/pci0000:3a/0000:3a:02.0/0000:3b:00.0 ==
modalias : pci:v000010DEd00002208sv000010DEsd00001535bc03sc00i00
vendor : NVIDIA Corporation
model : GA102 [GeForce RTX 3080 Ti]
manual_install: True
driver : nvidia-driver-470-server - distro non-free
driver : nvidia-driver-470 - distro non-free
driver : nvidia-driver-515 - distro non-free
driver : nvidia-driver-510 - distro non-free
driver : nvidia-driver-510-server - distro non-free
driver : nvidia-driver-515-open - distro non-free recommended
driver : nvidia-driver-515-server - distro non-free
driver : xserver-xorg-video-nouveau - distro free builtin
在这里我选择的是nvidia-driver-515-server版,然后进行到容器内部后,使用apt install nvidia-driver-515-server进行安装,安装完成后,你在容器内部使用nvidia-smi即可看见相关信息表示安装成功。 关于如果要特定的cuda版本则需要根据具体情况选择对应的显卡驱动。
配置容器的远程登陆
安装ssh:
apt install openssh-server
安装完成后可以通过以下命令查看是否启动:
systemctl status sshd
配置完成后,可以找一台内网的机器通过ssh-keygen -t rsa生成非对称加密的密钥,然后将公钥的内容复制到容器内部/root/.ssh/authorizedkeys文件中,保存退出,最后重启ssh服务:
systemctl restart sshd
配置完成后,回到宿主机中,设置端口映射,目的在于当宿主机接到的目标端口的请求的时候,将数据传输到指定端口的容器内部中,在这里配置的是sshd远程连接,所以容器接收的端口为22,宿主机的监听端口则是设置为6001,当宿主机的6001端口接到数据就转发给容器内部的22端口。 设置命令可以通过下面的代码设置:
sudo lxc config device add <ContainerName> <name> proxy listen=tcp:<host_ip>:<host_port> connect=tcp:<container_ip>:<container_port> bind=host
#这里我的设置为:
sudo lxc config device add GPUTemplate testssh proxy listen=tcp:192.168.1.102:6001 connect=tcp:10.180.194.93:22 bind=host
如果后期要删除该条测试端口映射,则使用以下的命令:
# 查看配置项目
sudo lxc config device list <ContainerName>
# 找到需要删除的端口别称,然后删除
sudo lxc config device remove <ContainerName> <config_name>
制作容器实例
制作容器实例实际上就是基于现有运行的实例进行复制一份,然后再做一点基础的修改就可以让他人使用。 复制容器:
sudo lxc copy <ContainerTemplateName> <newContainerName>
复制后,需要手动启动
sudo lxc start <newContainerName>
复制完成后,可以按照上述的步骤设置使用者的ssh key和端口映射即可。
参考文章
- https://shenxiaohai.me/2018/12/03/gpu-server-lab/
- https://linuxcontainers.org/lxd/introduction/
- https://zh.wikipedia.org/wiki/LXC
- https://linuxcontainers.org/lxd/docs/master/explanation/storage/
- https://linuxcontainers.org/lxd/docs/master/explanation/networks/
- https://blog.csdn.net/zhw864680355/article/details/90411288
- https://developer.nvidia.com/cuda-toolkit-archive
- https://www.cnblogs.com/booturbo/p/13960935.html
- https://pytorch.org/get-started/locally/
- https://www.jianshu.com/p/978bc51029fa
- https://command-not-found.com/ubuntu-drivers
- https://www.myfreax.com/how-to-nvidia-drivers-on-ubuntu-20-04/
- https://blog.csdn.net/Guzarish/article/details/118626384
- https://blog.csdn.net/dou3516/article/details/120823932
- https://developer.aliyun.com/article/971986