Slrum集群调度系统与Apptainer容器技术

6/17/2023 Slrum集群调度系统ApptainerSingularity容器技术高性能计算

# 1. Slrum集群调度系统概述

# 1.1 Slrum是什么

Slurm 是一个开源、容错、高可伸缩的集群管理和 Linux 集群作业调度系统。

它有三个关键功能:

  • 在一段时间内为用户分配独占或者非独占的计算资源,用于执行工作任务。
  • 提供一个框架,用于在分配的节点集上启动、执行、监视工作,一般是并行作业任务。
  • 管理挂起的工作队列,来仲裁资源争夺问题。

# 1.2 Slrum架构设计

通过集中式的 slurmctld 来管理和控制资源,充当控制节点。每个计算节点都有一个守护进程,称为 slurmd。slurmdbd 负责记录在数据库中 slurm 所管理的集群信息。通过 slurmrestd 的 REST API 与 Slurm 交互。还有一些命令行工具,来实现对作业的处理以及分区、节点等维护。

Slrum架构设计

# 1.3 Slrum运行方式

[1] 交互式作业提交 (srun)

  • 资源分配与任务加载两步均通过srun命令进行。
  • 当在登录shell中执行srun命令时,srun首先向系统提交作业请求并等待资源分配,然后在所分配的节点上加载作业任务。
  • 采用该模式,用户在该终端需等待任务结束才能继续其它操作,在作业结束前,如果提交时的命令行终端断开,则任务终止。
  • 一般用于短时间小作业测试。

[2] 批处理作业 (sbatch)

  • 批处理作业:提交后立即返回该命令行终端,用户可进行其它操作
  • 使用sbatch命令提交作业脚本,作业被调度运行后,在所分配的首个节点上执行作业脚本。
  • 提交时采用的命令行终端终止,也不影响作业运行。

[3] 实时分配模式作业 (salloc)

  • 用户需指定所需要的资源条件,向资源管理器提出作业的资源分配请求。提交后,作业处于排队, 当用户请求资源被满足时,将在用户提交作业的节点上执行用户所指定的命令。
  • 指定的命令运行结束后,用户申请的资源被释放。
  • 在作业结束前,如果提交时的命令行终端断开,则任务终止。
  • 典型用途是分配资源并启动一个shell, 然后在这个shell中运行并行作业。

# 2. 搭建单节点Slurm环境

服务器环境:Debian 11 x86_64 系统,8GB内存,160GB存储,2x Intel Xeon CPU,无GPU,带宽1 Gigabit

对于单节点部署来说,slurmctld和slurmd必须配置,而slurmdbd可以不配置。不过如果要实现限制每个用户同时能提交多少作业,能占用多少卡,作业最长能跑多长时间等等这些约束,还是需要配置slurmdbd的,此处跳过。另外,如果是多节点使用Slurm还需要挂载网络文件系统(NFS),而这个没有在单节点部署中使用到。除此之外,由于这台服务器没有GPU,因此与GPU相关的配置也跳过。

# 2.1 部署Munge服务

# 2.1.1 Munge是什么

Munge是认证服务,用于生成和验证证书。应用于大规模的HPC集群中。它允许进程在“具有公用用户和组的”主机组中,对另外一个“本地或者远程的”进程的UID和GID进行身份验证。这些主机构成由共享密钥定义的安全领域。在此领域中的客户端能够在不使用root权限,不保留端口,或其他特定平台下进行创建凭据和验证。简而言之,在集群中,Munge能够实现本地或者远程主机进程的GID和UID验证。

# 2.1.2 安装Munge服务

安装munge

$ sudo apt-get update
$ sudo apt-get install munge
1
2

设置正确的权限

$ sudo chown -R munge: /etc/munge /var/log/munge /var/lib/munge
$ sudo chmod 700 /etc/munge /var/log/munge /var/lib/munge
$ sudo chown munge:munge /etc/munge/munge.key
$ sudo chmod 400 /etc/munge/munge.key
1
2
3
4

启动munge服务

$ sudo systemctl enable munge
$ sudo systemctl start munge
1
2

检查munge服务状态

$ sudo systemctl status munge

