slurm单机最简安装全球最详细教程

2021年1月27日

本文指导你在Ubuntu 20.04下安装slurm 19.05。你只需要一台机器。本文不安装数据库。除了安装,本文还负责验证安装,并提供提交作业的范例。

安装

{{sudoText}}apt install -y slurm-wlm 
{{sudoText}}apt install -y slurm-wlm-doc

slurm-wlm-doc提供了相关文档,比如/usr/share/doc/slurm-wlm/html/configurator.html。如果你按照本slurm single machine minimal installation guide,你不需要用configurator来生成配置文件。

有的文章要求安装munge[1]——Authentication plugins identifies the user originating a message[2],官方网站说munge是一个plugin,对于到底单机模式要不要plug in说得不明不白。我这里并不告诉你是否要安装,你只要跟着本教程走就行了!apt install slurm-wlm的时候自动安装了munge,你就不用考虑要不要装了,反正已经装上了!

下载https://gist.github.com/gqqnbig/8a1e5082ec1c974a84fdd8abd1a4fbf6,注意检查开头三行的路径是否正确。运行结束后,不要运行systemctl相关的命令!

截至目前,slurm已经安装并配置完毕了,但到底能不能用还是个问号。不用systemctl是因为systemctl多加了一层包装,出错可能是systemctl出错,也可能是slurm出错,不易区分。所以,下面我们手动运行slurm。

按照官方文档,slurmctld运行在master节点,负责监视资源和作业;slurmd运行在计算节点(slave节点),负责执行作业。所以,因为我们只有一台机器,必须既运行slurmctld,又运行slurmd。注意,slurm软件本身并没有slurm命令。

验证

运行slurmctld

$ sinfo
PARTITION AVAIL  TIMELIMIT  NODES  STATE NODELIST
normal*      up   infinite      1   unk* localhost

发现state是unknown*。unknown表示控制节点不知道节点localhost的状态。这是正常的,因为你还没有启动slurmctld。*表示节点localhost无法联通。[3]这是正常的,因为你还没有启动slurmd。

