Debian 12 部署 Slurm 集群:高可用、GPU 与多租户实战
前言
当团队需要把分散的计算资源统一管理,无论是要管科研课题组的 GPU 服务器、跑生物信息的批量分析,还是给 AI 训练集群做算力调度,Slurm 都是常见选择。它在资源分配、公平调度和记账审计上已经过大规模验证。
Slurm 的文档很多,但从零搭一套生产可用的集群,还是要自己在官方手册、邮件列表和各种博客之间拼。这篇把单节点验证到多节点部署的过程串起来,重点补官方文档里讲得少的运维部分:cgroup v2 资源隔离的实际行为、slurmctld 主备切换怎么测试、节点健康检查脚本、多租户 QoS,以及学校场景里的 Lmod 和 LDAP/SSSD。
本文在以下环境做过实际验证:
- 操作系统:Debian 12 (Bookworm),内核 6.1.x,cgroup v2(unified hierarchy)
- Slurm 版本:Debian 官方仓库
22.05.8-4+deb12u3,安装命令见下文 - 2026-11 实测规模:2 台 controller(primary/backup)+ 2 台计算节点,NFS 共享
StateSaveLocation,多节点调度、cgroup、记账、QoS、主备切换、Lmod、LDAP/SSSD 登录、CephFS 共享目录、pam_slurm_adopt都实际跑过,结果见文末“实测环境与结果” - 文中 4 计算节点/32 节点属于扩展内容;GPU/GRES 用 PVE Intel GVT-g 实测,Slurm-web、Open OnDemand(Authentik OIDC)、Teleport(本地用户 + MFA)和 Prometheus/Grafana 告警链也都实际跑过。CephFS 一节用示例名
slurmfs,实际部署时把它换成你的文件系统名,cephx cap 也要跟着改
如使用 SchedMD 官方源安装 23.02+ 或 24.05+ 版本,部分参数名称可能有差异;25.05 起 select/cons_res 插件已移除,要改用 select/cons_tres。请对照对应版本的官方文档。
文章按部署、使用、多租户、运维、实测的顺序展开,篇幅较长;只看结果的读者可以直接跳到文末“实测环境与结果”。
Slurm 是什么?
- 一个开源的作业调度与资源管理系统,广泛应用于 HPC 集群。
- 核心组件:
- slurmctld:控制器守护进程(管理队列、分配资源)。
- slurmd:计算节点守护进程(执行任务)。
- slurmdbd:计费/审计数据库守护进程(可选但推荐)。
- munge:认证组件,所有节点共享同一 key。
- 常用命令:sinfo、squeue、sacct、srun、sbatch、scontrol、sacctmgr。
部署总览
架构与术语
- 控制节点(Head/Controller):运行 munge、slurmctld(可选 slurmdbd 与数据库)。
- 计算节点(Compute):运行 munge、slurmd。
- 分区(Partition):队列的逻辑集合,例如 debug、batch。
- 记账(Accounting):通过 slurmdbd + MariaDB/MySQL 收集作业、用户与项目统计。
选择部署形态
- 单节点最小示例(便于学习/开发机):仅 slurmctld + slurmd + munge,无数据库。
- 小型生产:控制节点运行 slurmctld + slurmdbd + MariaDB,计算节点仅 slurmd。
多节点集群架构
下图展示一个典型的多节点 Slurm 集群拓扑,用户通过 Login Node 提交作业,slurmctld 调度至计算节点执行,所有节点共享存储以保证路径一致:
graph TD
User["User SSH"] --> Login["Login Node<br/>Slurm Client + munged"]
Login -->|"sbatch / srun"| CTLD["slurmctld<br/>Controller"]
CTLD -->|"dispatch"| N1["node01 slurmd"]
CTLD -->|"dispatch"| N2["node02 slurmd"]
CTLD -->|"dispatch"| N3["node03 slurmd"]
CTLD -->|"dispatch"| N4["node04 slurmd"]
CTLD --- DBD["slurmdbd"]
DBD --- DB[("MariaDB")]
FS[("Shared Storage<br/>CephFS / NFS")] -.-> Login
FS -.-> N1
FS -.-> N2
FS -.-> N3
FS -.-> N4
关键设计要点:
- 控制节点承载 slurmctld、slurmdbd 和 MariaDB,是集群的调度中枢;生产环境中建议与计算节点物理分离,避免用户作业影响调度器稳定性。
- 登录节点只安装 Slurm 客户端工具和 munged,不运行 slurmd,不参与计算。
- 所有节点共享同一 Munge Key;时间偏差超过 300 秒将导致认证失败。
- 共享存储保证用户在 Login Node 上编写的脚本和数据在计算节点上路径一致。
角色与网络拓扑
把管理面、身份源、存储和计算节点放在一张图里,实际部署时通常会再拆管理网、存储网和计算网:
graph TB
subgraph Users["用户 / 学生"]
U["SSH / sbatch / srun"]
end
subgraph Login["登录节点"]
L["slurm-client + munge + SSSD"]
end
subgraph Control["控制 / 管理节点"]
C["slurmctld + slurmdbd + MariaDB"]
LDAP["OpenLDAP / AD"]
end
subgraph Compute["计算节点"]
N1["slurmd + cgroup v2 + Lmod"]
N2["slurmd + cgroup v2 + Lmod"]
end
subgraph Storage["共享存储"]
FS["CephFS / NFS / 并行文件系统"]
end
U --> L
L -->|"提交 / 查询"| C
C -->|"调度"| N1
C -->|"调度"| N2
L -.->|"LDAP/SSSD"| LDAP
N1 -.->|"LDAP/SSSD"| LDAP
N2 -.->|"LDAP/SSSD"| LDAP
L --- FS
N1 --- FS
N2 --- FS
这张图是逻辑拓扑:生产环境建议管理网(Slurm/Munge/LDAP)和存储网(CephFS/NFS)分开,计算网(MPI/RDMA)按需再加一张网卡;不要把存储流量和管理流量混在同一条 1Gb 链路上。
作业生命周期
一个典型的批处理作业从提交到完成的全过程:
sequenceDiagram
participant U as User
participant L as Login Node
participant C as slurmctld
participant D as slurmdbd
participant N as Compute Node
U->>L: sbatch job.sh
L->>C: Submit Request
C->>D: Log Submission
C->>C: Backfill Schedule
C->>N: Dispatch Job
N->>N: Execute Prolog
N->>N: Run User Job
N->>N: Execute Epilog
N->>C: Report Completion
C->>D: Log Completion
U->>L: sacct -j JOBID
L->>D: Query Accounting
D-->>U: Return Statistics
部署流程
整个部署过程按依赖顺序推进:
flowchart LR
A["OS Baseline<br/>NTP Kernel"] --> B["Munge<br/>Auth"]
B --> C["MariaDB<br/>Database"]
C --> D["slurmdbd<br/>Accounting"]
D --> E["slurm.conf<br/>Core Config"]
E --> F["cgroup.conf<br/>Isolation"]
F --> G["slurmctld<br/>Controller"]
G --> H["slurmd<br/>Compute"]
H --> I["Validation<br/>sinfo srun"]
在 Debian 上安装
适用版本:Debian 12 (Bookworm) 或更新版本。不同版本包名可能略有差异,建议先用 apt search 确认。
准备工作(所有节点)
- 主机名与 /etc/hosts 解析正确(控制节点与计算节点互相可解析)。
- 时间同步:建议安装 chrony 或启用 systemd-timesyncd,保证各节点时间一致。
- 防火墙端口(如使用):
- 6817/tcp:slurmctld
- 6818/tcp:slurmd
- 6819/tcp:slurmdbd(如启用)
配置时间同步(使用内网 NTP:192.0.2.10)
建议使用 Chrony;所有节点均需配置,指向你的内网时间同步服务器 192.0.2.10。
安装并配置:
sudo apt update
sudo apt install -y chrony
# 备份原配置
sudo cp /etc/chrony/chrony.conf /etc/chrony/chrony.conf.bak
# 仅使用内网 NTP 源(可按需保留/删除其他 pool/server 条目)
sudo sed -i 's/^pool .*/# &/' /etc/chrony/chrony.conf
echo -e "server 192.0.2.10 iburst" | sudo tee -a /etc/chrony/chrony.conf
# 开放本机查询(可选,根据安全策略调整)
grep -q '^allow ' /etc/chrony/chrony.conf || echo 'allow 10.0.0.0/8' | sudo tee -a /etc/chrony/chrony.conf
sudo systemctl enable --now chrony
sleep 2
chronyc sources -v
chronyc tracking
如果使用防火墙,确保 UDP/123 放行(节点到 192.0.2.10,必要时双向)。
操作系统基线与内核调优(所有节点)
HPC 场景对进程数、文件描述符、网络缓冲区等有较高要求。建议在所有节点统一配置以下参数:
# 系统级 limits(/etc/security/limits.d/99-hpc.conf)
cat | sudo tee /etc/security/limits.d/99-hpc.conf >/dev/null <<'EOF'
* soft nofile 1048576
* hard nofile 1048576
* soft nproc unlimited
* hard nproc unlimited
* soft memlock unlimited
* hard memlock unlimited
* soft stack unlimited
* hard stack unlimited
root soft nofile 1048576
root hard nofile 1048576
EOF
# 内核参数(/etc/sysctl.d/99-hpc.conf)
cat | sudo tee /etc/sysctl.d/99-hpc.conf >/dev/null <<'EOF'
# 网络缓冲区 - MPI 和大规模并行通信需要
net.core.rmem_max = 16777216
net.core.wmem_max = 16777216
net.core.rmem_default = 1048576
net.core.wmem_default = 1048576
net.ipv4.tcp_rmem = 4096 1048576 16777216
net.ipv4.tcp_wmem = 4096 1048576 16777216
# 连接追踪与 TIME_WAIT - 大量短连接场景
net.ipv4.tcp_tw_reuse = 1
net.ipv4.tcp_fin_timeout = 15
# 虚拟内存 - 避免计算节点 OOM 前过度 swap
vm.swappiness = 10
vm.overcommit_memory = 0
vm.dirty_ratio = 40
vm.dirty_background_ratio = 10
# PID 上限 - 大规模并行任务需要
kernel.pid_max = 4194304
# inotify - 部分科学软件和存储客户端需要
fs.inotify.max_user_watches = 524288
fs.inotify.max_user_instances = 8192
EOF
sudo sysctl --system
说明:
memlock unlimited对于 InfiniBand RDMA 和大页内存(HugePages)场景是必需的;如果不使用 IB 或 HugePages,可适当缩小。vm.swappiness = 10在计算节点上通常足够;若节点无 swap 分区则此参数无效。- 以上参数要按实际硬件(内存大小、网卡带宽、存储类型)压测后调整。
安装必需软件包
在控制节点(只跑 slurmctld/slurmdbd,不跑作业):
sudo apt update
sudo apt install -y slurmctld slurm-client slurmdbd mariadb-server \
munge libmunge2
# 如不做记账,可省略 slurmdbd/mariadb-server
如果控制节点也当计算节点(单节点示例),再补一个 slurmd:
sudo apt install -y slurmd
在计算节点:
sudo apt update
sudo apt install -y slurmd slurm-client munge libmunge2
注:实际包名以 apt search slurm 确认。slurm-wlm 是 meta 包,会把 slurmd、slurmctld、slurm-client 一起装上;按角色拆开装更干净。
控制节点误装 slurmd 时,它会因为 NodeName 里没有本机而报错,需要 systemctl disable --now slurmd。Debian 12 的 munge 包已经包含 munge、unmunge、remunge 和 mungekey,没有 munge-tools 这个包,也没有 create-munge-key。
配置 Munge(所有节点)
在控制节点创建 key,并分发到所有节点;保持权限正确。
sudo /usr/sbin/mungekey --create --force # Debian 12 的 munge 包提供的是 mungekey
sudo chown munge:munge /etc/munge/munge.key
sudo chmod 400 /etc/munge/munge.key
# 将 /etc/munge/munge.key 复制到每个计算节点同一路径,权限与属主一致
sudo systemctl enable --now munge
sudo systemctl status munge --no-pager
简单自检:
munge -n | unmunge
remunge
配置数据库与 slurmdbd(可选但推荐,用于记账)
在控制节点:
sudo systemctl enable --now mariadb
sudo mysql -e "CREATE DATABASE slurm_acct_db;"
sudo mysql -e "CREATE USER 'slurm'@'localhost' IDENTIFIED BY 'strong_password';"
sudo mysql -e "GRANT ALL ON slurm_acct_db.* TO 'slurm'@'localhost'; FLUSH PRIVILEGES;"
编辑 /etc/slurm/slurmdbd.conf(若不存在则新建,属主建议 slurm 或 root,权限 600):
AuthType=auth/munge
DbdHost=controller-node
DbdPort=6819
SlurmUser=slurm
LogFile=/var/log/slurm/slurmdbd.log
PidFile=/run/slurmdbd.pid
StorageType=accounting_storage/mysql
StorageHost=localhost
StoragePort=3306
StorageUser=slurm
StoragePass=strong_password
StorageLoc=slurm_acct_db
DbdHost 是 slurmdbd 实际监听的地址。单机可以写 localhost;如果登录节点或备控制器也要查询记账,DbdHost 和 slurm.conf 里的 AccountingStorageHost 都要写控制节点主机名或 VIP,并放行 6819/tcp。用主机名时确认它解析到管理网 IP,而不是 Debian 默认的 127.0.1.1,否则 slurmdbd 只会监听回环。
启动 slurmdbd(先建好日志目录,否则 slurmdbd 打不开 LogFile):
sudo mkdir -p /var/log/slurm
sudo chown slurm:slurm /var/log/slurm
sudo systemctl enable --now slurmdbd
sudo systemctl status slurmdbd --no-pager
生成与编辑 slurm.conf
建议先用官方工具生成一个基础模板后再改:
# 在任意机器上生成配置样板(会打开浏览器),或使用交互式命令行向导
# https://slurm.schedmd.com/configurator.html
最小单节点示例(放到所有节点的 /etc/slurm/slurm.conf,文件相同;权限 644):
ClusterName=debian-cluster
SlurmctldHost=controller-node # 控制节点主机名
SlurmUser=slurm
StateSaveLocation=/var/lib/slurm-llnl
SlurmdSpoolDir=/var/spool/slurmd
SlurmctldLogFile=/var/log/slurm/slurmctld.log
SlurmdLogFile=/var/log/slurm/slurmd.log
AuthType=auth/munge
ProctrackType=proctrack/cgroup
ReturnToService=2
SchedulerType=sched/backfill
SelectType=select/cons_res
SelectTypeParameters=CR_CPU_Memory
TaskPlugin=task/affinity,task/cgroup
# 推荐的优先级与计费策略(启用 QoS/Assoc 限额时常用)
PriorityType=priority/multifactor
PriorityWeightAge=1000
PriorityWeightFairshare=100000
PriorityWeightPartition=10000
PriorityWeightJobSize=0
AccountingStorageEnforce=associations,limits,qos
# Accounting(若启用 slurmdbd)
AccountingStorageType=accounting_storage/slurmdbd
AccountingStorageHost=controller-node
JobAcctGatherType=jobacct_gather/cgroup
# 节点与分区(按实际 CPU/Mem 修改)
NodeName=controller-node CPUs=8 RealMemory=32000 State=UNKNOWN
PartitionName=debug Nodes=ALL Default=YES MaxTime=INFINITE State=UP
多节点示例:
ClusterName=debian-cluster
SlurmctldHost=controller-node
SlurmUser=slurm
StateSaveLocation=/var/lib/slurm-llnl
SlurmdSpoolDir=/var/spool/slurmd
SlurmctldLogFile=/var/log/slurm/slurmctld.log
SlurmdLogFile=/var/log/slurm/slurmd.log
AuthType=auth/munge
ProctrackType=proctrack/cgroup
ReturnToService=2
SchedulerType=sched/backfill
SelectType=select/cons_res
SelectTypeParameters=CR_CPU_Memory
TaskPlugin=task/affinity,task/cgroup
PriorityType=priority/multifactor
PriorityWeightAge=1000
PriorityWeightFairshare=100000
PriorityWeightPartition=10000
PriorityWeightJobSize=0
AccountingStorageEnforce=associations,limits,qos
AccountingStorageType=accounting_storage/slurmdbd
AccountingStorageHost=controller-node
JobAcctGatherType=jobacct_gather/cgroup
NodeName=node[01-04] CPUs=16 RealMemory=64000 State=UNKNOWN
PartitionName=batch Nodes=node[01-04] Default=YES MaxTime=7-00:00:00 State=UP
创建需要的目录并设置权限(所有节点):
sudo mkdir -p /var/lib/slurm-llnl /var/spool/slurmd /var/log/slurm
sudo chown -R slurm:slurm /var/lib/slurm-llnl /var/spool/slurmd /var/log/slurm
初始化集群对象(sacctmgr 会读 /etc/slurm/slurm.conf,所以放在配置生成之后;slurmdbd 已经启动):
sudo sacctmgr add cluster debian-cluster
登录/提交节点与计算节点分离
目标:提供一个供学生/科研用户 SSH 登录、编写脚本并提交作业的“登录/提交节点(login node)”,作业实际在计算节点运行,避免在登录节点上消耗大量资源。
2026-11 用一台独立 Debian 12 VM(
slurm-build,10.31.0.229,2 vCPU / 4 GB)做了登录节点验证。它和控制器、计算节点分开,只装客户端和 munge,没有slurmd;实测结果见下面的“独立登录节点实测”。
登录/提交节点需要什么?
- 与集群一致的 munge key(/etc/munge/munge.key)。
- Slurm 客户端工具即可(不需要 slurmd):
sudo apt update
# Debian 12 有独立的 slurm-client 包,不需要装 slurmd/slurmctld
sudo apt install -y slurm-client munge libmunge2
# 复制控制节点上的 /etc/slurm/slurm.conf 到登录节点(保持完全一致)
# 确保 SlurmctldHost 指向控制节点,NodeName 与 Partition 仅包含计算节点
# 登录节点上不运行 slurmd,避免执行作业
sudo systemctl disable --now slurmd 2>/dev/null || true
sudo systemctl enable --now munge
注意:这里的 slurm-client 是 Debian 12 仓库里的 22.05。本次集群已经升到 23.11.4,登录节点实际用的是同一版本编译的 /opt/slurm-23.11/bin;客户端和控制器不是同一协议版本时不要混用。生产上客户端和控制器版本要保持一致。
登录节点的主机名不要出现在 slurm.conf 的 NodeName 列表中;只定义计算节点。例如:
NodeName=node[01-04] CPUs=16 RealMemory=64000 State=UNKNOWN
PartitionName=batch Nodes=node[01-04] Default=YES MaxTime=7-00:00:00 State=UP
登录节点上的 AccountingStorageHost 要指向 slurmdbd 所在的控制节点(或 VIP),不能照抄控制节点的 localhost,否则 sacct 会连不上数据库。
独立登录节点实测
测试机 slurm-build(10.31.0.229,2 vCPU / 4 GB)只作为登录/提交节点,同时兼作后面的 OOD 主机;它没有运行 slurmd,也没有出现在 slurm.conf 的 NodeName 里。
配置步骤:
- 复制
/etc/slurm/slurm.conf和控制节点的/etc/munge/munge.key,启动 munge。 - 登录节点上要有与控制器相同 UID 的
slurm系统用户(本次是 64030)。没有这个用户时,客户端解析配置会报Invalid user for SlurmUser slurm并直接退出;它不需要 shell,也不需要家目录。 - 在
/etc/hosts里补上控制节点、备控和计算节点的主机名,因为SlurmctldHost写的是短主机名。 - 统一用户 UID:登录节点和计算节点都建了
stu01(20002:20000),否则作业跨节点时会因为 uid 不一致找不到家目录或输出文件。
第一次测试时 munge 已由 apt 安装后自动启动,覆盖 munge.key 再执行 systemctl enable --now munge 不会重新加载密钥。控制器日志报 Munge decode failed,scontrol ping 显示两个控制器都 DOWN;执行 systemctl restart munge 后恢复。换 key 或同步 key 后这个细节很容易漏。
实测命令和输出(以 stu01 身份):
$ sinfo
PARTITION AVAIL TIMELIMIT NODES STATE NODELIST
debug* up infinite 2 idle slurm-node[1-2]
classA up 4:00:00 1 idle node-gpu
$ srun -A classa -n1 hostname
slurm-node1
$ sbatch -A classa --chdir=/tmp --wrap 'hostname'
Submitted batch job 74
$ sacct -j 74 --format=JobID,State,NodeList
JobID State NodeList
-------- ------------ -----------
74 COMPLETED slurm-node1
sbatch 继承的是提交时的当前目录,不是 $HOME。第一次在 /home/user 下提交时作业失败:
[73.batch] error: Could not open stdout file /home/user/slurm-73.out: Permission denied
改成 cd ~ 或加 --chdir=/tmp 后正常。登录节点和计算节点本次没有挂共享 /home,所以输出放在 /tmp;生产上按下一节挂 NFS/CephFS,否则用户脚本、输出和家目录在节点间不可见。
推荐:共享家目录与数据路径
为方便用户在登录节点编写脚本并在计算节点运行,建议共享 /home 与项目目录(NFS/SMB/分布式存储均可)。示例(仅供参考,按你现有存储实现):
# 服务器上 /etc/exports(示意)
/home 10.0.0.0/8(rw,sync,no_root_squash)
# 客户端(登录/计算节点)/etc/fstab(示意)
nfs-server:/home /home nfs defaults,_netdev 0 0
no_root_squash让计算节点的 root 在 NFS 上保留 root 权限,只在完全信任计算节点时使用。若保留root_squash,Prolog 里以 root 执行chown会失败,需要改由用户自己创建目录或用其它机制。
使用 Ceph 存储(无需单独 NFS 服务器)
Ceph 集群本身的部署步骤见 cephadm 部署 Ceph 集群;下面只讲 Slurm 节点如何挂载 CephFS。
你的后端是 Ceph,推荐直接挂载 CephFS(无需额外起一台 NFS VM、减少一层协议)。
请务必做到:登录/提交节点与所有计算节点用“相同的挂载路径”(例如统一都用 /home、/projects),以保证作业在任意节点看到的路径一致。
方式 A:直接挂载 CephFS(kernel cephfs)
- 在登录/提交节点与所有计算节点安装客户端工具:
sudo apt install -y ceph-common
- 在 Ceph 集群上为 HPC 场景创建一个只需最小权限的 cephx 账号(示例:client.hpc),并限制到需要的路径:
可在 Ceph 管理节点执行(按需调整 FS 名称、路径与 pool):
# 创建/获取密钥(示例,实际请根据 Ceph 版本与安全策略调整)
ceph auth get-or-create client.hpc \
mon 'allow r' \
mds 'allow r, allow rw path=/home, allow rw path=/projects' \
osd 'allow rw tag cephfs data=slurmfs' \
> /etc/ceph/ceph.client.hpc.keyring
将生成的 keyring 安全分发到所有登录/提交节点与计算节点:/etc/ceph/ceph.client.hpc.keyring(权限 600)。内核 CephFS 的 secretfile 要的是 key 本身,不是 keyring 文件,额外导出一份:
ceph auth get-key client.hpc | sudo tee /etc/ceph/ceph.client.hpc.secret
sudo chmod 600 /etc/ceph/ceph.client.hpc.secret
如节点上没有 ceph.conf,也可在 fstab 里直接写监视器 IP 列表。
实测:
osd的tag cephfs data=要写 CephFS 名称(本文示例为slurmfs),不是数据池名。写错时touch可能成功,但写数据会报Operation not permitted。另外secretfile需要节点安装ceph-common(提供mount.ceph),否则内核会把secretfile当成未知参数。
- 在所有节点写入 /etc/fstab(示例,使用监视器 IP 列表与 FS 名称 cephfs,挂载到统一的 /cephfs,然后通过 bind-mount 暴露 /home、/projects):
# 直接挂载 CephFS 根到 /cephfs(将 10.1.1.[1-3] 替换为你的 MON 地址;fs=slurmfs 换成你的 CephFS 名称)
10.1.1.1,10.1.1.2,10.1.1.3:/ /cephfs ceph name=hpc,secretfile=/etc/ceph/ceph.client.hpc.secret,fs=slurmfs,_netdev,noatime 0 2
# 将 CephFS 子目录绑定到标准路径,保证路径一致
/cephfs/home /home none bind 0 0
/cephfs/projects /projects none bind 0 0
也可以直接把 CephFS 挂到 /home(需确保 CephFS 上已有 /home 目录):
10.1.1.1,10.1.1.2,10.1.1.3:/ /home ceph name=hpc,secretfile=/etc/ceph/ceph.client.hpc.secret,fs=slurmfs,_netdev,noatime,ms_mode=secure 0 2
挂载生效:
sudo systemctl daemon-reload || true
sudo mkdir -p /cephfs /home /projects
sudo mount -a
注意事项:
- 路径统一:所有节点使用一致的挂载点(/home、/projects 等)。
- 账号统一:配合前文的 SSSD/LDAP/SSO,保证 UID/GID 在所有节点一致,否则权限会错乱。
- 网络与时间:存储流量建议走独立网络;Chrony 已配置对齐时间,避免分布式文件系统报错。
- 高可用:CephFS 客户端可连接多个 MON,建议写多个 MON 地址;生产可结合多网卡与负载隔离。
登录/提交节点资源自我保护(可选)
- PAM limits:限制每用户进程数/内存,防止误占。
sudo tee /etc/security/limits.d/login-node.conf >/dev/null <<'LIM'
* soft nproc 4096
* hard nproc 8192
* soft memlock 64
* hard memlock 64
LIM
- 如需更强约束,可用 systemd resource control(例如将用户会话置于特定 slice)。
从登录节点提交与验证
在登录节点执行以下命令,确认调度发生在计算节点:
# 查看分区/节点
sinfo
# 交互分配一个 shell(应被分配到 node01/02 等计算节点)
srun -n1 --mem=1G --pty bash -l -c 'hostname; sleep 1'
# 提交批作业
sbatch --wrap 'echo run on $(hostname); sleep 2'
squeue -u $USER
若发现作业在登录节点执行,检查:
- 登录节点是否误启动了 slurmd(应停用)。
- slurm.conf 的 NodeName/Partition 是否包含了登录节点(应移除)。
cgroup.conf(推荐,cgroup v2)
Debian 12 默认使用 cgroup v2(unified hierarchy)。Slurm 22.05+ 原生支持 cgroup v2,无需额外设置兼容模式。
确认当前系统使用的 cgroup 版本:
stat -fc %T /sys/fs/cgroup
# 输出 cgroup2fs 表示 cgroup v2;tmpfs 表示 cgroup v1
/etc/slurm/cgroup.conf:
CgroupMountpoint=/sys/fs/cgroup
# CPU 核绑定 - 防止作业间 CPU 争抢
ConstrainCores=yes
# 内存限制 - 超出分配值的进程将被 OOM Kill
ConstrainRAMSpace=yes
# 设备隔离 - 配合 GRES 限制 GPU 等设备访问
ConstrainDevices=yes
# Swap 控制 - 把作业 cgroup 的 swap 限额压到 0
ConstrainSwapSpace=yes
AllowedSwapSpace=0
说明:
ConstrainCores=yes通过 cgroup 的 cpuset 控制器将作业绑定到分配的 CPU 核上。对科学计算和 MPI 应用,核绑定可避免 NUMA 跨节点访问带来的性能损失。ConstrainRAMSpace=yes启用内存硬限制。分配的--mem值将严格通过 cgroup memory controller 执行,超出的进程被 Kill。这是生产环境中防止单个作业耗尽节点内存的关键保护。ConstrainSwapSpace=yes配合AllowedSwapSpace=0把作业 cgroup 的 swap 限额压到 0;它不阻止内核换出其它进程,必要时再配合MemorySwappiness。- 如需在 cgroup v2 下使用内存压力统计(memory.pressure),需确保内核启用 PSI(Pressure Stall Information),Debian 12 默认已开启。
本文测试的 22.05 + cgroup v2 环境验证了 CPU 和内存限制;
ConstrainDevices、ConstrainSwapSpace在 cgroup v2 下的行为会随 Slurm 版本和内核变化,GPU 设备隔离要在有 GPU 的节点上单独验证。
gres.conf(可选,GPU/特殊设备)
/etc/slurm/gres.conf(仅设备节点上):
NodeName=node01 Name=gpu File=/dev/nvidia0
NodeName=node01 Name=gpu File=/dev/nvidia1
slurm.conf 中对应添加:
GresTypes=gpu
NodeName=node01 Gres=gpu:2 CPUs=32 RealMemory=128000 State=UNKNOWN
启动服务
控制节点:
sudo systemctl enable --now munge
sudo systemctl enable --now slurmctld
# 如启用记账: slurmdbd 已在上文启动
计算节点:
sudo systemctl enable --now munge
sudo systemctl enable --now slurmd
变更配置后:
sudo scontrol reconfigure # 控制节点执行,使变更生效
scontrol reconfigure只重读一部分参数。实测AccountingStorageEnforce、HealthCheckProgram/HealthCheckInterval、SlurmctldHost这类改动需要重启slurmctld(必要时重启slurmd)才生效。
高可用架构(生产环境)
单控制器在 slurmctld 宕机时会导致整个集群无法调度新作业(已运行的作业不受影响)。生产环境建议部署主备 slurmctld 实现自动故障转移。
架构概览
graph TD
subgraph HA["slurmctld HA Pair"]
Primary["controller-01<br/>slurmctld Primary"]
Backup["controller-02<br/>slurmctld Backup"]
end
SharedFS[("StateSaveLocation<br/>Shared Filesystem")]
Primary --- SharedFS
Backup --- SharedFS
Primary -->|"Active"| Nodes["Compute Nodes"]
Backup -.->|"Standby Failover"| Nodes
DBD["slurmdbd"] --- Primary
DBD -.-> Backup
配置要点
在 slurm.conf 中定义两个 SlurmctldHost,第一个为主,第二个为备:
SlurmctldHost=controller-01(192.0.2.10)
SlurmctldHost=controller-02(192.0.2.11)
关键要求:
- 共享 StateSaveLocation:主备节点必须能访问同一个
StateSaveLocation路径(通常为 NFS 或 CephFS 挂载点)。当主节点故障时,备节点通过该路径恢复调度器状态。 - 相同配置文件:所有节点(包含主备控制器、计算节点、登录节点)的
slurm.conf内容完全一致。 - Munge Key 一致:主备控制器与所有节点共享同一 Munge Key。
- 两台控制器均运行 slurmctld:备节点的 slurmctld 启动后自动进入 standby 状态,不会产生调度冲突。
- 故障检测超时:默认
SlurmctldTimeout=120秒。实测从停掉主节点到备节点接管约 2 分 46 秒;调小前先确认共享存储和心跳稳定,避免误切换。 - slurmdbd 地址:主备控制器的
AccountingStorageHost要指向同一个 slurmdbd 地址(或 VIP),不要两台都写localhost,否则备节点接管后记账会失败。slurmdbd.conf里的DbdHost也要写其它节点能访问到的地址,只写localhost时 6819 端口只在回环上可达。
# 在主备两台控制器上都启用 slurmctld
sudo systemctl enable --now slurmctld
# 查看配置里的主备地址是否可达
scontrol ping
# 输出示例:
# Slurmctld(primary) at controller-01 is UP
# Slurmctld(backup) at controller-02 is UP
scontrol ping显示的是SlurmctldHost配置里的主/备角色和可达性,不是当前 active 角色。备节点接管后,它仍然会按配置显示为backup,不要用这行输出判断谁在干活。
故障转移测试
# 在主节点模拟故障
sudo systemctl stop slurmctld # controller-01
# 默认 SlurmctldTimeout=120 秒,备节点要等主节点超时后才接管。
# 实测从 stop 到备节点日志出现 "Running as primary" 约 2 分 46 秒。
# 可以调小 SlurmctldTimeout,但不要小于心跳和共享存储恢复所需时间。
sleep 180
# 看日志确认备节点是否接管(比 scontrol ping 可靠)
sudo journalctl -u slurmctld -n 30 --no-pager | grep -E 'Running as primary|standby'
# 提交测试作业确认调度正常
srun -n1 hostname
# 恢复原主节点
sudo systemctl start slurmctld # controller-01
# 实测 controller-01 重启后会重新成为 primary,controller-02 退回 standby;
# 如果希望备节点保持 primary,需要在恢复前手动接管或调整启动顺序。
slurmdbd 与数据库高可用(Galera 实测)
slurmctld 主备测过之后,数据库层也搭了一套:三个 MariaDB 10.11 + Galera 4 实例,HAProxy 做入口,slurmdbd 主备各连同一个集群。
三个实例都跑在
slurm-auth(10.31.0.243)上,端口 3307/3308/3309。这是为了在现有资源里验证 Galera 和slurmdbd故障转移;生产应把三个实例分散到三台机器,并给 HAProxy 配 keepalived/VIP。
每个实例的 my.cnf 关键项(以 3307 为例):
[mysqld]
port=3307
bind-address=127.0.0.1
wsrep_on=ON
wsrep_provider=/usr/lib/galera/libgalera_smm.so
wsrep_cluster_name=slurm_galera
wsrep_cluster_address=gcomm://127.0.0.1:4567,127.0.0.1:4577,127.0.0.1:4587
wsrep_node_name=galera1
wsrep_node_address=127.0.0.1:4567
wsrep_provider_options="gmcast.listen_addr=tcp://127.0.0.1:4567;ist.recv_addr=127.0.0.1:4568"
wsrep_sst_method=rsync
wsrep_sst_receive_address=127.0.0.1:4444
binlog_format=ROW
innodb_autoinc_lock_mode=2
另外两个实例把端口改成 3308/3309,wsrep_node_address、ist.recv_addr 和 wsrep_sst_receive_address 也要成对改开。这里踩过一次坑:ist.recv_addr 和 wsrep_sst_receive_address 用了同一个端口,第二个节点启动时报 Failed to open IST listener ... Address already in use,SST 失败;把 SST 端口单独分出来后恢复正常。
HAProxy 只做 TCP 转发:
frontend galera
bind 0.0.0.0:3306
default_backend galera_nodes
backend galera_nodes
option tcp-check
server galera1 127.0.0.1:3307 check inter 2s fall 2 rise 2
server galera2 127.0.0.1:3308 check inter 2s fall 2 rise 2
server galera3 127.0.0.1:3309 check inter 2s fall 2 rise 2
把原来的 slurm_acct_db 导出后导入 Galera,slurmdbd 改成连 HAProxy:
# /etc/slurm/slurmdbd.conf
DbdHost=controller-01
DbdBackupHost=controller-02
StorageHost=10.31.0.243
StoragePort=3306
StorageUser=slurm
StorageLoc=slurm_acct_db
slurm.conf 里同时指定主备 DBD:
AccountingStorageHost=controller-01
AccountingStorageBackupHost=controller-02
实测结果:
- 三个实例的
wsrep_cluster_size都是 3,wsrep_local_state_comment=Synced;导入后slurm_acct_db里的slurm-lab_job_table有 75 条记录,sacct能查到升级前后的历史作业。 systemctl stop galera@1后集群剩 2 个节点,HAProxy 把连接切到 3308/3309;此时提交作业 76,sacct正常记账。systemctl start galera@1后它通过 SST 重新加入,集群回到 3 个节点。- 主
slurmdbd停掉后,slurmctld按AccountingStorageBackupHost连到 controller-02 上的备份slurmdbd;提交作业 77,sacct -j 77仍能查到记录。主slurmdbd重新启动后恢复。 - 备份
slurmdbd的DbdHost必须写它自己的主机名,不能写 IP:写DbdHost=10.31.0.228时启动直接报This host not configured to run SlurmDBD。主机名解析到 IPv6 时再加DbdAddr=10.31.0.228,用 IPv4 建立连接。 - 备份节点要装
libmariadb3,并确保/run/slurmdbd.pid对slurm用户可写;本次一开始备份slurmdbd就因为这个 pidfile 权限和缺库起不来。 - MariaDB 会提示
Database settings not recommended values: innodb_buffer_pool_size innodb_lock_wait_timeout。实验环境没调,生产要按 DBD 的并发量设置,否则slurmdbd重启或积压时容易等锁。
slurmdbd 短暂不可用时,slurmctld 会在本地缓存记账消息,恢复后回放;缓存有上限,长时间失联仍可能丢记录。Galera 解决的是数据库节点故障,不替代对 slurmdbd 进程和队列的监控。不用 Galera 的话,也可以参考 MySQL 双主部署 的做法;本文选 Galera 是因为多主写入和成员自动管理更直接。
单节点最小验证
如果启用了 AccountingStorageEnforce=associations(本文配置启用了),先创建默认账户并关联当前用户,否则 srun 会报 Invalid account or account/partition combination specified:
sudo sacctmgr -i add account users Description="Default account" Organization=local
sudo sacctmgr -i add user "$USER" Account=users
sinfo
scontrol ping
srun -N1 -n1 hostname
cat > sleep.sh <<'EOF'
#!/usr/bin/env bash
#SBATCH -J test
#SBATCH -p debug
#SBATCH -n 1
#SBATCH -o out.%j
echo "hello from $(hostname)"
sleep 5
EOF
sbatch sleep.sh
squeue -u $USER
部署完成后的使用验证
以下示例帮助你在完成安装后进一步验证调度、资源、QoS 与记账是否工作正常。
1. 交互作业(srun)
# 申请 1 个任务、1 个 CPU、内存 1G,打开交互式 shell(默认分区/默认 QoS)
srun -n1 -c1 --mem=1G --pty bash -l
hostname && echo "CPU: $(nproc)" && exit
预期:进入一个 shell,hostname 输出为分配到的节点;退出后资源释放。
2. 批处理作业(sbatch)
cat > job_simple.sh <<'EOF'
#!/usr/bin/env bash
#SBATCH -J hello
#SBATCH -o hello.%j.out
echo "Hello from $(hostname)"
sleep 3
EOF
sbatch job_simple.sh
squeue -u $USER
预期:作业完成后生成 hello..out,包含 hostname 输出。
3. 多节点/多任务 MPI 示例(无 MPI 也可当并行任务验证)
cat > job_multinode.sh <<'EOF'
#!/usr/bin/env bash
#SBATCH -J multi
#SBATCH -N 2 # 2 台节点
#SBATCH -n 4 # 4 个任务
#SBATCH -o multi.%j.out
srun -N2 -n4 bash -lc 'echo HOST=$(hostname) TASK=$SLURM_PROCID'
EOF
sbatch job_multinode.sh
预期:输出中能看到 4 行,不同任务的 HOST 可能分布在 2 台节点。
如使用 MPI(OpenMPI/MPICH),通常直接 srun <mpi-program>,由 Slurm 的 PMI/PMIx 启动任务;要用 mpirun 时,先确认 MPI 编译时带 Slurm 支持,避免两层启动器打架。
4. 资源约束与拒绝验证(内存/CPU)
# 申请超过节点内存尝试(应被拒绝或 Pending)
sbatch --mem=1000G -n1 -J too-much-mem --wrap 'sleep 1'
# 申请指定 CPU 核数与绑定
sbatch -n1 -c4 -J cpu4 --wrap 'echo CPU=$(nproc); lscpu | grep -E "^CPU\(s\)|Thread|Core"'
预期:第一条应排队 Pending 或被拒;第二条在 out 文件中看到绑定情况。
5. QoS/分区限制验证
# 使用 short QoS,限制墙时 4 小时(根据你的配置)
sbatch -J qos-short --qos=short --time=01:00:00 --wrap 'sleep 10'
# 若分区限制 MaxTime=04:00:00,提交超过限制应被拒
sbatch -p debug --time=10:00:00 --wrap 'sleep 10'
预期:超过分区 MaxTime 的作业通常在提交时被拒绝。
QoS 的 MaxWall、MaxTRESPU、MaxJobsPerUser 超限一般不是提交被拒,而是作业进入 PENDING,Reason 显示 QOSMaxWallDurationPerJobLimit、QOSMaxCpuPerUserLimit、QOSMaxJobsPerUserLimit 等。用 scontrol show job <jobid> 或 sacct -j <jobid> --format=JobID,State,Reason 查看。
6. GPU/GRES 验证(Intel GVT-g 实测)
如果节点是 NVIDIA,gres.conf 通常写 File=/dev/nvidia0;这次的测试环境只有 Intel iGPU,用 PVE 的 GVT-g 给计算节点挂了一个 vGPU。
手边没有 NVIDIA GPU,本文没有实测
/dev/nvidia*、NVIDIA 驱动、DCGM 和nvidia-smi路径;下面的实测只覆盖 Intel GVT-g。NVIDIA 的写法来自 Slurm 文档,保留作参考,不作为本文的验证结果。
如果要在 PVE 上做 NVIDIA 直通,可参考 PVE GPU 透传实战;这条路径和 GVT-g 不同。
PVE 宿主机(i3-6100 + HD 530)需要在内核命令行打开 GVT-g:
i915.enable_gvt=1 i915.enable_guc=0
确认 mdev 类型和可用实例:
ls /sys/bus/pci/devices/0000:00:02.0/mdev_supported_types/
cat /sys/bus/pci/devices/0000:00:02.0/mdev_supported_types/i915-GVTg_V5_4/available_instances
给 VM 挂 mdev(PVE 9.2):
qm set <vmid> -hostpci0 0000:00:02.0,mdev=i915-GVTg_V5_4
guest 侧要注意 Debian cloud 镜像默认的 cloud-amd64 内核不带 i915,lspci 能看到 HD 530,但 /dev/dri 不出现。装 linux-image-amd64 并用 generic 内核启动后:
sudo apt install -y linux-image-amd64 intel-opencl-icd clinfo clpeak
lspci -nnk -s 00:10.0 # 8086:1912, Kernel driver in use: i915
ls -l /dev/dri # card1 + renderD128
renderD128 是 root:render 0660,跑 GPU 作业的用户要在 render 组里:
sudo usermod -aG render <user>
组信息要在控制节点和计算节点一致,改完重启 slurmd,否则作业里的 clinfo 会因为拿不到 render 组而看不到设备。
Slurm 侧:
# slurm.conf
GresTypes=gpu
NodeName=node-gpu CPUs=2 RealMemory=1800 Gres=gpu:1 State=UNKNOWN
AccountingStorageTRES=gres/gpu
# /etc/slurm/gres.conf(只放 GPU 节点)
NodeName=node-gpu Name=gpu File=/dev/dri/renderD128
重启 slurmctld 和 slurmd 后,sinfo -o "%N %G" 应显示 gpu:1。提交:
srun -w node-gpu --gres=gpu:1 -n1 bash -lc \
'echo $SLURM_GPUS_ON_NODE; clinfo -l; clpeak --compute-sp'
实测 SLURM_GPUS_ON_NODE=1,sacct 的 AllocTRES 里有 gres/gpu=1。cgroup.conf 开着 ConstrainDevices=yes 时,不带 --gres 的作业虽然还能 ls /dev/dri,但 clinfo 返回 0 个 platform;带 --gres 的作业才能拿到 OpenCL 设备。
VA-API 在 GVT-g 下没跑通:iHD 和 i965 都在初始化时报 DRM_IOCTL_I915_GEM_APERTURE failed / get chip id failed,所以这里用 OpenCL 测,不把 VA-API 当成已验证能力。glmark2-drm 也没法在无 X 的 guest 里选到 card1,最后用的是 clpeak。
基准数据和混合负载见“实测环境与结果”。
7. 记账(Accounting)验证
# 查看最近作业的账户/用量
sacct -u $USER --starttime today --format=JobID,JobName,Account,User,Partition,AllocTRES,Elapsed,State
# 管理视角(root 或有权限):
sacctmgr show assoc format=Cluster,Account,User,Partition,FairShare
sacctmgr show qos format=Name,Priority,MaxWall,MaxJobsPU,MaxTRESPU
预期:记录能正常写入,关联、QoS 策略生效。
8. 节点/分区状态与调度健康
sinfo -R # 查看调度器理由(Reason)
scontrol show nodes # 节点详细状态
scontrol show partition # 分区配置
若有异常,结合 /var/log/slurm/slurmctld.log 与各节点的 slurmd.log 排查;必要时 scontrol reconfigure 使配置重新加载。
接入单点登录(SSO)
目标:用户通过 SSO 认证后,能直接 SSH 登录到共享的登录节点(login node),然后在该节点上使用 srun/sbatch 提交作业。
这里有两种做法:
- Authentik LDAP Outpost + SSSD(推荐简洁、原生 Linux 体验)
- Teleport + Authentik OIDC/SAML(带审计、短期证书、零信任风格;OIDC/SAML 需要 Teleport Enterprise)
选择哪种取决于你是否偏好基于 LDAP/SSH 公钥的传统 Linux 账户,还是希望要更强的会话审计与自动到期证书。
Authentik 这条路径已实际部署 2024.12.3,并用它的 LDAP Outpost 完成 SSSD 认证、Slurm-web 登录和 OOD 的 OIDC 登录。Teleport 18.10 社区版也部署了,本地用户 + MFA + Web 终端可用;但 OIDC connector 在社区版返回 Enterprise-only,详见下文。
用 Authentik LDAP Outpost 接入
前提:在 Authentik 中配置好 LDAP Outpost(提供 LDAP 目录和可选 SSH 公钥属性),向内网暴露 LDAP(s)。
在登录节点(Debian)安装并配置 SSSD:
sudo apt update
sudo apt install -y sssd sssd-ldap libnss-sss libpam-sss
sudo cp /etc/sssd/sssd.conf /etc/sssd/sssd.conf.bak 2>/dev/null || true
cat | sudo tee /etc/sssd/sssd.conf >/dev/null <<'SSSD'
[sssd]
services = nss, pam, ssh
config_file_version = 2
domains = authentik
[domain/authentik]
id_provider = ldap
auth_provider = ldap
chpass_provider = ldap
ldap_uri = ldaps://authentik-ldap.internal:636
ldap_search_base = dc=example,dc=internal
ldap_default_bind_dn = uid=binduser,ou=system,dc=example,dc=internal
ldap_default_authtok = BIND_USER_PASSWORD
ldap_tls_reqcert = demand
cache_credentials = True
enumerate = False
ldap_user_ssh_public_key = sshPublicKey
access_provider = ldap
ldap_access_filter = (memberOf=cn=slurm-users,ou=groups,dc=example,dc=internal)
SSSD
sudo chmod 600 /etc/sssd/sssd.conf
sudo systemctl enable --now sssd
启用 NSS/PAM 集成,让系统识别 LDAP 用户并允许登录:
# Debian 用 pam-auth-update 管理 PAM;不要覆盖 common-session
sudo pam-auth-update --enable mkhomedir
sudo sed -i 's/^#\?\s*UsePAM.*/UsePAM yes/' /etc/ssh/sshd_config
sudo sed -i 's/^#\?\s*PasswordAuthentication.*/PasswordAuthentication yes/' /etc/ssh/sshd_config
sudo sed -i 's/^#\?\s*PubkeyAuthentication.*/PubkeyAuthentication yes/' /etc/ssh/sshd_config
sudo systemctl reload ssh || sudo systemctl restart ssh
上面的
PasswordAuthentication yes只在确实需要 password 登录时打开;如果使用 SSH 公钥或 Teleport,保持no更安全。
可选:只允许某个组登录(与上文 ldap_access_filter 保持一致),例如:
echo 'AllowGroups slurm-users' | sudo tee -a /etc/ssh/sshd_config
sudo systemctl reload ssh
要点:
- 将 sssd.conf 中的 ldap_uri、bind DN、BaseDN、证书与组名替换成你 Authentik 的实际配置;若使用自签 CA,安装 CA 到
/usr/local/share/ca-certificates/并update-ca-certificates。 - 若使用公钥登录,可让 LDAP 暴露
sshPublicKey属性。SSSD 只提供sss_ssh_authorizedkeys查询接口,不会自动写authorized_keys;sshd 还要配置AuthorizedKeysCommand /usr/bin/sss_ssh_authorizedkeys和AuthorizedKeysCommandUser nobody。 - 建议把登录节点限制为只跑轻量任务,在 slurm 中配置为提交入口,不计入计算资源。
Authentik LDAP Outpost 实测
2026-11 在 10.31.0.243 上部署 Authentik 2024.12.3(Docker 静态包,PostgreSQL/Redis 用 Debian 原生包),bootstrap 管理员账号 akadmin,创建学生用户 stu01 和 students 组。
Authentik 登录页:

图:Authentik 登录页。
管理后台用户列表里能看到 stu01,最后一次登录就是刚才通过 Slurm-web 的 LDAP 认证:

图:Authentik 管理后台用户列表,stu01 的最后登录来自 Slurm-web。
Slurm-web 改用 Authentik LDAP 后,stu01 登录成功:

图:Slurm-web 使用 Authentik 的 stu01 登录。
关键配置和实测中的问题(Provider/Outpost 在 Authentik 管理后台的 Applications 里创建):
- LDAP Provider 的
base_dn设为dc=example,dc=edu,bind_mode=direct、search_mode=direct、mfa_support=false。 authorization_flow要指向default-authentication-flow,不是default-provider-authorization-*。指向授权 flow 时,LDAP bind 会走到未认证用户不适用的 flow,日志报FlowNonApplicableException,客户端只看到Invalid credentials。- LDAP Outpost 用
ghcr.io/goauthentik/ldap:2024.12.3,环境变量AUTHENTIK_HOST、AUTHENTIK_TOKEN(outpost token),监听 3389/6636。 - SSSD 用 LDAPS 6636 +
ldap_tls_reqcert=never(测试自签证书);ldap_id_use_start_tls=false在这个 Authentik 版本上仍会尝试 START TLS,最后改用 LDAPS。 - Authentik 的
uid是哈希,登录名在cn/sAMAccountName;SSSD 里要ldap_user_name = cn,否则getent拿到的是哈希。 - Slurm-web gateway 的 LDAP 配置改成 Authentik:
user_base=ou=users,...、group_base=ou=groups,...、bind_dn=cn=akadmin,...、user_name_attribute=cn、restricted_groups=students。
服务启动方式(镜像可以提前 docker load,不依赖在线拉取):
docker run -d --name authentik-server --network host \
--env-file /opt/authentik/env -v /opt/authentik/media:/media \
ghcr.io/goauthentik/server:2024.12.3 server
docker run -d --name authentik-worker --network host \
--env-file /opt/authentik/env -v /opt/authentik/media:/media \
ghcr.io/goauthentik/server:2024.12.3 worker
# token 用 LDAP Outpost 详情里的服务账号 token
docker run -d --name authentik-ldap --network host \
-e AUTHENTIK_HOST=http://10.31.0.243:9000 \
-e AUTHENTIK_TOKEN=... \
ghcr.io/goauthentik/ldap:2024.12.3
SSSD 关键配置:
[domain/authentik]
id_provider = ldap
auth_provider = ldap
ldap_uri = ldaps://10.31.0.243:6636
ldap_tls_reqcert = never
ldap_default_bind_dn = cn=akadmin,ou=users,dc=example,dc=edu
ldap_default_authtok = ...
ldap_user_search_base = ou=users,dc=example,dc=edu
ldap_group_search_base = ou=groups,dc=example,dc=edu
ldap_user_object_class = posixAccount
ldap_group_object_class = posixGroup
ldap_user_name = cn
ldap_user_uid_number = uidNumber
ldap_user_gid_number = gidNumber
ldap_user_gecos = displayName
ldap_user_home_directory = homeDirectory
ldap_id_mapping = false
ldap_access_filter = (objectClass=posixAccount)
实测 getent passwd stu01 返回 uid/gid 2005,pamtester login stu01 authenticate 成功;Authentik 用户列表里也能看到这次登录时间。测试环境用 HTTP、bootstrap 口令和自签证书,生产要换 TLS、正式 CA 和 credential管理;LDAP bind 也不要用 akadmin,换成只读服务账号并限制搜索范围。
用 Teleport 接入(实测)
Teleport 18.10 社区版装在 slurm-auth(10.31.0.243)上,auth 和 proxy 用同一个进程,TLS 用自签证书;登录节点 slurm-build 以 node 角色加入集群。
配置步骤:
- 在 Teleport 建角色
slurm-login,允许user和stu01登录,节点标签放开。 - 用
tctl users add生成邀请链接;本地用户必须设置密码并绑定 TOTP。社区版不能用second_factor: off关掉 MFA,tctl会直接报cannot disable multi-factor authentication。 - 登录节点安装 Teleport,用
tctl tokens add --type=node生成的 token 注册为 node。 - 浏览器登录 Teleport,在 Resources 里打开
slurm-build的 Web 终端。
关键命令:
# Teleport 服务端
teleport start --config /etc/teleport.yaml
# 建角色和用户
tctl users add labadmin --roles=slurm-login --logins=user,stu01
# 生成节点 token,然后在登录节点启动 node 服务
tctl tokens add --type=node --ttl=1h
teleport start --roles=node --token=<token> \
--auth-server=10.31.0.243:3025 --insecure
--insecure 只用于自签证书的实验环境;生产要换成正式证书并去掉这个参数。节点注册后,tctl nodes ls 能看到:
Host ID Public Address Labels Version
------------ ------------------- ---------------- ----------- ---------
slurm-build d09e2fe6-e501-42... 10.31.0.229:3022 role=login 18.10.0
Web 资源页和 Web 终端:

图:Teleport Web 资源页里的登录节点。

图:通过 Teleport Web 终端登录 slurm-build;sinfo 返回两个计算节点。
Teleport 默认把 node 会话录到 /var/lib/teleport/log/ 下,本次会话目录约 76 KB,说明录制已经开启;没有打开播放器逐帧检查。
OIDC 的限制:在社区版执行 tctl create 创建 OIDC connector 时返回:
ERROR: OIDC is only available in Teleport Enterprise
所以 Authentik 作为 Teleport 的 OIDC IdP 这条路径没有在社区版跑通,本文的 Teleport 实测是本地用户 + TOTP + Web 终端。要用 Authentik 做 Teleport 的 SSO,需要 Teleport Enterprise,或者选一个仍把 OIDC 放在社区版的旧版本并自行验证。
无论用哪种方式,登录节点统一身份后,用户直接在该节点使用 sacct/squeue/srun/sbatch 即可与 Slurm 交互;配合前文的 AccountingStorageEnforce=associations,limits,qos,可确保只有已关联的用户/账户/QoS 能够正常提交作业。
Web 界面(作业可视化与管理)
本节实际部署了 Slurm-web 3.3.0 和 Open OnDemand 4.0.11。Slurm-web 用 LDAP 账号登录,Open OnDemand 用 Authentik OIDC 登录,两套都看到了真实的节点和作业数据。
想在浏览器查看作业、队列、节点状态并进行基本管理,常见的 Web 前端和门户有以下几类:
Slurm-web(基于 slurmrestd)
Slurm-web v3 要求 Slurm >=23.02;本次在 23.11.4 上实测,22.05 不能直接用这个版本。下面先给通用做法,实际配置见下面的“Slurm-web 3.3.0 实测”。
Slurm 提供 REST API(slurmrestd),社区有基于该 API 的 Web UI(常见实现:Slurm-web、Slurm UI)。
步骤概览(控制节点):
sudo apt install -y slurmrestd
# 生成或放置 slurmrestd 运行所需的凭据(基于 Munge 或 Basic/OAuth 反向代理)
# 简单起见,建议放在内网并在反向代理层做认证(如 Nginx+OIDC/Authentik)。
# 以 Unix Socket 运行(推荐与反代配合)
sudo mkdir -p /run/slurm
sudo chown slurm:slurm /run/slurm
sudo tee /etc/systemd/system/slurmrestd.service >/dev/null <<'UNIT'
[Unit]
Description=Slurm REST API Service
After=network.target slurmctld.service
[Service]
User=slurm
Group=slurm
ExecStart=/usr/sbin/slurmrestd unix:/run/slurm/slurmrestd.sock
Restart=on-failure
[Install]
WantedBy=multi-user.target
UNIT
sudo systemctl daemon-reload
sudo systemctl enable --now slurmrestd.service
如果发行版的 slurmrestd 自带 socket activation,不要同时启用它的 .socket 和这里手动绑定的 service,两者会抢同一个 socket 路径。Nginx 以 www-data 运行时,还要让这个用户能读写 /run/slurm/slurmrestd.sock(例如把 www-data 加入 slurm 组,或单独调整 socket 属组)。
然后:
- 在 Nginx/Caddy 前面挂一个反向代理,将
/api/转发到该 Unix Socket。 - 在反向代理层做认证(推荐与前文的 Authentik OIDC 结合),并将用户身份映射为 HTTP 头给 slurmrestd。
- 部署 Slurm-web 前端(参考其项目文档)以调用
/api/。
注意:不同的 Slurm-web 前端项目配置略有差异;建议选一个维护活跃、与当前 Slurm 版本兼容的项目。
示例:用 Nginx 反代 slurmrestd(Unix Socket)并用 oauth2-proxy 对接 Authentik OIDC
- 安装 oauth2-proxy(示例用二进制方式,替换版本/路径):
sudo useradd -r -s /sbin/nologin oauth2-proxy || true
sudo mkdir -p /etc/oauth2-proxy
curl -L -o /tmp/oauth2-proxy.tar.gz https://github.com/oauth2-proxy/oauth2-proxy/releases/download/v7.6.0/oauth2-proxy-v7.6.0.linux-amd64.tar.gz
tar xzf /tmp/oauth2-proxy.tar.gz -C /tmp
sudo install -m 0755 /tmp/oauth2-proxy-v7.6.0.linux-amd64/oauth2-proxy /usr/local/bin/oauth2-proxy
sudo tee /etc/oauth2-proxy/oauth2-proxy.cfg >/dev/null <<'CFG'
provider = "oidc"
oidc_issuer_url = "https://auth.example.com/application/o/your-authentik/"
client_id = "YOUR_CLIENT_ID"
client_secret = "YOUR_CLIENT_SECRET"
cookie_secret = "RANDOM_32B_BASE64=="
email_domains = ["*"]
upstreams = ["file:///dev/null"]
reverse_proxy = true
pass_authorization_header = true
set_xauthrequest = true
skip_provider_button = true
redirect_url = "https://slurm.example.com/oauth2/callback"
whitelist_domains = [".example.com"]
CFG
sudo tee /etc/systemd/system/oauth2-proxy.service >/dev/null <<'UNIT'
[Unit]
Description=oauth2-proxy
After=network-online.target
[Service]
User=oauth2-proxy
Group=oauth2-proxy
ExecStart=/usr/local/bin/oauth2-proxy --config=/etc/oauth2-proxy/oauth2-proxy.cfg
Restart=on-failure
[Install]
WantedBy=multi-user.target
UNIT
sudo systemctl daemon-reload
sudo systemctl enable --now oauth2-proxy
- Nginx 站点(/api 直连 slurmrestd 的 Unix Socket,整站走 oauth2-proxy 的 auth_request):
server {
listen 80;
server_name slurm.example.com;
return 301 https://$host$request_uri;
}
server {
listen 443 ssl http2;
server_name slurm.example.com;
ssl_certificate /etc/ssl/certs/your.crt;
ssl_certificate_key /etc/ssl/private/your.key;
# 与 oauth2-proxy 集成
location = /oauth2/auth {
proxy_pass http://127.0.0.1:4180/oauth2/auth;
proxy_set_header X-Original-URI $request_uri;
proxy_set_header X-Real-IP $remote_addr;
proxy_set_header X-Scheme $scheme;
proxy_set_header X-Auth-Request-Redirect $request_uri;
}
location /oauth2/ {
proxy_pass http://127.0.0.1:4180;
proxy_set_header Host $host;
proxy_set_header X-Real-IP $remote_addr;
proxy_set_header X-Scheme $scheme;
}
# 保护整个站点
auth_request /oauth2/auth;
error_page 401 = @error401;
location @error401 {
return 302 /oauth2/start?rd=$scheme://$http_host$request_uri;
}
# 前端静态资源(将 root 指向你的 Slurm-web 前端构建目录)
root /var/www/slurm-web;
index index.html;
# 将 /api 转发到 slurmrestd 的 Unix Socket
location /api/ {
proxy_set_header Host $host;
proxy_set_header X-Forwarded-Proto $scheme;
proxy_set_header X-Forwarded-For $remote_addr;
proxy_pass http://unix:/run/slurm/slurmrestd.sock:/;
}
}
说明:
- oauth2-proxy 的 issuer_url、client_id/secret、redirect_url 需在 Authentik 应用中创建并替换。
- 如需在 Slurm 内部识别用户身份,可在前端调用 slurmrestd 时附带映射的用户名(参考所用前端项目文档);同时将 slurmrestd 仅暴露在本机 Unix Socket,减少越权风险。
Slurm-web 3.3.0 实测
2026-11 在 23.11.4 集群上实际部署:Rackslab APT 源安装 slurm-web-agent/slurm-web-gateway 3.3.0,slurmrestd 用 23.11 源码,gateway 接 OpenLDAP。
登录页:

图:Slurm-web 登录页。
用 student1(LDAP,Students 组)登录后的 Dashboard:

图:LDAP 用户登录后的 Dashboard。
Jobs 页能看到 --gres=gpu:1 的作业处于 RUNNING:

图:Jobs 列表里的 GPU 作业。
作业详情里能看到提交命令的 --gres=gpu:1,Requested 和 Allocated 都有 gres: 1:

图:作业详情中的 --gres=gpu:1 和 gres 分配。
实测中的几个问题:
slurmrestd用默认 local auth,不要加-a rest_auth/jwt。v3 的 agent 通过 Unix socket 以slurm用户连接;加 JWT 后页面会报Unsupported Content-Type for slurmrestd response ... text/plain。- Slurm-web 3.3 和 Debian 的
python3-racksdb 0.7不兼容,agent 会报Property types is required in schema for object Schema_content;测试里用 RacksDB 0.5 的 Python 包和 0.5 schema,并给 agent 配PYTHONPATH和最小racksdb.yml。 - gateway 的 LDAP 配置用
uri=ldap://...、user_base、group_base、bind_dn、bind_password、restricted_groups=students;生产应换成 LDAPS 并保护 bind 口令。 - agent 和 gateway 默认跑 Flask 开发服务器,生产要换 WSGI/HTTPS 反代。
- 如果启用了
AuthAltTypes=auth/jwt,JWT key 要同步到主备slurmctld;测试里 ctl2 缺少/var/spool/slurm/jwt_hs256.key时直接 fatal,备控制器起不来。
实际配置(节选):
# /etc/slurm-web/agent.ini
[service]
cluster=slurm-lab
[slurmrestd]
socket=/run/slurmrestd/slurmrestd.socket
version=0.0.39
[racksdb]
schema=/opt/racksdb05/schema/racksdb.yml
db=/var/lib/racksdb/racksdb.yml
# /etc/slurm-web/gateway.ini
[service]
interface=0.0.0.0
[ui]
host=http://10.31.0.225:5011
[agents]
url=http://localhost:5012
[authentication]
enabled=yes
[ldap]
uri=ldap://10.31.0.225
user_base=ou=people,dc=example,dc=edu
group_base=ou=groups,dc=example,dc=edu
bind_dn=cn=admin,dc=example,dc=edu
bind_password=...
restricted_groups=students
slurmrestd 的 unit 实测:
[Service]
User=slurm
Group=slurm
Environment=SLURMRESTD_SECURITY=disable_user_check
ExecStart=/usr/sbin/slurmrestd unix:/run/slurmrestd/slurmrestd.socket
源码安装时把 /usr/sbin/slurmrestd 换成实际 prefix 下的路径(测试用 /opt/slurm-23.11/sbin/slurmrestd)。
Open OnDemand(实测)
Open OnDemand 4.0.11 装在 slurm-build(10.31.0.229)上,系统是 Debian 12,Slurm 适配器直接调用 /opt/slurm-23.11/bin。登录走 Authentik 的 OIDC,Dashboard 和 Active Jobs 都能看到真实作业。
安装(Debian 12 / bookworm):
wget -O /tmp/ondemand-release-web_4.0.0-bookworm_all.deb \
https://apt.osc.edu/ondemand/4.0/ondemand-release-web_4.0.0-bookworm_all.deb
sudo apt install /tmp/ondemand-release-web_4.0.0-bookworm_all.deb
sudo apt update
sudo apt install ondemand libapache2-mod-auth-openidc
sudo a2enmod ssl
sudo a2enmod auth_openidc
本次 OOD 用 HTTPS 443 + 自签证书做实验,生产要换正式证书。/etc/ood/config/ood_portal.yml:
servername: "10.31.0.229"
port: 443
ssl:
- 'SSLCertificateFile "/etc/ssl/certs/ood.crt"'
- 'SSLCertificateKeyFile "/etc/ssl/private/ood.key"'
auth:
- "AuthType openid-connect"
- "Require valid-user"
oidc_uri: "/oidc"
oidc_provider_metadata_url: "http://10.31.0.243:9000/application/o/ood/.well-known/openid-configuration"
oidc_client_id: "YOUR_CLIENT_ID"
oidc_client_secret: "YOUR_CLIENT_SECRET"
oidc_remote_user_claim: "preferred_username"
oidc_scope: "openid profile email"
user_map_match: ".*"
在 Authentik 里创建 OAuth2/OpenID Provider 时,重定向 URI 要填 https://10.31.0.229/oidc,不是 /oidc/callback。OOD 的 oidc_uri 本身就充当回调路径;实测 OOD 发出的 redirect_uri 是 /oidc,如果 Provider 里填 /oidc/callback,两边对不上,登录会失败。这一步和很多 OIDC 示例不一样。
Slurm 集群配置 /etc/ood/config/clusters.d/debian.yml:
v2:
metadata:
title: "Debian Slurm"
login:
host: "10.31.0.229"
job:
adapter: "slurm"
cluster: "slurm-lab"
bin: "/opt/slurm-23.11/bin"
应用配置:
sudo /opt/ood/ood-portal-generator/sbin/update_ood_portal
sudo a2dissite 000-default
sudo apache2ctl configtest
sudo systemctl restart apache2
OOD 的本地用户要和 OIDC 里的 preferred_username 对上。本次 stu01 在 OOD 主机上是本地用户(20002:20000),Authentik 的 preferred_username 也是 stu01,映射成功。