● munge.service - MUNGE authentication service
     Loaded: loaded (/lib/systemd/system/munge.service; enabled; vendor preset: enabled)
     Active: active (running) since Sat 2023-06-24 21:08:42 CST; 1min 48s ago
       Docs: man:munged(8)
   Main PID: 1003194 (munged)
      Tasks: 4 (limit: 9528)
     Memory: 684.0K
        CPU: 11ms
     CGroup: /system.slice/munge.service
             └─1003194 /usr/sbin/munged

Sat 12 21:08:42 eula systemd[1]: Starting MUNGE authentication service...
Sat 12 21:08:42 eula systemd[1]: Started MUNGE authentication service.
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15

注:可以通过如下命令进行卸载

// 停止munge服务
$ sudo systemctl stop munge
// 卸载munge
$ sudo apt-get remove --purge munge
// 清理残留文件
$ sudo rm -rf /etc/munge /var/log/munge /var/lib/munge
1
2
3
4
5
6

# 2.2 部署Slurm服务

# 2.2.1 安装Slurm并准备配置文件

安装Slurm

$ sudo apt install slurm-wlm slurm-wlm-doc slurm-wlm-torque -y \
&& sudo rm -rf /var/spool/slurm-llnl \
&& sudo mkdir /var/spool/slurm-llnl \
&& sudo chown -R slurm.slurm /var/spool/slurm-llnl \
&& sudo rm -rf /var/run/slurm-llnl/ \
&& sudo mkdir /var/run/slurm-llnl/ \
&& sudo chown -R slurm.slurm /var/run/slurm-llnl/
1
2
3
4
5
6
7

在创建配置文件之前,需要去查看几个参数:

// 查看本机名称,配置文件里要用到,用<hostname>代替
$ hostname
// 查看CPU物理核数
$ lscpu | grep "Core(s) per socket" | awk '{print $4}'
// 查看总内存大小
$ free -h | grep Mem | awk '{print $2}'
1
2
3
4
5
6

/etc/slurm创建slurm.conf文件,需要注意该配置文件里有三处<hostname>,需要改成刚刚查询到的值,配置错了会起不来服务。

# slurm.conf file generated by configurator easy.html.
# Put this file on all nodes of your cluster.
# See the slurm.conf man page for more information.
#
ControlMachine=<hostname>
#ControlAddr=
#
#MailProg=/bin/mail
MpiDefault=none
#MpiParams=ports=#-#
ProctrackType=proctrack/pgid
ReturnToService=1
SlurmctldPidFile=/var/run/slurm-llnl/slurmctld.pid
#SlurmctldPort=6817
SlurmdPidFile=/var/run/slurm-llnl/slurmd.pid
#SlurmdPort=6818
SlurmdSpoolDir=/var/spool/slurmd
SlurmUser=slurm
#SlurmdUser=root
StateSaveLocation=/var/spool/slurm-llnl
SwitchType=switch/none
TaskPlugin=task/none
#
#
# TIMERS
#KillWait=30
#MinJobAge=300
#SlurmctldTimeout=120
#SlurmdTimeout=300
#
#
# SCHEDULING
#SchedulerType=sched/backfill
#SelectType=select/linear
SelectType=select/cons_res
SelectTypeParameters=CR_CPU
#
#
# LOGGING AND ACCOUNTING
AccountingStorageType=accounting_storage/none
ClusterName=cluster
#JobAcctGatherFrequency=30
JobAcctGatherType=jobacct_gather/none
#SlurmctldDebug=3
#SlurmctldLogFile=
#SlurmdDebug=3
#SlurmdLogFile=
#
#
# COMPUTE NODES
NodeName=<hostname> CPUs=4 State=UNKNOWN
PartitionName=cpu Nodes=<hostname> Default=YES MaxTime=INFINITE State=UP
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52

# 2.2.2 启动slurmctld和slurmd服务

之后便可启动slurmctld和slurmd服务,并运行sinfo命令检查是否安装成功。