$ sudo slurmctld -c -D
slurmctld: error: Unable to open pidfile `/var/run/slurm/slurmctld.pid': No such file or directory
slurmctld: error: Configured MailProg is invalid
slurmctld: slurmctld version 19.05.5 started on cluster 35adae022fc4478592f75c3b4c97bce1
slurmctld: No memory enforcing mechanism configured.
slurmctld: layouts: no layout to initialize
slurmctld: layouts: loading entities/relations information
slurmctld: Recovered state of 0 reservations
slurmctld: _preserve_plugins: backup_controller not specified
slurmctld: Running as primary controller
slurmctld: No parameter for mcs plugin, default values set

发现第一行就报错。打开/etc/slurm-llnl/slurm.conf,发现该路径由SlurmctldPidFile指定,而/var/run里没有slurm目录。按照经验,slurm不会创建目录。于是,在/etc/slurm-llnl/slurm.conf修改为

SlurmctldPidFile=/var/run/slurmctld.pid
SlurmdPidFile=/var/run/slurmd.pid

再运行

$ sudo slurmctld -c -D
slurmctld: error: Configured MailProg is invalid
slurmctld: slurmctld version 19.05.5 started on cluster 35adae022fc4478592f75c3b4c97bce1
slurmctld: No memory enforcing mechanism configured.
slurmctld: layouts: no layout to initialize
slurmctld: layouts: loading entities/relations information
slurmctld: Recovered state of 0 reservations
slurmctld: _preserve_plugins: backup_controller not specified
slurmctld: Running as primary controller
slurmctld: No parameter for mcs plugin, default values set

发现pidfile的错误不见了。”error: Configured MailProg is invalid”问题不大,可以以后再修。slurm可以在job完成后发电子邮件通知,这个错误的意思是没有配置好邮件服务。

$ sinfo
PARTITION AVAIL  TIMELIMIT  NODES  STATE NODELIST
normal*      up   infinite      1  down* localhost

发现控制节点已经知道节点localhost的状态为down。

接下来运行slurmd。

运行slurmd

$ sudo slurmd -D
slurmd: Message aggregation disabled
slurmd: WARNING: A line in gres.conf for GRES gpu has 1 more configured than expected in slurm.conf. Ignoring extra GRES.
slurmd: slurmd version 19.05.5 started
slurmd: slurmd started on Thu, 28 Jan 2021 02:59:20 +0000
slurmd: CPUs=48 Boards=1 Sockets=2 Cores=12 Threads=2 Memory=128573 TmpDisk=111654 Uptime=2860 CPUSpecList=(null) FeaturesAvail=(null) FeaturesActive=(null)

同时发现slurmctld的日志已经输出”slurmctld: Node localhost now responding”,运行sinfo发现

$ sinfo
PARTITION AVAIL  TIMELIMIT  NODES  STATE NODELIST
normal*      up   infinite      1   down localhost

到目前为止,控制节点和计算节点的通信已经正常。但是第二行有警告“WARNING: A line in gres.conf for GRES gpu has 1 more configured than expected in slurm.conf. Ignoring extra GRES.”

打开/etc/slurm-llnl/gres.conf,发现有Name=gpu File=/dev/nvidia[0-1],说明刚才的自动脚本已经正确识别到了本机有两个GPU。打开/etc/slurm-llnl/slurm.conf,发现有NodeName=localhost Gres=gpu CPUs=8 Boards=1 SocketsPerBoard=2 ...。这是不对的。根据slurm.conf – Slurm configuration file,Gres的参数必须有number项,所以要修改为

NodeName=localhost Gres=gpu:2 CPUs=8 Boards=1 SocketsPerBoard=2 ...

重启slurmctld和slurmd,发现该错误消失了。

接下来测试提交作业。

提交作业

$ sinfo
PARTITION AVAIL  TIMELIMIT  NODES  STATE NODELIST
normal*      up   infinite      1   idle localhost
$ squeue
             JOBID PARTITION     NAME     USER ST       TIME  NODES NODELIST(REASON)
$ scontrol show job
No jobs in the system

以上代码显示slurm单机集群正常,目前没有任何job(作业),队列为空。

下面提交一个作业,要求运行名为hostname的程序。hostname是Linux的内置程序,用来打印当前机器的名称。-N1表示hostname程序要在1个节点运行。

$ srun -N1 hostname
gqqnbig

如果该命令迟迟不返回,可能是防火墙问题。

下面提交一个作业,要求运行名为hostname的程序。–nodes=2-3表示该程序要在2到3个节点运行。显然,本文只配置单机集群,没有这么多计算节点,本命令会陷入无限等待。

$ srun --nodes=2-3 hostname
srun: Requested partition configuration not available now
srun: job 17 queued and waiting for resources

在另一个命令行窗口运行

$ squeue
             JOBID PARTITION     NAME     USER ST       TIME  NODES NODELIST(REASON)
                17    normal hostname    gqqnb PD       0:00      2 (PartitionNodeLimit)

发现job 17正在等待。回到原来的命令行窗口,按ctrl+c终止job 17。至于--nodes还可以接受什么样的参数,请参见man srun

测试资源限制

使用《浅谈Linux Cgroups机制》()的C++代码。

#include <unistd.h>
#include <stdio.h>
#include <cstring>
#include <thread>

void test_cpu() {
    printf("thread: test_cpu start\n");
    int total = 0;
    while (1) {
        ++total;
    }
}

void test_mem() {
    printf("thread: test_mem start\n");
    int step = 20;
    int size = 10 * 1024 * 1024; // 10Mb
    for (int i = 0; i < step; ++i) {
        char* tmp = new char[size];
        memset(tmp, i, size);
        sleep(1);
    }
    printf("thread: test_mem done\n");
}

int main(int argc, char** argv) {
    std::thread t1(test_cpu);
    std::thread t2(test_mem);
    t1.join();
    t2.join();
    return 0;
}

编译并运行

$ g++ -o test test.cc --std=c++11 -lpthread
$ ./test
htop

发现CPU占用为100%,内存慢慢涨到约400MB。(如果htop显示三个test,按H切换到进程模式,就只会显示一个了。)运行srun ./test,内存占用相同。

限制内存

现在实现内存限制。在/etc/slurm-lnl/cgroup.conf写入

CgroupAutomount=yes
MaxRAMPercent=0.1
ConstrainRAMSpace=yes

在/etc/slurm-llnl/slurm.conf写入或修改

ProctrackType=proctrack/cgroup
TaskPlugin=task/cgroup

重启slurmctld和slurmd,确保没报任何异常。这时再运行srun ./test,发现RES被限制在12MB,VIRT则很大,说明内存限制成功。(但我们没有限制虚拟内存)

限制CPU

创建文件test-cpu.py,运行它。test-cpu.py输出CPU的数量,并且创建该数量的线程。

#!/usr/bin/env python3

import threading, multiprocessing
import time

print(multiprocessing.cpu_count())

def loop():
    x = 0
    while True:
        x = x ^ 1

for i in range(multiprocessing.cpu_count()):
    t = threading.Thread(target=loop)
    print(f'create a thread {i}...', flush=True)

    t.start()

ps -eLF | grep test-cpu | sort -n -k9 第9列显示的是test-cpu的线程所在的CPU,发现test-cpu.py运行在数个CPU上。

现在用slurm限制,运行srun -c4 ./test-cpu.py,再运行ps,发现test-cpu.py运行在4个CPU上。

这说明,向slurm申请CPU,slurm就只分配那么多个CPU。虽然multiprocessing.cpu_count()能获取到真实的CPU数量,但无法全部使用。

另外也可以通过scontrol show job来检查-c的设置是否生效。

注意,一个slurm job仍然可以看到所有用户或slurm job的进程。 你可以设置hidepid=2令用户只能看到自己的进程。[4]mount -o ...,hidepid=2 /proc这个技术跟slurm无关。

申请GPU

运行tf-GPU-test.py并申请4个GPU。

srun --gres=gpu:4 python tf-GPU-test.py
import time

if __name__ == '__main__':
	# 大概需要300MB内存
	arr = [None] * 10000000

	time.sleep(10)
	for i in range(len(arr)):
		arr[i] = i


	time.sleep(10)
	print('done')

https://stackoverflow.com/questions/52421171/slurm-exceeded-job-memory-limit-with-python-multiprocessing

$ srun --mem=100G hostname
srun: error: Memory specification can not be satisfied
srun: error: Unable to allocate resources: Requested node configuration is not available

我们的机器内存没有100G,所以该任务无法运行。把命令改为srun --mem=10M hostname就可以运行。同时也发现,--mem并不限制任务本身的内存占用。

本文以CC-BY-SA 3.0协议发布
但不允许存在于百度旗下网站

参考资料

neurokernel. gpu-cluster-config/slurm.conf. . 2016-03-13 [2021-01-28].

参考资料

  1. . SLURM single node install. . [2021-01-27].
  2. . Download Slurm. Slurm. [2021-01-27].
  3. . sinfo - View information about Slurm nodes and partitions.. . [2021-01-28]. “NODE STATE CODES”
  4. Vivek Gite. Linux hide processes from other users and ps command. . 2021-06-13 [2022-09-04].