ubuntu 安装slurm并配置
-
- [A. 联网机器(dry-legion):准备离线包](#A. 联网机器(dry-legion):准备离线包)
- [B. 服务器:建本地仓库并安装](#B. 服务器:建本地仓库并安装)
- [C. 主机名、munge、目录](#C. 主机名、munge、目录)
- [D. 读硬件并写配置](#D. 读硬件并写配置)
- [E. 记账数据库](#E. 记账数据库)
- [F. 按顺序启动](#F. 按顺序启动)
- [G. 账户、限额、强制记账](#G. 账户、限额、强制记账)
- [H. 验证](#H. 验证)
- [I. 作业脚本](#I. 作业脚本)
- [J. 可选项(没有它们前面也能用)](#J. 可选项(没有它们前面也能用))
- 常见问题
I put every step we ran into one script, slurm_offline.sh, with three sub-commands. I only checked the syntax and the help output in my sandbox; I haven't run prepare or install on a real machine. The first full run is the real test, so read the output as it goes.
开始前要按机器修改的值:
| 项目 | 本次的值 | 在哪里取 |
|---|---|---|
| CPUs / Sockets / Cores / Threads | 128 / 2 / 32 / 2 | slurmd -C |
| RealMemory | 489000(实测 515402 的约 95%) | slurmd -C |
| GPU 数量 | 2 | nvidia-smi -L |
| 集群名 / 账户名 | r750 / myaccount | 自定 |
HOST、CLUSTER、DBPASS 这三个变量要在同一个终端里使用,中途不要关掉终端。
A. 联网机器(dry-legion):准备离线包
bash
mkdir -p ~/slurm-debs && cd ~/slurm-debs
apt-get download $(apt-cache depends --recurse --no-recommends --no-suggests \
--no-conflicts --no-breaks --no-replaces --no-enhances \
slurm-wlm slurm-wlm-basic-plugins munge openssl mariadb-server slurmdbd \
| grep '^\w' | sort -u)
rm -f *_i386.deb # 删掉多架构混进来的 32 位包
ls *.deb | wc -l # 约 181
cd ~ && tar czf slurm-offline.tar.gz slurm-debs
把 slurm-offline.tar.gz 拷到服务器(scp 或 U 盘)。
B. 服务器:建本地仓库并安装
bash
cd ~ && tar xzf slurm-offline.tar.gz
# 仓库放在 /opt,因为 _apt 用户读不了家目录
sudo mkdir -p /opt/slurm-repo
sudo cp ~/slurm-debs/*.deb /opt/slurm-repo/
cd /opt/slurm-repo
sudo sh -c 'dpkg-scanpackages . /dev/null > Packages 2>/dev/null && gzip -9c Packages > Packages.gz'
sudo chmod -R a+rX /opt/slurm-repo
grep -c '^Package:' Packages # 约 181
echo "deb [trusted=yes] file:/opt/slurm-repo ./" > /tmp/local.list
APT_OPTS="-o Dir::Etc::sourcelist=/tmp/local.list -o Dir::Etc::sourceparts=- -o APT::Get::List-Cleanup=0"
sudo apt-get $APT_OPTS update
apt-cache $APT_OPTS policy slurm-wlm # Candidate: 19.05.5-1
# 不加 -y:看一眼要升级的包,有 libc6/dpkg/perl 等就先停下
sudo apt-get $APT_OPTS install slurm-wlm slurm-wlm-basic-plugins munge openssl mariadb-server slurmdbd
slurmd -V # slurm-wlm 19.05.5
C. 主机名、munge、目录
bash
getent hosts $(hostname -s) || echo "127.0.1.1 $(hostname -s)" | sudo tee -a /etc/hosts
sudo ls -l /etc/munge/munge.key # 要用 sudo,普通用户读不了这个目录
sudo systemctl enable --now munge
munge -n | unmunge | grep STATUS # Success
sudo mkdir -p /var/spool/slurmctld /var/spool/slurmd /var/log/slurm
sudo chown slurm:slurm /var/spool/slurmctld /var/spool/slurmd /var/log/slurm
D. 读硬件并写配置
bash
slurmd -C | head -n1
nvidia-smi -L
ls /dev/nvidia*
HOST=$(hostname -s) # 主机名有大写也不要手改
CLUSTER=r750
bash
sudo tee /etc/slurm-llnl/slurm.conf >/dev/null <<EOF
ClusterName=$CLUSTER
SlurmctldHost=$HOST
SlurmctldPort=6817
SlurmdPort=6818
SlurmUser=slurm
AuthType=auth/munge
MpiDefault=none
ReturnToService=2
SlurmctldPidFile=/run/slurmctld.pid
SlurmdPidFile=/run/slurmd.pid
SlurmdSpoolDir=/var/spool/slurmd
StateSaveLocation=/var/spool/slurmctld
SlurmctldLogFile=/var/log/slurm/slurmctld.log
SlurmdLogFile=/var/log/slurm/slurmd.log
ProctrackType=proctrack/cgroup
TaskPlugin=task/cgroup,task/affinity
SchedulerType=sched/backfill
SelectType=select/cons_tres
SelectTypeParameters=CR_Core_Memory
GresTypes=gpu
AccountingStorageType=accounting_storage/slurmdbd
AccountingStorageHost=localhost
AccountingStorageTRES=gres/gpu
JobAcctGatherType=jobacct_gather/linux
JobAcctGatherFrequency=30
NodeName=$HOST CPUs=128 Boards=1 SocketsPerBoard=2 CoresPerSocket=32 ThreadsPerCore=2 RealMemory=489000 Gres=gpu:2 State=UNKNOWN
PartitionName=main Nodes=$HOST Default=YES MaxTime=INFINITE State=UP
EOF
sudo tee /etc/slurm-llnl/gres.conf >/dev/null <<EOF
NodeName=$HOST Name=gpu File=/dev/nvidia0
NodeName=$HOST Name=gpu File=/dev/nvidia1
EOF
sudo tee /etc/slurm-llnl/cgroup.conf >/dev/null <<'EOF'
CgroupAutomount=yes
ConstrainCores=yes
ConstrainRAMSpace=yes
EOF
grep -n -E '^ClusterName|^SlurmctldHost|^GresTypes|^NodeName' /etc/slurm-llnl/slurm.conf
没有 GPU 的机器:去掉 GresTypes=gpu、AccountingStorageTRES=gres/gpu、NodeName 行里的 Gres=gpu:2,并且不要创建 gres.conf。
E. 记账数据库
bash
DBPASS=$(openssl rand -hex 16)
sudo systemctl enable --now mariadb
sudo tee /etc/mysql/mariadb.conf.d/99-slurm.cnf >/dev/null <<'EOF'
[mysqld]
innodb_buffer_pool_size=1024M
innodb_lock_wait_timeout=900
innodb_log_file_size=64M
EOF
sudo systemctl restart mariadb
sudo mysql -e "
CREATE DATABASE IF NOT EXISTS slurm_acct_db;
CREATE USER IF NOT EXISTS 'slurm'@'localhost' IDENTIFIED BY '$DBPASS';
ALTER USER 'slurm'@'localhost' IDENTIFIED BY '$DBPASS';
GRANT ALL ON slurm_acct_db.* TO 'slurm'@'localhost';
FLUSH PRIVILEGES;"
sudo tee /etc/slurm-llnl/slurmdbd.conf >/dev/null <<EOF
AuthType=auth/munge
DbdHost=localhost
SlurmUser=slurm
DebugLevel=info
LogFile=/var/log/slurm/slurmdbd.log
PidFile=/run/slurmdbd.pid
StorageType=accounting_storage/mysql
StorageHost=localhost
StorageUser=slurm
StoragePass=$DBPASS
StorageLoc=slurm_acct_db
EOF
sudo chown slurm:slurm /etc/slurm-llnl/slurmdbd.conf
sudo chmod 600 /etc/slurm-llnl/slurmdbd.conf # 权限不对 slurmdbd 不会启动
systemctl is-active mariadb # active
F. 按顺序启动
顺序不能换,先启动 slurmctld 会出现 no remote port 或 Database is busy。
bash
sudo systemctl stop slurmctld slurmd 2>/dev/null
sudo systemctl enable slurmdbd
sudo systemctl restart slurmdbd
sleep 5
sudo sacctmgr show cluster # 空表可以,报错不行
sudo sacctmgr -i add cluster $CLUSTER
sudo systemctl enable slurmctld slurmd
sudo systemctl restart slurmctld
sleep 3
sudo systemctl restart slurmd
sinfo # idle
scontrol show node $(hostname -s) | grep -E 'CPUTot|RealMemory|Gres|State'
G. 账户、限额、强制记账
bash
ACCT=myaccount
sudo sacctmgr -i add account $ACCT Description="local" Organization="local"
sudo sacctmgr -i add user $USER Account=$ACCT
sudo sacctmgr -i modify user $USER set DefaultAccount=$ACCT
# 可选限额:最多 4 个运行作业、64 个 CPU、同时 1 块 GPU
sudo sacctmgr -i modify user $USER set MaxJobs=4 GrpTRES=cpu=64,gres/gpu=1
sacctmgr show assoc format=cluster,account,user,maxjobs,grptres%30
# 账户建好之后再开强制,并且必须 restart(reconfigure 无效)
echo "AccountingStorageEnforce=associations,limits" | sudo tee -a /etc/slurm-llnl/slurm.conf
sudo systemctl restart slurmctld
scontrol show config | grep AccountingStorageEnforce # associations,limits
sleep 10 && sinfo # 刚重启时可能显示 unk,等几秒
其他用户:sudo sacctmgr -i add user <用户名> Account=$ACCT。没关联账户的用户提交作业会被拒绝。
改限额:
bash
sudo sacctmgr -i modify user $USER set GrpTRES=cpu=64,gres/gpu=2 # 允许两块 GPU
sudo sacctmgr -i modify user $USER set MaxJobs=-1 GrpTRES=cpu=-1 # 取消限制
H. 验证
bash
srun hostname
srun --cpus-per-task=2 nproc # 输出 2,说明 CPU 限制生效
srun --mem=1G --cpus-per-task=1 python3 -c "x = bytearray(3*1024**3); print('allocated')"
# 被 oom-kill,说明内存限制生效
srun --gres=gpu:1 nvidia-smi -L
for i in 1 2; do sbatch --gres=gpu:1 --wrap="sleep 60"; done
squeue -o "%.6i %.4t %.30R" # 一个 R,一个 PD (AssocGrpGRES)
scancel -u $USER
sacct --format=JobID,JobName,State,Elapsed,AllocTRES%40
这台服务器上,CPU 和内存限制已验证生效。GPU 隔离没有配置,只靠 CUDA_VISIBLE_DEVICES。
I. 作业脚本
bash
#!/bin/bash
#SBATCH --job-name=train_on_local
#SBATCH --nodes=1
#SBATCH --ntasks=1
#SBATCH --cpus-per-task=4
#SBATCH --mem=40G # 必须写,超出会被杀
#SBATCH --partition=main
#SBATCH --gres=gpu:1 # 19.05 不支持 --gpus=1
#SBATCH --time=0-00:05:00
#SBATCH --output=%x-%j.out
#SBATCH --account=myaccount
PY=/home/yin/miniconda3/envs/<env>/bin/python # conda env list 查路径
cd /path/to/project
export OMP_NUM_THREADS=$SLURM_CPUS_PER_TASK
srun -n1 $PY -u train.py
提交和查看:sbatch job.sh、squeue -u $USER、sacct -j <jobid> --format=JobID,State,Elapsed,MaxRSS,AllocTRES%40、scancel <jobid>。
J. 可选项(没有它们前面也能用)
漏写 --mem 时给默认值(不设的话没有内存限制):
bash
echo "DefMemPerCPU=3800" | sudo tee -a /etc/slurm-llnl/slurm.conf
sudo systemctl restart slurmctld
GPU 隔离(没测试过):让作业只能看到分给它的那块卡。
bash
echo "ConstrainDevices=yes" | sudo tee -a /etc/slurm-llnl/cgroup.conf
sudo tee /etc/slurm-llnl/cgroup_allowed_devices_file.conf >/dev/null <<'EOF'
/dev/null
/dev/urandom
/dev/zero
/dev/sda*
/dev/cpu/*/*
/dev/pts/*
/dev/nvidiactl
/dev/nvidia-uvm
/dev/nvidia-uvm-tools
/dev/nvidia-modeset
EOF
sudo systemctl restart slurmd
srun --gres=gpu:1 nvidia-smi -L # 只应列出 1 块
这个文件里不要 写 /dev/nvidia*。我之前的回复里写过,那样会放行所有 GPU,隔离就没有意义了。上面的版本只列出共用的控制设备。
常见问题
| 现象 | 处理 |
|---|---|
E: 无法定位软件包 |
本地仓库没读到:确认 /opt/slurm-repo 里有 Packages 和 Packages.gz,权限 a+rX |
Unable to resolve "..." |
slurm.conf 里的主机名和 hostname -s 不一致 |
Gres=(null) |
NodeName 那一行少了 Gres=gpu:N |
AccountingStorageEnforce = none |
slurmctld 没重启 |
sinfo 显示 unk、down 或 drain |
等几秒;不行就 sinfo -R,再 sudo scontrol update nodename=$(hostname -s) state=resume |
| 新作业分到一块显存已满的 GPU | 有 Slurm 之外的进程占着 GPU,Slurm 不知道;要求所有人都用 Slurm 提交,或暂时把那块卡从 gres.conf 里去掉 |