$ sudo service slurmctld status
● slurmctld.service - Slurm controller daemon
     Loaded: loaded (/lib/systemd/system/slurmctld.service; enabled; vendor preset: enabled)
     Active: active (running) since Sat 2023-06-24 21:28:42 CST; 6min ago
       Docs: man:slurmctld(8)
   Main PID: 1456212 (slurmctld)
      Tasks: 7
     Memory: 3.4M
        CPU: 228ms
     CGroup: /system.slice/slurmctld.service
             └─1456212 /usr/sbin/slurmctld -D

Sat 24 21:28:42 eula systemd[1]: Started Slurm controller daemon.
$ sudo service slurmd start
$ sudo service slurmd status
● slurmd.service - Slurm node daemon
     Loaded: loaded (/lib/systemd/system/slurmd.service; enabled; vendor preset: enabled)
     Active: active (running) since Sat 2023-06-24 21:29:22 CST; 7min ago
       Docs: man:slurmd(8)
   Main PID: 1452775 (slurmd)
      Tasks: 1
     Memory: 4.5M
        CPU: 589ms
     CGroup: /system.slice/slurmd.service
             └─1452775 /usr/sbin/slurmd -D

Sat 24 21:29:22 eula systemd[1]: Started Slurm node daemon.
$ sinfo
PARTITION AVAIL  TIMELIMIT  NODES  STATE NODELIST
cpu*         up   infinite      1  drain eula
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30

# 3. Slrum常用命令及基本使用

# 3.1 Slurm常用命令

Slurm常用命令如下:

scancel:取消排队或运行中的作业或作业步。
squeue:显示队列中的作业及作业状态。
sinfo:显示队列或节点状态。
scontrol:显示或设定Slurm作业、队列、节点等状态。
1
2
3
4

更多命令详见官方手册:https://slurm.schedmd.com/archive/slurm-19.05.2/man_index.html (opens new window)

# 3.2 Slurm申请资源参数

Slurm申请资源的参数如下:

-J test              # 作业名指定为test
--partition=debug    # 作业提交分区为debug分区
--nodes=1            # 最小需要分配的节点数量
--nodelist=gpu01     # 指定分配的节点
--cpus-per-task=1    # 需要分配的CPU核心数
-c=1                 # 需要分配的CPU核心数 (同上)
--gres=gpu:1         # 每个节点需要分配的GPU数
--mem=10G            # 需要分配的内存
--time=1:00:00       # 任务运行的最长时间
1
2
3
4
5
6
7
8
9

原则:不要影响其他人使用

  • 确保 --gres=gpu:0 要加在命令或sbatch的脚本上,不然默认分配全部gpu,如果你只用1张卡,那这样其他的别人就没法用了。
  • 确保 --time=xxx 加上。给自己的程序或脚本加一个合理的时间,不然有的程序死循环,可能会一直占用资源。
  • 确保 CUDA_VISIBLE_DEVICES 不用。他会绕过 slurm 资源分配,抢占别人的资源。
  • 确保申请资源不用后释放掉。例如salloc申请了资源,及时释放。

# 4. Apptainer容器技术概述

# 4.1 Apptainer是什么

Apptainer容器技术是劳伦斯伯克利国家实验室开发专门用于高性能计算场景的容器技术,它完全基于可移植性进行虚拟化,更加轻量级,部署更快,是专为共享系统和高性能计算(HPC)环境中的易用性而设计,目前被广泛地各高性能计算中心。

注:Apptainer 原来叫做 Singularity(因Singularity项目加入Linux基金会,改名为Apptainer),Singularity目前已经不再维护了,仅用于存档。旧版项目地址 (opens new window)

Apptainer特性

它具有以下特点:

  • 不可变的单文件容器镜像格式,支持加密签名和加密。
  • 默认集成优于隔离,轻松利用集群或服务器上的 GPU、高速网络、并行文件系统。
  • 计算的移动性,单文件 SIF 容器格式易于传输和共享。
  • 简单有效的安全模型。在容器内部与容器外部是同一用户,并且默认情况下无法在主机系统上获得额外的权限。

# 4.2 HPC场景选择Apptainer的原因

Apptainer 容器技术在功能上类似于 Docker,使用上与 Docker 略有不同,Docker 用户可以轻松上手使用。

# 4.2.1 Docker在HPC集群中的问题