图:Open OnDemand 4.0.11 的 Dashboard,登录用户为 stu01。
提交作业后,Active Jobs 能看到作业号、用户、账户、队列和状态:

图:OOD Active Jobs 读取 slurm-lab 集群;job 80 通过 Job Composer 提交并完成。
Job Composer 在 HTTP 下会返回 422 InvalidAuthenticityToken:myjobs 的 session cookie 配置是 secure: Rails.env.production?,HTTP 页面里浏览器不会保存这个 Secure cookie,POST 时 CSRF 校验失败。切到 HTTPS 后 Cookie 正常保存,创建 workflow 和提交都成功。默认模板创建出的目录里没有脚本,本次手动放了 main_job.sh(带 #SBATCH -A classa),点 Submit 后 job 80 完成。

图:OOD Job Composer 提交 main_job.sh 后,job 80 进入队列。
Grafana/Prometheus(监控与可视化,实测)
这套监控在一台独立 VM(slurm-auth,10.31.0.243)上跑:Prometheus 2.42.0、Alertmanager 0.25.0、Grafana 13.3.1;Slurm 指标用 SckyzO 的 slurm_exporter 1.8.6,节点指标用 Debian 的 prometheus-node-exporter。
先说选型。本文早先写的 ubccr/slurm-exporter 通过 slurmrestd 的 REST API 取数,最新版按 Slurm REST API v0.0.44 生成客户端;测试集群是 Slurm 23.11.4,REST API 到 v0.0.39,直接使用会打不中版本。最后改用 sckyzo/slurm_exporter:它直接调用 sinfo、squeue、sdiag 等命令,不依赖 REST API 版本,Debian 12 上不需要额外编译。
在控制节点安装 exporter:
curl -L -o /tmp/slurm_exporter.tar.gz \
https://github.com/sckyzo/slurm_exporter/releases/download/v1.8.6/slurm_exporter-1.8.6-linux-amd64.tar.gz
tar -xzf /tmp/slurm_exporter.tar.gz -C /tmp
sudo install -m 755 /tmp/slurm_exporter /usr/local/bin/slurm_exporter
systemd 单元:
[Unit]
Description=Prometheus Slurm exporter
After=network.target munge.service
[Service]
User=slurm
Group=slurm
ExecStart=/usr/local/bin/slurm_exporter \
--slurm.bin-path=/opt/slurm-23.11/bin \
--web.listen-address=0.0.0.0:9341
Restart=on-failure
[Install]
WantedBy=multi-user.target
Prometheus 抓取配置:
global:
scrape_interval: 15s
evaluation_interval: 15s
rule_files:
- /etc/prometheus/rules/slurm-lab.yml
alerting:
alertmanagers:
- static_configs:
- targets: ["127.0.0.1:9093"]
scrape_configs:
- job_name: "slurm-exporter"
static_configs:
- targets: ["10.31.0.225:9341"]
- job_name: "node"
static_configs:
- targets:
- "10.31.0.225:9100"
- "10.31.0.226:9100"
- "10.31.0.227:9100"
告警规则(测试时把 for 缩到 30 秒,生产可以按需放宽):
groups:
- name: slurm-lab
rules:
- alert: SlurmNodeDown
expr: sum(slurm_nodes_down + slurm_nodes_drain) > 0
for: 30s
labels:
severity: warning
annotations:
summary: "Slurm 节点 DOWN 或 DRAIN"
description: "{{ $value }} 个节点不可用。"
Alertmanager 接一个 webhook:
route:
receiver: webhook
group_wait: 5s
group_interval: 10s
repeat_interval: 1m
receivers:
- name: webhook
webhook_configs:
- url: "http://127.0.0.1:9099/alerts"
send_resolved: true
实测触发:
scontrol update NodeName=node-gpu State=DRAIN Reason=alert-pipeline-test
约 30 秒后 Prometheus 的 SlurmNodeDown 进入 firing,Alertmanager 把通知 POST 到 webhook;恢复节点:
scontrol update NodeName=node-gpu State=RESUME
webhook 收到的 firing 和 resolved 记录都能在 /var/log/alertmanager-webhook.log 里看到。这里也踩到一个坑:先试的是 State=DOWN,但 ReturnToService=2 会让节点在重新注册后自动回到 IDLE,告警来不及稳定触发;改用 DRAIN 后状态保持住,测试才成立。
Prometheus 的告警页:

图:Prometheus 的 Alerts 页面,SlurmNodeDown 正在 firing。
Grafana 导入 exporter 项目自带的 01-slurm-overview.json,数据源选 Prometheus:

图:Grafana 的 Slurm Cluster Overview;测试时 GPU 节点处于 DRAIN。
Debian 的 prometheus-alertmanager 包不带 Web UI,访问 9093 只会看到“The Debian package … does not include a web application”。要么用 amtool/HTTP API,要么换官方二进制;本文用 API 和 webhook 日志验证告警链,没有把 Alertmanager UI 截图当作结果。
多用户与项目配额(QoS)
以下示例展示如何用 sacctmgr 配置账户(项目)、用户关联与 QoS 限额。需启用 slurmdbd 与 AccountingStorageEnforce=associations,limits,qos。
概念速记
- Account(项目):用于汇总计费/配额的逻辑单位,如 projA。
- User:系统用户与 Account 关联后才能提交(在 enforce=associations 启用时)。
- QoS:定义资源与时间等约束,可分配给用户/账户/分区。
建立账户与用户关联
# 新建账户(项目)
sudo sacctmgr add account projA Description="Project A" Organization=orgA
# 关联用户到账户(如已有系统用户 alice、bob)
sudo sacctmgr add user alice Account=projA
sudo sacctmgr add user bob Account=projA
# 可选:设置 Fairshare 权重(影响调度优先级公平性)
sudo sacctmgr modify account projA set fairshare=100
sudo sacctmgr modify user alice set fairshare=50
sudo sacctmgr modify user bob set fairshare=50
sudo sacctmgr show assoc format=Cluster,Account,User,Partition,FairShare
定义 QoS 与限额
常见字段:
- MaxJobsPerUser、MaxJobs、MaxSubmitJobs:并行/排队作业数限制。
- MaxWall、MaxTRESPU、MaxTRESPA:对资源类型的限额(如 cpu、mem、gres/gpu)。
- GrpCPUs、GrpNodes、GrpWall:以账户为维度的聚合限制。
示例 1:创建两个 QoS
normal可能是 Slurm 自动创建的默认 QoS。先sacctmgr show qos确认;已存在就用modify,不存在再用add。对已存在的 QoS 执行add会报 “Nothing new added”,限制也不会写进去。
# 一个短作业 QoS:最多 4 小时,每用户最多并行 10 个作业
sudo sacctmgr add qos short MaxWall=04:00:00 MaxJobsPerUser=10 Priority=100
# normal 已存在时,用 modify 设置:最多 2 天,每用户最多 3 个作业,最多 64 CPU
sudo sacctmgr modify qos normal set MaxWall=2-00:00:00 MaxJobsPerUser=3 MaxTRESPU=cpu=64 Priority=50
sudo sacctmgr show qos format=Name,Priority,MaxWall,MaxJobsPU,MaxTRESPU
QoS 的时间/资源限制要生效,
AccountingStorageEnforce必须包含limits,改完要重启slurmctld(scontrol reconfigure不一定能刷新这部分)。
示例 2:为账户/用户指定 QoS 默认与可用列表
# 账户 projA 可用 QoS:short、normal;默认使用 normal
sudo sacctmgr modify account projA set qos=normal,short defaultqos=normal
# 若需更细化到用户层:
sudo sacctmgr modify user alice set qos=short,normal defaultqos=short
sudo sacctmgr modify user bob set qos=normal
示例 3:账户级聚合资源限制(避免项目独占集群)
# 限制 projA 聚合最多同时占用 256 CPU、4 台节点、总墙时 3 天
sudo sacctmgr modify account projA set GrpCPUs=256,GrpNodes=4,GrpWall=3-00:00:00
22.05 里
GrpCPUs=256会落到GrpTRES=cpu=256;直接写GrpTRES=cpu=256也可以。
GPU(GRES)相关 QoS 限额:
# 限制每用户最多占用 2 张 GPU(假设 GRES 名称为 gpu)
sudo sacctmgr modify qos normal set MaxTRESPU=gres/gpu=2
# 或者为账户维度设置聚合 GPU 上限 8 张
sudo sacctmgr modify account projA set GrpTRES=gres/gpu=8
与分区的配合
可以将 QoS 与分区策略配合,例如:
# 在 slurm.conf 中设置分区配额/限制(示意)
PartitionName=debug Nodes=ALL Default=YES MaxTime=04:00:00 State=UP QOS=short
注意:有的站点更倾向不在分区上固定 QOS,而是仅通过 sacctmgr 赋予用户/账户 QoS 列表,以获得更灵活的控制。
生效与排错
sudo scontrol reconfigure
sudo sacctmgr show qos -n
sudo sacctmgr show assoc -n
多租户:学校/实验室场景
学校或实验室的典型需求是:每个班级/项目一个 account,学生用 LDAP/SSSD 登录,作业按 account、QoS、partition 隔离,软件环境用 Lmod 管理,存储按用户/项目做配额。Slurm 不提供 LDAP 或 module 系统,这几块要组合起来。
账户、分区与公平调度
# 每个班级/项目一个 account
sudo sacctmgr -i add account classA Description="Class A" Organization=school
sudo sacctmgr -i add account classB Description="Class B" Organization=school
# 学生关联到 account;一个用户可以属于多个 account
sudo sacctmgr -i add user alice Account=classA
sudo sacctmgr -i add user bob Account=classB
# 公平调度权重
sudo sacctmgr -i modify account classA set fairshare=100
sudo sacctmgr -i modify account classB set fairshare=50
# 账户级资源上限:classA 最多 64 CPU,classB 最多 32 CPU
sudo sacctmgr -i modify account classA set GrpTRES=cpu=64
sudo sacctmgr -i modify account classB set GrpTRES=cpu=32
Slurm 的 account 名大小写不敏感,实际存储会转成小写;
AllowAccounts=classA在scontrol show partition里会显示为classa,不影响匹配。
按班级划分分区,限制可用 account:
# slurm.conf
PartitionName=classA Nodes=node[01-02] AllowAccounts=classA MaxTime=04:00:00 State=UP
PartitionName=classB Nodes=node[03-04] AllowAccounts=classB MaxTime=08:00:00 State=UP
AllowAccounts / AllowGroups 的拒绝不一定发生在 sbatch 提交阶段。实测把 -A classB 的作业提交到 classA 分区时,sbatch 仍然返回 job id,随后作业以 Job's account not permitted to use this partition (...) 结束或被拒绝。排错时看 scontrol show job 的 Reason,不要只看提交返回值。
如果分区 MaxTime 比 Slurm 默认作业时长小,学生脚本又没写 --time,作业会 Pending PartitionTimeLimit(实测)。给学生用的分区要么设置 DefaultTime,要么在作业模板里固定 #SBATCH --time=...。
按班级/项目出用量报表:
# 按账户+用户统计某个月的 CPU 分钟
sreport cluster AccountUtilizationByUser Start=2026-11-01 End=2026-12-01
# 看公平份额和当前用量
sshare -a
Lmod 软件环境
Debian 12 自带 lmod(8.6.x),可以直接装:
sudo apt install -y lmod
把 modulefiles 放在共享目录(多节点必须一致),例如 /opt/modulefiles/hello/1.0.lua:
graph LR
J["学生作业"] --> M["module load"]
M --> MF["modulefiles<br/>gcc / openmpi / cuda"]
MF --> SW["共享软件目录 /opt"]
SW --> C["计算节点"]
help([[hello 1.0]])
whatis("Name: hello")
whatis("Version: 1.0")
prepend_path("PATH", "/opt/hello/1.0/bin")
setenv("HELLO_VERSION", "1.0")
登录节点和计算节点都加一行,让 Lmod 找到本地 modulefiles:
echo 'module use /opt/modulefiles' | sudo tee /etc/profile.d/zz-local-modules.sh
作业里通过 login shell 加载:
srun -N2 -n2 bash -lc 'module load hello/1.0; hello; echo VERSION=$HELLO_VERSION'
实测输出:
hello 1.0 on slurm-node2
hello 1.0 on slurm-node1
VERSION=1.0
VERSION=1.0
Lmod 的几个实践点:
- modulefiles 放在共享存储或每个节点用配置管理同步,避免节点之间模块版本不一致。
- 作业脚本用
bash -lc或显式source /etc/profile.d/lmod.sh,非登录 shell 不会自动加载module函数。 - 需要固定默认环境时用
LMOD_SYSTEM_DEFAULT_MODULES或module save;学生自己module load的栈不要写进系统级默认。 - modulefile 里避免写死节点本地路径;软件装在共享路径,或用
module use指向共享 modulefiles。
LDAP/SSSD 与 Slurm 账户
LDAP/SSSD 解决的是“系统用户登录、UID/GID、家目录、SSH 公钥”;Slurm 的 Account/User 关联存在 slurmdbd 的数据库里,是另一套东西。两者要分别配置,再做同步。登录节点的 Authentik LDAP/Teleport 接法见前文“接入单点登录”,这里补多租户相关的 UID/GID、家目录和 Slurm association。
graph LR
subgraph Identity["身份源"]
LDAP["LDAP / AD<br/>用户 / 组 / UID/GID / SSH key"]
end
subgraph Linux["Linux 节点"]
SSSD["SSSD<br/>nss + pam + ssh"]
LOGIN["登录节点 / sshd"]
COMPUTE["计算节点 / slurmd"]
end
subgraph Slurm["Slurm 控制面"]
DBD["slurmdbd / MariaDB<br/>account association"]
CTLD["slurmctld<br/>account / QoS / partition"]
end
LDAP --> SSSD
LDAP --> SYNC["同步脚本<br/>LDAP 班级 -> sacctmgr"]
SSSD --> LOGIN
SSSD --> COMPUTE
LOGIN -->|"提交 / 查询"| CTLD
SYNC --> DBD
DBD --- CTLD
Debian 12 上安装 SSSD 和 PAM 模块:
sudo apt install -y sssd sssd-ldap libnss-sss libpam-sss libpam-slurm-adopt
sudo pam-auth-update --enable mkhomedir
Debian 没有
authselect(那是 RHEL 系的工具),也不要用echo ... > /etc/pam.d/common-session覆盖 PAM 配置;用pam-auth-update或pam-auth-update --enable mkhomedir。
SSSD 的 LDAP 配置示例:
[sssd]
services = nss, pam, ssh
config_file_version = 2
domains = school
[domain/school]
id_provider = ldap
auth_provider = ldap
ldap_uri = ldaps://ldap.example.edu:636
ldap_search_base = dc=example,dc=edu
ldap_default_bind_dn = uid=binduser,ou=system,dc=example,dc=edu
ldap_default_authtok = BIND_USER_PASSWORD
ldap_tls_reqcert = demand
ldap_id_mapping = false
cache_credentials = True
enumerate = False
ldap_user_ssh_public_key = sshPublicKey
access_provider = ldap
ldap_access_filter = (memberOf=cn=students,ou=groups,dc=example,dc=edu)
要点:
ldap_id_mapping = false仅适用于 LDAP 里已经有 POSIX UID/GID 的情况;如果没有,保持默认映射,并确保所有节点用同一个 SSSD 配置,否则同一用户在登录节点和计算节点上的 UID 可能不同。ldap_access_filter用memberOf时,OpenLDAP 要先加载 memberof overlay 并维护组属性;普通 OpenLDAP 没有这个 overlay,可以先用(objectClass=posixAccount)验证登录,再换组成员过滤。- 家目录放在共享存储,配合
pam_mkhomedir;否则学生第一次登录的节点和作业节点看到的/home不一致。 - 如果 LDAP 提供 SSH 公钥,
ldap_user_ssh_public_key让 SSSD 能查到 key;sshd 还要配AuthorizedKeysCommand /usr/bin/sss_ssh_authorizedkeys(AuthorizedKeysCommandUser nobody),否则公钥不会自动生效。没有 LDAP 公钥时用配置管理分发authorized_keys。 - 计算节点加
libpam-slurm-adopt,并在/etc/pam.d/sshd里加account required pam_slurm_adopt.so;同时slurm.conf要设PrologFlags=Contain,否则作业没有externstep,有作业的用户也会被拒绝。session 栈里还要禁用pam_systemd,否则会话会被 systemd 放进自己的 scope,不在作业 cgroup 里。实测无作业拒绝、有 batch 作业时 SSH 会话进入job_<id>/step_externcgroup,细节见“安全加固”一节。
新生开户不要在每台节点上 useradd,直接在 LDAP 里加 posixAccount 条目。下面是一个最小 LDIF(uidNumber 和 gidNumber 要和学校的号段规划一致):
dn: uid=stu01,ou=people,dc=example,dc=edu
objectClass: inetOrgPerson
objectClass: posixAccount
objectClass: shadowAccount
uid: stu01
cn: Student 01
sn: 01
givenName: Student
uidNumber: 20002
gidNumber: 20000
homeDirectory: /home/stu01
loginShell: /bin/bash
mail: [email protected]
userPassword: {SSHA}...
userPassword 用 slappasswd -s '初始口令' 生成后填进去,再用管理员 DN 导入:
LDAPTLS_REQCERT=never ldapadd -x -H ldaps://ldap.example.edu:636 \
-D cn=admin,dc=example,dc=edu -W -f stu01.ldif
-W 会交互式提示 bind 口令,不要把管理员口令写进脚本或 shell history。LDAPTLS_REQCERT=never 只用于自签证书的测试环境;生产环境把 CA 装到系统信任库,去掉这个变量。
LDAP 里加完后,配置了 SSSD 的节点 getent passwd stu01 就能看到用户;第一次 SSH 登录时 pam_mkhomedir 会按 /etc/skel 建家目录。2026-11 的测试里新建 stu01(uid 20002)后没有在任何节点执行 useradd,直接用 LDAP 密码 SSH 登录控制节点成功,家目录自动创建为 stu01:students。
如果 getent 暂时看不到新用户,可能是 SSSD 缓存了之前的失败查询;执行 sudo sss_cache -E 或等缓存过期再试。
计算节点要看到同一个家目录,仍然需要共享存储(NFS 或 CephFS);测试集群最初只在登录节点建了家目录,srun 到 node1 时就报了 couldn't chdir to /home/stu01,回退到 /tmp。
Slurm 没有内置的 LDAP 后端,LDAP 用户不会自动变成 sacctmgr association。常见做法是用脚本从 LDAP/教务系统导出“用户-班级”关系,再调用 sacctmgr 同步:
# 示例:从 CSV(user,account)同步 association;已存在时会提示,可按需忽略
while IFS=, read -r user account; do
sudo sacctmgr -i add user "$user" Account="$account"
done < users.csv
实测:LDAP 里刚建完
stu01时直接srun会报Invalid account or account/partition combination specified(因为启用了AccountingStorageEnforce=associations);执行sacctmgr -i add user stu01 Account=classA后立即可以提交。生产环境把“LDAP 建用户”和“sacctmgr 加 association”放进同一个开户脚本,离校时两处都删。
2026-11 用 OpenLDAP + LDAPS 自签证书在测试集群上做了端到端验证:LDAP 里新建用户后,
getent passwd、pamtester login(LDAP password认证)、SSH 登录、家目录自动创建、srun/sbatch和sacct都通过。测试环境为了省事用了ldap_tls_reqcert = never;生产环境换成demand并安装正式 CA 证书。
存储配额
Slurm 的 QoS 只限制 CPU、内存、GPU 和作业数,不限制磁盘。学生场景要单独做:
- 家目录/项目目录放共享存储(CephFS、NFS 或并行文件系统),用文件系统配额或项目配额限制用量。
- scratch 目录按作业或用户定期清理,不要和家目录混在一起。
- 配额告警接入监控;配额满了作业会以各种“看起来像 Slurm 的问题”失败,排错时先看
df -h、quota或 CephFS quota。
学生上机/离校清单
- LDAP/教务系统创建用户和组,确认 UID/GID、家目录、SSH 公钥。
sacctmgr创建 account 和 association,设置 fairshare、QoS、GrpTRES。- 共享存储创建家目录/项目目录,设置配额。
- 用测试账号跑
sinfo、srun、sbatch,确认分区和 account 权限。 - 离校时禁用 LDAP、移除 association、归档/清理家目录和配额。
Prolog 与 Epilog 脚本
Prolog 和 Epilog 是 Slurm 在每个作业启动前和结束后自动在计算节点上执行的脚本,用于环境准备与清理。这是生产环境中保证节点状态干净、防止作业间相互影响的关键机制。
在 slurm.conf 中配置:
Prolog=/etc/slurm/prolog.sh
Epilog=/etc/slurm/epilog.sh
# PrologSlurmctld 和 EpilogSlurmctld 在控制节点执行,用于集群级别的前后处理
# PrologSlurmctld=/etc/slurm/prolog_ctld.sh
# EpilogSlurmctld=/etc/slurm/epilog_ctld.sh
Prolog 示例(作业启动前)
#!/usr/bin/env bash
# /etc/slurm/prolog.sh - 在计算节点上以 root 身份执行
set -euo pipefail
JOBID="${SLURM_JOB_ID:-unknown}"
# 为当前作业创建隔离的临时目录
JOB_TMPDIR="/tmp/slurm-job-${JOBID}"
mkdir -p "${JOB_TMPDIR}"
chown "${SLURM_JOB_UID}:${SLURM_JOB_GID}" "${JOB_TMPDIR}"
chmod 700 "${JOB_TMPDIR}"
# 检查关键文件系统是否挂载
if ! mountpoint -q /home; then
logger -t slurm-prolog "ERROR: /home not mounted for job ${JOBID}"
exit 1
fi
# 检查 GPU 驱动状态(如有 GPU)
if command -v nvidia-smi &>/dev/null; then
if ! nvidia-smi &>/dev/null; then
logger -t slurm-prolog "ERROR: nvidia-smi failed for job ${JOBID}"
exit 1
fi
fi
logger -t slurm-prolog "Prolog completed for job ${JOBID} user ${SLURM_JOB_USER}"
exit 0
Epilog 示例(作业结束后)
#!/usr/bin/env bash
# /etc/slurm/epilog.sh - 在计算节点上以 root 身份执行
set -euo pipefail
JOBID="${SLURM_JOB_ID:-unknown}"
# 只清理本作业创建的临时目录
rm -rf "/tmp/slurm-job-${JOBID}" 2>/dev/null || true
# 作业进程由 proctrack/cgroup 负责清理;这里不要 pkill -9 -u,
# 那会误杀同一用户在节点上的其它作业。
logger -t slurm-epilog "Epilog completed for job ${JOBID}"
exit 0
注意:
- Prolog 脚本返回非零值会导致作业无法在该节点运行,节点将被标记为
DRAIN状态。利用这一特性可以实现节点级别的准入检查。 - 脚本权限必须为 755,属主 root:root。
- 脚本内避免耗时操作(如网络请求),Prolog 执行时间过长会延迟作业启动。
- 生产环境建议将 Prolog/Epilog 的日志写入 syslog 或独立日志文件,便于事后排查。
- Epilog 只按作业 ID 清理;不要
pkill -u $SLURM_JOB_USER或删除整个用户的/dev/shm,那会误杀同一用户在节点上的其它作业。孤儿进程交给proctrack/cgroup处理。 - Prolog 里的
mountpoint -q /home假设/home是共享挂载;如果家目录就在根分区,这项检查会误判,改成检查你的实际挂载点或删掉。 - Prolog 里用
SLURM_JOB_UID:SLURM_JOB_GID,不要用user:user。LDAP 用户的主组可能是students而不是同名组;实测写成同名组会chown失败,Prolog 失败并把节点 DRAIN。
节点健康检查
Slurm 支持定期在计算节点上执行健康检查脚本。注意它只负责运行脚本,不会因为脚本返回非零就自动 DRAIN;节点状态要由脚本自己调用 scontrol update 来改。在 slurm.conf 中配置:
HealthCheckProgram=/etc/slurm/health_check.sh
HealthCheckInterval=300
HealthCheckNodeState=ANY
HealthCheckInterval=300:每 5 分钟执行一次检查。HealthCheckNodeState=ANY:对所有状态的节点都执行检查;也可设为IDLE仅检查空闲节点。
修改
HealthCheckProgram/HealthCheckInterval后,实测需要重启slurmctld才能让新配置生效;scontrol reconfigure在这组参数上不一定够。
健康检查脚本示例
#!/usr/bin/env bash
# /etc/slurm/health_check.sh
set -euo pipefail
HOSTNAME=$(hostname -s)
ERRORS=()
# 1. 检查关键文件系统
for mp in /home /projects; do
if [[ -d "${mp}" ]] && ! mountpoint -q "${mp}" 2>/dev/null; then
ERRORS+=("${mp} not mounted")
fi
done
# 2. 检查磁盘空间(根分区使用率超过 95% 视为异常)
for mp in / /tmp; do
usage=$(df --output=pcent "${mp}" 2>/dev/null | tail -1 | tr -d '% ')
if [[ -n "${usage}" ]] && (( usage > 95 )); then
ERRORS+=("${mp} disk usage ${usage}%")
fi
done
# 3. 检查内存(可用内存低于 512MB 视为异常)
avail_kb=$(awk '/MemAvailable/ {print $2}' /proc/meminfo)
if (( avail_kb < 524288 )); then
ERRORS+=("available memory ${avail_kb}KB too low")
fi
# 4. 检查 GPU 状态(如有)
if command -v nvidia-smi &>/dev/null; then
if ! nvidia-smi --query-gpu=gpu_bus_id --format=csv,noheader &>/dev/null; then
ERRORS+=("nvidia-smi query failed")
fi
# 检查不可纠正的 ECC 错误
ecc_errors=$(nvidia-smi --query-gpu=ecc.errors.uncorrected.aggregate.total \
--format=csv,noheader,nounits 2>/dev/null | awk '{s+=$1}END{print s}')
if [[ -n "${ecc_errors}" ]] && (( ecc_errors > 0 )); then
ERRORS+=("GPU uncorrected ECC errors: ${ecc_errors}")
fi
fi
# 5. 检查 Munge 认证
if ! munge -n 2>/dev/null | unmunge &>/dev/null; then
ERRORS+=("munge auth failed")
fi
# 6. 检查网络连通性(到控制节点)
if ! timeout 3 bash -c 'echo > /dev/tcp/controller-node/6817' 2>/dev/null; then
ERRORS+=("cannot reach slurmctld on port 6817")
fi
if (( ${#ERRORS[@]} > 0 )); then
reason=$(IFS='; '; echo "${ERRORS[*]}")
# 关键:HealthCheckProgram 不会自动 DRAIN,必须显式调用 scontrol
scontrol update NodeName="${HOSTNAME}" State=DRAIN Reason="${reason}"
logger -t slurm-health "UNHEALTHY ${HOSTNAME}: ${reason}"
echo "UNHEALTHY: ${reason}"
exit 1
fi
exit 0
示例假设 /home、/projects 是独立挂载点;如果它们在根分区,mountpoint 会失败并把节点 DRAIN,按实际挂载点改或删掉这段。
脚本返回非零值本身不会改变节点状态;上面的示例在返回前显式执行了 scontrol update NodeName=... State=DRAIN,节点才会被移出调度池。修复问题后需手动恢复:
sudo scontrol update NodeName=node01 State=RESUME Reason=""
日常管理
这一节是管理员每天会用的操作。下面的命令在 Debian 12 + Slurm 22.05 的测试集群上跑过,节点名、分区名按你的环境替换。
节点维护:DRAIN 和恢复
# 把节点从调度池里拿出来,写清楚原因
sudo scontrol update NodeName=node01 State=DRAIN Reason="kernel upgrade"
# 看节点状态和原因
sinfo -R
scontrol show node node01
# 等节点上的作业跑完(急事可以 scancel/requeue)
squeue -w node01
# 维护完成,恢复调度
sudo scontrol update NodeName=node01 State=RESUME Reason=""
实测 State=DRAIN 后新作业不会再落到该节点,RESUME 后恢复 IDLE。节点如果因为 Prolog 失败或健康检查失败自己进了 IDLE+DRAIN,先看 Reason 再处理。
分区维护
sudo scontrol update PartitionName=debug State=DOWN
sudo scontrol update PartitionName=debug State=UP
分区 DOWN 后不再接受新作业,已经在跑的作业不受影响,适合做整个分区的维护窗口。
作业管理
# 看队列和等待原因
squeue
squeue -t PD -o "%.10i %.9P %.12j %.8u %.2t %.10M %.20R"
# 挂起、恢复、重排、取消
sudo scontrol hold <jobid>
sudo scontrol release <jobid>
sudo scontrol requeue <jobid>
sudo scancel <jobid>
sudo scancel -u <user>
实测对运行中的作业执行 hold 后,状态还是 RUNNING,Reason=JobHeldAdmin;release 后恢复;requeue 后重新排队,可能显示 PENDING BeginTime。普通用户只能取消自己的作业。
账户与用户
sudo sacctmgr show assoc format=Cluster,Account,User,QOS,GrpTRES
sudo sacctmgr add user <user> Account=<account>
sudo sacctmgr remove user where name=<user> account=<account>
sudo sacctmgr modify account <account> set GrpTRES=cpu=64
毕业/离校时先移除 association,再禁用 LDAP;不要只删系统用户,Slurm 里可能还留着 association。
节点上下线
新增计算节点:
- 装
slurmd slurm-client munge libmunge2,同步/etc/slurm/slurm.conf和 munge key。 - 在
slurm.conf的NodeName/PartitionName里加节点。 scontrol reconfigure;结构性变更可能需要重启slurmctld和slurmd。systemctl enable --now slurmd,用sinfo确认节点变成 IDLE。
下线节点:先 DRAIN,等作业排空,systemctl stop slurmd,再从配置里删掉,scontrol reconfigure。不要直接关机了事。
维护与升级
Slurm 升级不是 apt upgrade 之后重启就完事,slurmdbd 的数据库 schema、slurmctld 的状态文件、slurmd 的版本兼容都要考虑。下面是一个保守的维护窗口流程。
维护窗口清单
- 提前通知用户,把分区 DOWN 或节点 DRAIN,停止新作业。
- 让运行中的作业跑完;急事可以
scontrol requeue或scancel。 - 备份
slurmdbd数据库、/etc/slurm、/etc/munge/munge.key和StateSaveLocation。 - 升级
slurmdbd,启动并确认 schema 升级成功。 - 升级
slurmctld,再升级slurmd;顺序不要反。 - 用
sinfo、scontrol ping、srun验证,恢复分区和节点。
Debian 包升级
# 先备份数据库和配置
sudo mysqldump --single-transaction slurm_acct_db | gzip > /backup/slurm-acct-$(date +%F).sql.gz
sudo tar czf /backup/slurm-etc-$(date +%F).tar.gz /etc/slurm /etc/munge/munge.key
# 控制节点
sudo apt update
sudo apt install --only-upgrade slurmdbd slurmctld slurm-client
sudo systemctl restart slurmdbd
sleep 3
sudo systemctl restart slurmctld
# 计算节点
sudo apt install --only-upgrade slurmd slurm-client
sudo systemctl restart slurmd
版本兼容按 SchedMD 的升级说明来:
slurmdbd先于slurmctld,slurmctld先于slurmd。不确定时先在一套测试集群上升级。
跨大版本升级:先看数据库转换版本
apt install --only-upgrade 只在同一个大版本内安全。跨大版本时,先看 slurmdbd 数据库里的转换版本:
sudo mysql -N -e "select version from convert_version_table" slurm_acct_db
Debian 12 的 22.05.8 是 12。新版 slurmdbd 启动时只接受 MIN_CONVERT_VERSION 以上的旧库;25.05.9 的 MIN_CONVERT_VERSION 是 14,直接拿 22.05 的库启动会 fatal:
fatal: Database schema is too old for this version of Slurm to upgrade.
中间要经过 23.11(CONVERT_VERSION=14,MIN_CONVERT_VERSION=11):22.05(v12) → 23.11(v14) → 25.05(v16)。每一跳只启动 slurmdbd,让它把 schema 转完,再停掉换下一跳的二进制。转换前备份数据库;schema 升级不可逆,回滚只能恢复备份。实测这三步的 convert_version_table 分别是 12、14、16,23.11 和 25.05 的 slurmdbd 日志都打出了 Conversion done: success!。Debian 12 仓库只有 22.05,23.11 需要从源码或其它仓库取;测试里是在单独的构建 VM 上编译的。
SelectType=select/cons_res 在 25.05 已经移除,升级前改成 select/cons_tres;SelectTypeParameters=CR_CPU_Memory 可以保留。slurmctld 读不懂旧的 StateSaveLocation 时会拒绝启动,日志里能看到 incompatible version, got 9728 need >= 10240 <= 11008;确认没有运行中作业后,用 slurmctld -i 忽略读不懂的状态文件(-c 则是完全不恢复)。
配置检查
# 在计算节点上验证 slurmd 能解析配置并打印节点信息
sudo /usr/sbin/slurmd -f /etc/slurm/slurm.conf -C
# 比较所有节点的配置是否一致
md5sum /etc/slurm/slurm.conf
22.05 没有 slurmctld -t 这种只检查配置的模式;改完配置先在测试节点或测试集群启动验证,或者 scontrol reconfigure 后看 slurmctld.log / slurmd.log。
回滚
- 保留旧版本
.deb或 apt 缓存,必要时apt install slurm-wlm=<version>。 slurmdbd的数据库 schema 升级通常不可逆;回滚前先确认有备份,最稳的是恢复数据库备份加旧版本二进制。StateSaveLocation也要一起备份,否则控制器回滚后可能读不懂新状态。
监控与告警
Slurm 自带的状态命令适合人工看,长期监控要接 Prometheus/Grafana。先分清三层:节点、调度器、作业和账户。
常用状态命令
# 队列和节点
sinfo
sinfo -R
squeue -t PD -o "%.10i %.9P %.12j %.8u %.2t %.10M %.20R"
scontrol show node
scontrol show partition
# 调度器
sdiag
scontrol show daemons
sacctmgr show stats
# 作业和账户
sacct -a -X --format=JobID,JobName,User,Account,State,Elapsed,AllocTRES
sreport cluster AccountUtilizationByUser Start=2026-11-01 End=2026-12-01
sshare -a
sprio
实测 sdiag、sacctmgr show stats、scontrol show daemons 可用;scontrol show stats 在 22.05 不存在,会报 invalid entity:stats,不要写进监控脚本。
指标和告警
| 层面 | 指标 | 建议 |
|---|---|---|
| slurmctld | 进程、6817 端口、scontrol ping、sdiag 调度周期 |
控制器不可达、调度周期持续升高告警 |
| slurmd | 节点状态、sinfo -R、scontrol show node |
DOWN/DRAIN 突增告警 |
| 队列 | pending 作业数、最老 pending 时间、Reason 分布 | 排队时间超过基线告警 |
| 记账 | slurmdbd 6819、sacctmgr show stats、数据库磁盘 |
DBD 不可用、队列积压告警 |
| 节点 | CPU、内存、磁盘、网络(node_exporter) | 常规容量告警 |
| GPU | DCGM exporter:温度、ECC、显存 | GPU 掉卡、ECC 告警 |
| 身份 | LDAP/SSSD、munge、SSH | 登录/认证失败突增告警 |
Prometheus/Grafana
- 节点指标用
node_exporter;GPU 用dcgm-exporter(手边没有 NVIDIA 硬件,DCGM 未实测)。 - Slurm 指标用
sckyzo/slurm_exporter(直接调 CLI)或ubccr/slurm-exporter(走 REST,注意 API 版本);本集群的实测组合是前者 + node_exporter,接 Prometheus 和 Grafana,见“Web 界面”一节。 - 告警用 Alertmanager 接 webhook;Debian 的 alertmanager 包不带 Web UI,可用
amtool或 HTTP API。 - 日志用 Promtail/Loki 或 Filebeat 收集
slurmctld.log、slurmd.log、slurmdbd.log,至少对error/fatal做告警。 - 不要只盯 GPU 利用率;队列等待时间、节点 DRAIN 原因、
slurmdbd队列积压往往更早暴露问题。
日志和调试
sudo tail -f /var/log/slurm/slurmctld.log
sudo tail -f /var/log/slurm/slurmd.log
sudo tail -f /var/log/slurm/slurmdbd.log
sudo scontrol setdebug debug2 # 临时
sudo scontrol setdebug info # 恢复
SlurmctldDebug / SlurmdDebug 长期开 debug2 会迅速放大日志;用 logrotate 或 journald 限制大小,排障完恢复 info。
配置管理
Slurm 的配置文件要全节点一致,靠手工 scp 迟早会漂移。推荐把 /etc/slurm 放进 Git,用 Ansible 或脚本分发;密钥和数据库 password 不要进 Git。
单一配置源
slurm.conf、cgroup.conf、prolog.sh、epilog.sh、health_check.sh放一个仓库。gres.conf可以按节点不同,单独模板;slurm.conf保持完全一致。munge.key、slurmdbd.conf的StoragePass、LDAP bind password 用 Ansible Vault、SOPS 或外部 credential管理,不提交明文。
分发和校验
# 所有节点比较 md5;不一致会被 slurmctld 警告
md5sum /etc/slurm/slurm.conf
# 计算节点验证 slurmd 能解析配置
sudo /usr/sbin/slurmd -f /etc/slurm/slurm.conf -C
# 配置变更后
sudo scontrol reconfigure
# 结构性变更(节点、分区、SlurmctldHost)重启 slurmctld/slurmd
slurmctld 日志里出现 “appears to have a different slurm.conf” 时,先 diff 配置文件;确认是有意为之再加 DebugFlags=NO_CONF_HASH,不要用这个参数掩盖漂移。
变更流程
- 在 Git 里改配置,跑
slurmd -C或测试集群验证。 - 备份当前
/etc/slurm和数据库。 - 维护窗口分发到所有节点,
scontrol reconfigure或重启。 - 用
sinfo、scontrol ping、srun验证;失败按备份回滚。
备份与灾难恢复
需要备份的数据
| 数据 | 路径/来源 | 频率 | 说明 |
|---|---|---|---|
| slurm.conf 及相关配置 | /etc/slurm/ | 每次变更后 | 建议纳入版本控制(Git) |
| Munge Key | /etc/munge/munge.key | 初始化后一次 | 丢失后所有节点需重新分发 |
| slurmdbd 数据库 | MariaDB slurm_acct_db | 每日 | 包含全部记账、用户关联、QoS |
| StateSaveLocation | /var/lib/slurm-llnl/ | 实时(共享 FS) | slurmctld 重启时依赖此目录恢复状态 |
数据库备份脚本
#!/usr/bin/env bash
# /etc/cron.daily/slurm-db-backup
set -euo pipefail
BACKUP_DIR="/backup/slurm"
KEEP_DAYS=30
DATE=$(date +%Y%m%d_%H%M%S)
mkdir -p "${BACKUP_DIR}"
# 逻辑备份(适合中小规模)
mysqldump --single-transaction --routines --triggers \
slurm_acct_db | gzip > "${BACKUP_DIR}/slurm_acct_db_${DATE}.sql.gz"
# 备份配置文件
tar czf "${BACKUP_DIR}/slurm_config_${DATE}.tar.gz" \
/etc/slurm/ /etc/munge/munge.key 2>/dev/null || true
# 清理过期备份
find "${BACKUP_DIR}" -name "*.gz" -mtime +${KEEP_DAYS} -delete
logger -t slurm-backup "Backup completed: ${BACKUP_DIR}/slurm_acct_db_${DATE}.sql.gz"
恢复流程
# 1. 先停掉控制器和记账服务
sudo systemctl stop slurmctld slurmdbd
# 2. 清空并恢复数据库(先确认备份文件可用)
sudo mysql -e "DROP DATABASE IF EXISTS slurm_acct_db; CREATE DATABASE slurm_acct_db;"
gunzip < /backup/slurm/slurm_acct_db_YYYYMMDD.sql.gz | sudo mysql slurm_acct_db
# 3. 恢复配置
sudo tar xzf /backup/slurm/slurm_config_YYYYMMDD.tar.gz -C /
# 4. 重启服务(按顺序)
sudo systemctl restart munge
sudo systemctl restart slurmdbd
sleep 3
sudo systemctl restart slurmctld
配置版本控制
建议将 /etc/slurm/ 纳入 Git 管理:
cd /etc/slurm
sudo git init
# slurmdbd.conf 里有 StoragePass,不要提交;密钥文件同理
printf 'slurmdbd.conf\n*.key\n' | sudo tee .gitignore >/dev/null
sudo git add -A
sudo git commit -m "initial slurm config"
# 每次变更后
sudo git add -A && sudo git commit -m "description of change"
sudo git log --oneline
配合 Ansible/Puppet 等配置管理工具分发到所有节点,确保一致性。
安全加固
基本原则
- 最小权限:登录节点不运行 slurmd;计算节点不开放 SSH 给普通用户(或仅在有运行作业时允许)。
- 网络隔离:管理网络(Slurm 通信)与存储网络分离;如条件允许,计算网络(MPI)也独立。
- 认证加固:Munge Key 权限 400,仅 munge 用户可读;定期轮换。
Munge Key 轮换
轮换 key 要在维护窗口做:先停
slurmctld和各节点slurmd,换完 key 再启动,避免运行中的作业认证失败。
# 在控制节点生成新 Key
sudo /usr/sbin/mungekey --force
# 分发到所有节点(使用配置管理工具或 scp)
for node in node01 node02 node03 node04 login-node; do
sudo scp /etc/munge/munge.key "${node}":/etc/munge/munge.key
ssh "${node}" 'sudo chown munge:munge /etc/munge/munge.key && sudo chmod 400 /etc/munge/munge.key && sudo systemctl restart munge'
done
# 最后重启控制节点 munge
sudo systemctl restart munge
限制计算节点 SSH 访问
可通过 Slurm PAM 模块限制只有在该节点上有运行作业的用户才能 SSH 登录。Debian 12 需要单独安装模块:
sudo apt install -y libpam-slurm-adopt
在计算节点的 /etc/pam.d/sshd 中添加:
account required pam_slurm_adopt.so
只加 PAM 这一行还不够。pam_slurm_adopt 在注册会话时找的是作业的 extern step;如果 slurm.conf 里没有启用容器,batch 作业只有 batch step,没有 extern step,模块会把正在跑作业的用户也当成“没有活动作业”拒绝。还需要:
ProctrackType=proctrack/cgroup
PrologFlags=Contain
LaunchParameters=use_interactive_step
Contain 会在作业分配时用 ProcTrack 插件在分配的节点上建作业容器,并隐式打开 Alloc。改完重启 slurmctld 和所有 slurmd,新提交的作业才会带 extern step。LaunchParameters=use_interactive_step 只影响 srun --pty 的交互式步骤,不能替代 Contain。
pam_systemd 会和 pam_slurm_adopt 冲突:登录时它把会话放进 user.slice/user-<uid>.slice/session-<n>.scope,模块即使放行,进程也不在作业 cgroup 里。按 Slurm 文档,要在 sshd 或 common-session 的 session 栈里注释掉它:
# /etc/pam.d/common-session
# session optional pam_systemd.so
如果需要 /run/user/$UID 或 linger,可以在 Prolog/Epilog 里对该用户执行 loginctl enable-linger / disable-linger,并自行导出 XDG_*。
生产环境建议把失败策略收紧,默认配置在模块自身出错时可能放行未受限会话:
account required pam_slurm_adopt.so action_adopt_failure=deny action_generic_failure=deny
模块版本要和 slurmd 一致。实测拿 Debian 的 22.05 pam_slurm_adopt.so 去连 25.05 的 slurmd,即使作业有 extern step 也会被判定“没有活动作业”;换成 25.05 源码 contribs/pam_slurm_adopt 编译的模块后才正常。升级 Slurm 时把 libpam-slurm-adopt 一起升级,或者从同版本源码编译。
实测(Debian 12,22.05.8 和 25.05.9):只加 PAM 时,无作业 SSH 会被拒绝,但有 batch 作业的用户也被拒绝;加上 PrologFlags=Contain 并重启后,scontrol show step <jobid> 能看到 <jobid>.extern。25.05 上保留 pam_systemd 时,SSH 能登录但 cgroup 是 user.slice/.../session-<n>.scope;注释掉 pam_systemd 后,会话落在 .../job_<id>/step_extern/user/task_0。作业结束后同一用户再 SSH 返回 Access denied by pam_slurm_adopt: you have no active jobs on this node。
文件权限审计清单
| 文件/目录 | 权限 | 属主 |
|---|---|---|
| /etc/munge/munge.key | 0400 | munge:munge |
| /etc/slurm/slurm.conf | 0644 | root:root |
| /etc/slurm/slurmdbd.conf | 0600 | slurm:slurm |
| /etc/slurm/cgroup.conf | 0644 | root:root |
| /etc/slurm/prolog.sh | 0755 | root:root |
| /etc/slurm/epilog.sh | 0755 | root:root |
| /etc/slurm/health_check.sh | 0755 | root:root |
| /var/lib/slurm-llnl/ | 0755 | slurm:slurm |
| /var/spool/slurmd/ | 0755 | slurm:slurm |
| /var/log/slurm/ | 0755 | slurm:slurm |
性能调优
调度器参数
在 slurm.conf 中可调整的关键调度参数:
# 调度器运行间隔和 backfill 策略
SchedulerParameters=default_queue_depth=128,bf_continue,bf_interval=30,bf_max_job_test=1200,bf_resolution=600,bf_window=4320
参数说明:
| 参数 | 默认值 | 建议值 | 说明 |
|---|---|---|---|
| default_queue_depth | 100 | 128 | 每次调度周期评估的作业数上限 |
| bf_continue | 禁用 | 启用 | backfill 不因找到一个可运行作业就停止 |
| bf_interval | 30 | 30 | backfill 调度间隔(秒) |
| bf_max_job_test | 500 | 1200 | backfill 单次最多尝试的作业数 |
| bf_resolution | 60 | 600 | backfill 时间分辨率(秒) |
| bf_window | 1440 | 4320 | backfill 向前看的时间窗口(分钟) |
控制器性能
当集群超过 50 个节点或并发作业数频繁超过 1000 时,控制节点需要适当调优:
# 增大消息超时(默认 10 秒)
MessageTimeout=30
# 批作业启动超时
BatchStartTimeout=30
# 作业完成后等待时间(秒,避免快速回收导致不一致)
CompleteWait=10
数据库维护
slurmdbd 的 MariaDB 在长期运行后表会膨胀,建议定期归档和优化:
# 归档超过 6 个月的作业记录。Events/Jobs/Steps 要显式写,
# 否则带 Purge* 的调用会删除数据而不归档。
sacctmgr archive dump Directory=/backup/slurm/archive/ Events Jobs Steps \
PurgeEventAfter=6months \
PurgeJobAfter=6months \
PurgeStepAfter=6months
# 表名带集群前缀,先列出实际名字再优化(建议低负载时段执行)
mysql -N -e "SHOW TABLES FROM slurm_acct_db LIKE '%job_table';"
mysql -e "OPTIMIZE TABLE \`slurm_acct_db\`.\`debian-cluster_job_table\`, \`slurm_acct_db\`.\`debian-cluster_step_table\`;"
NUMA 感知调度
对于多路 CPU 服务器,NUMA 感知调度通常能给计算密集型作业带来性能收益:
# slurm.conf
SelectType=select/cons_tres
SelectTypeParameters=CR_Core_Memory
TaskPlugin=task/affinity,task/cgroup
在提交作业时使用绑定选项:
# 绑定到 socket(每个 NUMA 域)
srun --cpu-bind=socket -n4 ./my_app
# 绑定到核心
srun --cpu-bind=cores -n4 ./my_app
常见问题与排错
快速排障流程
flowchart TD
A["Problem Detected"] --> B{"scontrol ping OK?"}
B -->|"No"| C["Check slurmctld service<br/>and logs"]
B -->|"Yes"| D{"Node State?"}
D -->|"DOWN/DRAIN"| E["scontrol show node<br/>check Reason field"]
D -->|"IDLE but job pending"| F["Check partition state<br/>sinfo, scontrol show part"]
D -->|"UNKNOWN"| G["Check slurmd + munge<br/>DNS/hosts resolution"]
E --> H{"Munge OK?"}
H -->|"No"| I["Verify munge.key<br/>time sync, permissions"]
H -->|"Yes"| J["Check slurm.conf<br/>node definition match"]
F --> K{"Resources available?"}
K -->|"No"| L["Wait or adjust<br/>resource limits"]
K -->|"Yes"| M["Check QoS/association<br/>sacctmgr show assoc"]
按症状排查
Munge 认证失败
# 检查 key 一致性(在两个节点分别执行,比较 md5)
md5sum /etc/munge/munge.key
# 检查权限
ls -la /etc/munge/munge.key
# 预期:-r-------- 1 munge munge
# 检查时间偏差(超过 300 秒会失败)
date +%s # 在各节点比较 UNIX 时间戳
# 查看 munge 日志
journalctl -u munge --no-pager -n 50
节点状态异常(DOWN/DRAIN/UNKNOWN)
# 查看节点详情和原因
scontrol show node node01
# 常见原因及处理:
# "Not responding" -> 检查 slurmd 是否运行、网络是否通
# "Low RealMemory" -> slurm.conf 中 RealMemory 大于节点实际可用内存,需调小
# "Kill task failed" -> Epilog 或 cgroup 清理失败,检查 Epilog 脚本
# 恢复节点
sudo scontrol update NodeName=node01 State=RESUME Reason=""
作业持续 Pending 不运行
# 查看作业等待原因
scontrol show job <jobid> | grep Reason
# 常见 Reason:
# Priority -> 有更高优先级的作业排队,等待即可
# Resources -> 请求的资源当前不可用
# QOSMaxJobsPerUserLimit -> 超出 QoS 限制的并发作业数
# AssocMaxJobsLimit -> 超出账户关联的作业限制
# InvalidAccount -> 用户未关联到有效的 Account
# InvalidQOS -> 用户无权使用请求的 QoS
# 检查用户关联
sacctmgr show assoc user=$USER format=Cluster,Account,User,QOS
记账/slurmdbd 不可用
# 检查 slurmdbd 服务状态
sudo systemctl status slurmdbd --no-pager
# 检查数据库连接
mysql -u slurm -p -e "SELECT 1;" slurm_acct_db
# 检查端口监听
ss -tlnp | grep 6819
# 查看 slurmdbd 日志
sudo tail -100 /var/log/slurm/slurmdbd.log
配置变更未生效
# 在控制节点执行配置重载
sudo scontrol reconfigure
# 如果 reconfigure 不够(如修改了 node 数量等结构性变更),需重启
sudo systemctl restart slurmctld
# 验证配置是否已加载
scontrol show config | grep '参数名'
日志文件汇总
| 组件 | 日志路径 | 说明 |
|---|---|---|
| slurmctld | /var/log/slurm/slurmctld.log | 调度器主日志,首要排查对象 |
| slurmd | /var/log/slurm/slurmd.log | 计算节点日志,作业执行问题排查 |
| slurmdbd | /var/log/slurm/slurmdbd.log | 记账守护进程日志 |
| munge | /var/log/munge/munged.log | 认证相关问题 |
调试时可临时提高日志级别:
# 临时调高 slurmctld 日志级别(不需要重启)
sudo scontrol setdebug debug2
# 恢复默认级别
sudo scontrol setdebug info
实测环境与结果
下面这组结果是 2026-11 在一套 PVE 9.2 集群上实际跑出来的。
| 节点 | 角色 | 配置 |
|---|---|---|
| slurm-ctl | slurmctld primary + slurmdbd + MariaDB | 2 vCPU / 2 GB,Debian 12.6 |
| slurm-ctl2 | slurmctld backup + slurmdbd backup | 2 vCPU / 2 GB,Debian 12.6 |
| slurm-node1 | slurmd | 2 vCPU / 2 GB,Debian 12.6 |
| slurm-node2 | slurmd + GVT-g vGPU | 2 vCPU / 2 GB,Debian 12.6 |
| slurm-build | 独立登录节点 + OOD | 2 vCPU / 4 GB,Debian 12.6 |
| slurm-auth | Authentik + Teleport + Prometheus/Grafana + 3×Galera | 2 vCPU / 3 GB,Debian 12.6 |
Slurm 初始版本是 Debian 12 仓库的 22.05.8-4+deb12u3,cgroup v2(cgroup2fs),主备共用 NFS 上的 StateSaveLocation,Munge 和 slurm.conf 全节点一致。跨版本升级另外在一台构建 VM 上编译了 23.11.4 和 25.05.9;Web UI 和 Authentik 联调在升级到 23.11.4 后进行。GPU 测试给 slurm-node2 挂了 GVT-g vGPU;登录节点/OOD 在 slurm-build;Authentik、Teleport、Prometheus/Grafana 和三个 Galera 实例在 slurm-auth。Galera 三个实例跑在同一台 VM 上,是为了在现有资源里验证故障转移,生产要分散到三台机器。
验证过的点:
- 多节点调度:
srun -N2 -n4 hostname在slurm-node1/slurm-node2上各跑到 2 个任务。 - cgroup v2 内存限制:
--mem=100M的作业内尝试分配 300 MB,作业以OUT_OF_MEMORY结束,ExitCode=0:125。 - CPU 绑定:
srun -c1内Cpus_allowed_list: 0,-c2为0-1,说明ConstrainCores=yes生效。 - 记账与报表:
sacct能查到已完成作业的 JobID、State、NodeList、Elapsed;sreport cluster AccountUtilizationByUser和sshare -a能按账户输出用量/公平份额。 - QoS:
MaxWall、MaxTRESPU、MaxJobsPerUser超限时作业进入PENDING,Reason 分别为QOSMaxWallDurationPerJobLimit、QOSMaxCpuPerUserLimit、QOSMaxJobsPerUserLimit;不是提交阶段直接报错。 limits的必要性:只写AccountingStorageEnforce=associations,qos时,5 小时作业能绕过 4 小时的 QoSMaxWall;加上limits并重启slurmctld后才进入 Pending。- 主备切换:默认
SlurmctldTimeout=120,从停掉 primary 到 backup 日志出现Running as primary约 2 分 46 秒;scontrol ping仍按配置显示 primary/backup,不能用来判断当前 active 角色。原 primary 重启后会重新成为 primary。 - Prolog/Epilog:按 job ID 创建的
/tmp/slurm-job-<id>在作业运行期间存在,Epilog 后删除;没有使用pkill -u这类会误杀同用户其它作业的写法。 - 健康检查:脚本返回非零本身不会 DRAIN;脚本里显式执行
scontrol update NodeName=$(hostname -s) State=DRAIN Reason=...后,节点才进入IDLE+DRAIN。 - Lmod:Debian 12 的
lmod 8.6.19可用;srun -N2 -n2 bash -lc 'module load hello/1.0; hello'在两个计算节点都加载到同一个 module。 - 多租户:
classA/classBaccount、AllowAccounts分区、GrpTRES限额都生效;错误 account 提交到分区后以Job's account not permitted to use this partition (...)结束,超过账户GrpTRES的作业 Pending,Reason 为AssocGrpCpuLimit。 - LDAP/SSSD:OpenLDAP + LDAPS 自签证书;在 LDAP 里新建
stu01(不在节点上useradd),getent passwd、pamtester login(LDAP password认证)、SSH password登录、pam_mkhomedir自动建家目录、srun/sbatch、sacct全部通过。刚建完 LDAP 用户时srun报Invalid account or account/partition combination specified,sacctmgr add user stu01 Account=classA后正常。Prolog 用SLURM_JOB_UID/GID才适配 LDAP 的主组students。 - CephFS:测试集群的 CephFS(本文示例名
slurmfs)建client.slurm,三个节点通过 fstab 挂载/cephfs,srun -N2跨节点写同一个目录成功。secretfile需要装ceph-common,OSD cap 用tag cephfs data=<文件系统名>,写错时小文件能建、写数据报EPERM。 - GPU/GRES 与基准:PVE 9.2 的 Intel GVT-g 把 HD 530 以
i915-GVTg_V5_4挂给slurm-node2,Slurm 显示Gres=gpu:1,--gres=gpu:1作业的AllocTRES包含gres/gpu=1;不带--gres时clinfo看不到 OpenCL 设备。clpeak、sysbench、mbw、stress-ng、HPCC 的实际数据和混合负载见“CPU、GPU 与混合负载基准”。 - Slurm-web:Slurm 23.11.4 + Slurm-web 3.3.0,从 Rackslab 源安装,认证接 OpenLDAP;Dashboard、Jobs 和作业详情都能看到节点、作业和
--gres=gpu:1的 Requested/Allocated,截图见“Web 界面”的“Slurm-web 3.3.0 实测”。 - Authentik:Authentik 2024.12.3 的 LDAP Outpost 实测,SSSD 用 LDAPS +
ldap_user_name=cn能getent和pamtester;Slurm-web 改指向 Authentik LDAP 后,stu01登录成功,Authentik 用户列表能看到这次登录。关键坑是 LDAP Provider 的authorization_flow必须用 authentication flow,不能用 authorization flow。 - 独立登录节点:
slurm-build(10.31.0.229)只装客户端和 munge;stu01执行sinfo、srun -A classa -n1 hostname(返回slurm-node1)、sbatch --chdir=/tmp(job 74 COMPLETED)正常。默认在/home/user提交时 job 73 因输出文件无权限失败;客户端版本要和控制器保持一致,本次用的是 23.11 的客户端。 - Galera + slurmdbd 主备:3 个 MariaDB 10.11/Galera 4 实例 + HAProxy;停掉
galera@1后集群剩 2 节点,job 76 仍能记账;恢复后回到 3 节点。停掉主slurmdbd后,slurmctld走AccountingStorageBackupHost,job 77 由备份 dbd 记录,sacct -j 77可查。 - Teleport:Teleport 18.10 CE,本地用户
labadmin完成密码 + TOTP,slurm-build以 node 角色注册;Web 终端以stu01登录并执行sinfo,会话日志落在/var/lib/teleport/log/。Teleport 18 CE 的 OIDC connector 返回OIDC is only available in Teleport Enterprise,Authentik OIDC 没有跑通。 - Open OnDemand:OOD 4.0.11 + Authentik OIDC,
stu01登录 Dashboard,Active Jobs 看到 Job Composer 提交的 job 80(COMPLETED)。Job Composer 在 HTTP 下因 Secure session cookie 不保存报 422,切到 HTTPS 后创建并提交成功;默认模板目录没有脚本,手动补了main_job.sh。 - Prometheus/Grafana/Alertmanager:SckyzO
slurm_exporter1.8.6 + node_exporter,Prometheus 2.42 + Alertmanager 0.25 + Grafana 13.3.1;DRAIN GPU 节点后SlurmNodeDownfiring,webhook 收到 firing/resolved,Grafana 概览显示 2 节点、1 个运行作业、1 个 DRAIN。State=DOWN会因ReturnToService=2自动回 IDLE,测试改用 DRAIN。 pam_slurm_adopt:只加 PAM account 行时,有 batch 作业也会被拒绝;加上PrologFlags=Contain并重启后,作业出现.externstep。25.05 上还必须用同版本编译的 PAM 模块,并禁用pam_systemd,否则会话落在session-<n>.scope而不是job_<id>/step_extern;作业取消后同一用户 SSH 返回“no active jobs”。- 跨版本升级:22.05.8 的
convert_version_table是 12,直接启动 25.05.9 的slurmdbd报Database schema is too old for this version of Slurm to upgrade.(25.05 的MIN_CONVERT_VERSION=14)。用 23.11.4 的slurmdbd先转到 14,再用 25.05.9 转到 16。25.05 的slurmctld读 22.05 的StateSaveLocation报assoc_usage state ... got 9728 need >= 10240 <= 11008,加-i放弃旧状态后启动,恢复 0 节点/0 作业;之后sinfo、srun -N2 -n2、sbatch、sacct正常,旧的记账记录还在。22.05 的srun连 25.05 控制器会报Invalid Protocol Version 11008,客户端要一起升级;SelectType=select/cons_res也要先改成select/cons_tres,25.05 不再提供cons_res插件。 - 日常管理:节点 DRAIN/RESUME、分区 DOWN/UP、
scontrol hold/release/requeue都验证过;hold后Reason=JobHeldAdmin,requeue后显示PENDING BeginTime。 - 监控/配置:
sdiag、sacctmgr show stats、scontrol show daemons、slurmd -C可用;scontrol show stats在 22.05 不存在。
CPU、GPU 与混合负载基准
测试工具和输入都来自 Debian 12 仓库或对应项目的标准输入,版本和参数固定:
clpeak 1.1.2:OpenCL 设备带宽、单/双/半精度和整数吞吐、kernel 延迟。sysbench 1.0.20:CPU 质数计算、内存写带宽。mbw:memcpy / dumb / mcblock 三种内存拷贝。stress-ng 0.15.06:2 个 CPU stressor 的 bogo ops/s。hpcc 1.5.0:HPL、STREAM、DGEMM、FFT 等 HPC Challenge 测试;输入用/usr/share/doc/hpcc/examples/_hpccinf.txt改成N=2048, NB=64, P=2, Q=1,跑 2 个 MPI 进程。
CPU 单机结果:
| 测试 | 结果 |
|---|---|
| sysbench CPU,1 线程 | 429.07 events/s |
| sysbench CPU,2 线程 | 797.57 events/s |
| sysbench memory,1 MiB block,10 GiB write | 17085.28 MiB/s |
| mbw MEMCPY / DUMB / MCBLOCK | 6245.9 / 9234.2 / 12643.6 MiB/s |
| stress-ng,2 CPU,20s | 2589.90 bogo ops/s |
HPCC(N=2048,2 MPI 进程):
| 项目 | 结果 |
|---|---|
| HPL | 3.501 Gflops |
| STREAM Copy / Scale / Add / Triad | 17.97 / 14.18 / 15.62 / 17.16 GB/s |
| Single DGEMM | 2.053 Gflop/s |
| Single FFT | 3.302 Gflop/s |
GVT-g vGPU(i915-GVTg_V5_4,512 MB aperture,23 个 compute units,1050 MHz):
| 项目 | 结果 |
|---|---|
clpeak 单精度 |
323.09 GFLOPS |
| 半精度 | 638.76 GFLOPS |
| 双精度 | 81.39 GFLOPS |
| 整数 | 107.73 GIOPS |
| 全局内存带宽 float / float4 | 18.43 / 19.04 GB/s |
| transfer write / read | 10.01 / 9.12 GB/s |
| kernel launch latency | 1209.86 us |
多节点 CPU 和混合负载:
srun -N2 -n2 -c1两个节点各跑 sysbench:slurm-node1 429.27 events/s,slurm-node2 433.06 events/s。sbatch -c2 --gres=gpu:1同时跑 sysbench(1 线程)和clpeak --global-bandwidth --compute-sp:CPU 从单跑的 429.07 降到 233.46 events/s,GPU 仍有 322.68 GFLOPS、19.43 GB/s;作业的AllocTRES是cpu=2,gres/gpu=1,mem=1800M,说明 CPU 和 GPU 资源都按请求分配了。- GPU-only 的
clpeak --all-tests作业跑了 2 分 49 秒,sacct的AllocTRES包含gres/gpu=1;同一节点不带--gres的作业clinfo看不到 platform。
这些数字是 2 vCPU 虚拟机 + 512 MB vGPU 的小规模结果,HPL 的 N=2048 也远小于正式 HPL 调优规模,不能用它推断物理机的峰值;但用来验证“GRES 分配、设备隔离、CPU/GPU 并发时的相对变化”足够。
没有做端到端验证的部分:
- NVIDIA GPU 路径:手边没有 NVIDIA 硬件,
/dev/nvidia*、NVIDIA 驱动、DCGM 和nvidia-smi都没有实测,文章里的 NVIDIA 写法仅作参考。 - Teleport 的 Authentik OIDC/SAML:Teleport 18.10 社区版返回
OIDC is only available in Teleport Enterprise;本地用户 + TOTP + Web 终端已测,OIDC 这条没跑通。 - OOD 的交互式应用(Jupyter、VS Code 等)没有配置;Dashboard、Active Jobs 和 Job Composer 提交已测。
参考
- Slurm 官方文档首页
- 配置向导(交互式生成 slurm.conf)
- slurm.conf 参数手册
- cgroup 集成指南
- 记账与 slurmdbd 配置
- 高可用配置
- QoS 与资源限制
- Prolog/Epilog 脚本
- 调度器参数调优
- Slurm REST API
- Slurm-web 文档
- Authentik 文档
- Open OnDemand 文档
- Teleport 文档
- SckyzO slurm_exporter
- Prometheus
- Grafana
- clpeak
- sysbench
- mbw
- stress-ng
- HPC Challenge (HPCC)
- Proxmox 文档:Mediated Devices (vGPU, GVT-g)
如果你觉得这篇文章对你有所帮助,欢迎赞赏~
赞赏