Docker 与 Apptainer 是两种常见的容器技术,Docker 应用最为广泛,隔离性高,但是在大规模集群上并不适合,主要有以下几个方面:

  • 资源限制问题:Slurm 利用 cgroups 实现资源分配,需要在配置文件中进行细粒度的资源划分,Docker 通过 Docker daemon 无法实现资源限制,即调度管理器的资源限制无法施加到容器中。
  • 权限问题:Docker daemon 守护进程使用 root 用户启动,HPC 场景期望使用普通用户运行容器,如 Slurm 普通用户也可以提交作业一样,不需要什么操作都需要 root 用户来管理。
  • 容器化方便应用批量部署和维护,但 Docker 容器技术也包含了不必要的资源开销,如Docker镜像有可能携带多余的文件导致镜像体积大,占用系统资源。

集群中的资源使用通常需要由调度管理器来进行分配,例如 Slurm/PBS/SGE 等系统负责资源分配。调度管理器根据用户需求为每个作业分配一定的资源,实质上是利用 cgroups 针对每个作业进行配置实现的。而 Docker 镜像的启动实际上是由 Docker Daemon 去执行的,如此资源限制自然会失效。并且 Docker Daemon 是由 root 用户启动的,无论是为普通用户设置 sudoer 还是将普通用户添加到 Docker 用户组中都不是一个安全的方式。

# 4.2.2 Apptainer在HPC集群的优势

Apptainer 容器技术就是专门针对高性能计算场景的。因此解决了诸如Docker在大规模集群上的问题。具体优势有以下几种:

  • 权限问题,Apptainer 可以继承用户的权限,比如A用户使用的容器,只有A用户有权限进行操作。
  • Apptainer 方便迁移,拉取镜像直接放到自己目录下,直接拷贝走镜像即可,且 Apptainer 没有复杂的缓存机制,镜像已经过压缩,只需占用非常少的磁盘空间;而 Docker 所有人的镜像都放在固定位置,虽然 Docker 也可以打包拷贝走,但操作起来比较麻烦。
  • 和现有系统无缝整合:系统用户权限、网络等均直接继承宿主机配置,并且无需进入某个镜像后再执行命令,可以直接在外部调用镜像内的指令,就像执行一个本地安装的指令一样。
  • 无需运行 daemon 守护进程:Apptainer 提供的完全是一个运行时的环境,在不使用时不需要单独的进程,软件安装到一个虚拟机文件中,随时启动,不占用任何资源,资源限制和权限问题也得以解决。
  • 绑定目录的问题,Docker 每次运行都要绑定目录到容器中,非常麻烦,而 Apptainer 可以直接访问。
  • 根据 Apptainer 研发主管 Gregory Kurtzer 的说法,Apptainer 与 GPU 协同,非常适合与机器学习软件。

除此之外,Apptainer 还具有启动迅速、资源开销小、轻松的迁移和扩展等优点,Apptainer 还支持多种镜像和容器文件格式,甚至可以直接使用 Docker 提供的镜像。Apptainer 可以轻易的现有的 HPC 系统整合,几乎无需任何额外的开发就能让现有的 HPC 变成一个轻量级的容器云。

# 5. 搭建Apptainer服务

服务器环境:Debian 11 x86_64 系统,8GB内存,160GB存储,2x Intel Xeon CPU,无GPU,带宽1 Gigabit

这里采用编译安装的方式,具体详见 官方安装文档 (opens new window)

# 5.1 准备编译环境

# 5.1.1 安装系统依赖项

需要先将开发工具和依赖库安装到服务器上。

$ sudo apt-get update
$ sudo apt-get install -y \
    build-essential \
    libseccomp-dev \
    pkg-config \
    uidmap \
    squashfs-tools \
    squashfuse \
    fuse2fs \
    fuse-overlayfs \
    fakeroot \
    cryptsetup \
    curl wget git
1
2
3
4
5
6
7
8
9
10
11
12
13

# 5.1.2 安装Go环境

Apptainer是用Go编写的,建议安装较新版本的Go环境。

$ curl -O https://dl.google.com/go/go1.19.6.linux-amd64.tar.gz
$ tar xvf go1.19.6.linux-amd64.tar.gz && rm -f go1.19.6.linux-amd64.tar.gz
$ sudo chown -R root:root ./go
$ sudo mv go /usr/local
$ vim ~/.profile
1
2
3
4
5

在配置文件末尾追加Go的环境配置。

export GOROOT=/usr/local/go
export GOPATH=$HOME/work
export PATH=$GOPATH/bin:$GOROOT/bin:$PATH
1
2
3

刷新.profile配置文件并验证安装是否成功。

$ source ~/.profile
$ go version
go version go1.19.6 linux/amd64
1
2
3

# 5.2 编译安装Apptainer

拉取项目代码并编译构建。

$ git clone https://github.com/apptainer/apptainer.git
$ cd apptainer
$ ./mconfig
$ cd ./builddir
$ make
$ sudo make install
$ apptainer --version
apptainer version 1.2.3+291-g1a0df58e3
1
2
3
4
5
6
7
8

# 6. Apptainer命令及镜像制作

# 6.1 查看Apptainer命令帮助

$ apptainer --help
1
Apptainer查看帮助

# 6.2 制作Apptainer镜像

# 6.2.1 从Docker存储库拉取镜像

Apptainer可以直接拉取Docker镜像。

$ apptainer pull docker://deepcortex/ubuntu-conda
1

可见生成了一个文件,ubuntu-conda_latest.sif,这个文件可以直接运行,但是不能修改(即不能继续安装依赖包)。

$ apptainer shell ubuntu-conda_latest.sif
$ Apptainer> cat /etc/issue
Ubuntu 16.04.3 LTS \n \l
$ Apptainer> conda --version
conda 4.3.27
$ Apptainer> python3 --version
Python 3.6.2 :: Anaconda, Inc.
$ Apptainer> exit
1
2
3
4
5
6
7
8

# 6.2.2 继续安装依赖包制作镜像

要继续装包需要建立sandbox, ubuntu_sandbox 为 sandbox 名字,可以自由命名。执行过后会在当前目录下生成了ubuntu_sandbox目录。

$ apptainer build --sandbox ubuntu_sandbox ubuntu-conda_latest.sif
1

使用sudo进入镜像准备进行软件安装。

$ sudo apptainer shell --writable ubuntu_sandbox/
1

安装常用工具及依赖环境,如curl。

$ Apptainer> apt-get update -y && apt-get install curl -y  
$ Apptainer> curl --version
$ Apptainer> exit
1
2
3

安装常用工具及依赖环境安装完毕后,重新生成sif文件,可以减小镜像文件大小。

$ apptainer build test.sif ubuntu_sandbox
1

重新进入自己制作的镜像里查看环境。

$ apptainer shell test.sif
$ Apptainer> curl --version
1
2

# 7. 参考资料

[1] 高性能容器之Apptainer from CSDN (opens new window)

[2] Installing Apptainer from Github (opens new window)

[3] Restoring pre-Apptainer library behavior from Apptainer官方文档 (opens new window)

[4] Manjaro Linux安装singularity-container from 腾讯云 (opens new window)

[5] Apptainer_Singularity容器原理 from CSDN (opens new window)

[6] singularity制作镜像入门 from 知乎 (opens new window)

[7] 介绍另外一个容器技术 Apptainer from CSDN (opens new window)

[8] Slurm Man Pages from Slurm官方文档 (opens new window)

[9] Slurm资源管理架构 from CSDN (opens new window)

[10] 使用K8s一键部署Slurm集群 from Github (opens new window)

[11] slurm-gpu集群搭建详细步骤 from CSDN (opens new window)

[12] MLOps on HPC/Slurm with Kubeflow from DKubeX (opens new window)

[13] Singularity implementation of k8s operator for interacting with SLURM from Github (opens new window)

[14] Ubuntu单节点SLURM部署 from 知乎 (opens new window)

[15] munge认证服务配置-集群搭建步骤4 from CSDN (opens new window)

[16] CONQUEST 编译安装指南 Slurm 篇 from zhonger (opens new window)

Last Updated: 6/1/2024, 9:45:58 PM