INCIDENT-20260918-Slurm 26.05 部署排障¶
本文档是排障台账与交接记录,不是正式事故复盘报告。 变更档案见
SOP.md;日常运维见RUNBOOK.md。
一、概要¶
| 项 | 内容 |
|---|---|
| 发生时间 | 2026-09-18 05:00 – 13:30(UTC+8) |
| 等级 | 非生产事故(新集群部署阶段,5 台初始为空机,无业务与数据受影响) |
| 影响面 | 仅阻塞本次部署进度,集群未能按时交付 |
| 当前状态 | 已恢复。部署完成,主备双 UP,3 计算节点 idle,作业提交验证通过 |
一句话概括:新环境(Rocky 9.8 + cgroup v2)与部署工具原假设(CentOS 7 + cgroup v1)差异过大, 连续触发 10 个阻塞点,逐个定位并修复,其中 6 个已固化为部署器的自动处理能力。
二、影响范围¶
- 业务:无。目标 5 台机器在本次部署前是空机,未承载任何业务。
- 用户:无。集群尚未交付使用。
- 数据:无损坏、无丢失。部署过程中创建的数据库
slurm_acct_db为新建库; 宿主机/etc/exports的改动已备份且未影响同机 k8s 的既有导出。 - 附带影响:排障期间在宿主机
192.168.31.249上新增了一条 NFS 导出 (/data/nfs/slurm-state),并在/etc/exports留有 2 个备份文件(已登记台账)。
三、时间线¶
| 时间 | 事件 |
|---|---|
| 05:07 | 第 1 次部署启动,阶段 1 装包失败:dnf 报 Unable to find a match: munge-devel |
| 05:12 | 启用 CRB 仓库后重跑,阶段 2 数据库初始化成功(建库/建号/授权) |
| 05:19 | 阶段 3 编译失败:tar: command not found(.18 未装 tar) |
| 05:25 | 补齐 tar/gzip 后重跑,configure 报 mysql_config not found |
| 05:26 | 修正 --with-mysql_config 传参(应为目录而非文件路径),configure 通过;6 分钟后编译完成 |
| 05:34 | slurmdbd 启动失败:Failed to access /var/run/munge/munge.socket.2 |
| 05:40 | 定位为 munge key 权限(640)被 munged 拒绝;改 400 后 munge 启动 |
| 05:43 | slurmctld 启动失败:fatal: No Assoc usage file ... to recover |
| 05:50 | 定位到需以 -i 初始化 state;同时发现 key 一致时会提前 return、跳过"确保 munge 运行" |
| 05:52 | 以 -i 启动后新 fatal:Partition interactive has an invalid qos |
| 05:58 | 调整启动顺序(QoS 先于 slurmctld)后 slurmctld 起来 |
| 06:04 | slurmd 启动失败:wait-for-slurmctld.sh 连不上 slurm-master-01:6817 |
| 06:10 | 定位为 firewalld 只放通 ssh;部署器加入端口放通 |
| 06:23 | slurmd 再次失败:libhwloc.so.15: cannot open shared object file |
| 06:31 | 补齐运行库后仍失败:cannot create cgroup context for cgroup/v2 |
| 06:40 | 定位为缺 dbus-devel 导致未编译 cgroup_v2.so;补依赖重编译 |
| 06:50 | 各计算节点仍报缺插件(未重新分发);修正分发判据 |
| 12:43 | 部署首次完整成功:主备双 UP、3 节点 idle、作业可提交 |
| 12:45 | 开始修复性能问题:宿主机新建 async 专用 NFS 导出 |
| 13:04 | 完成共享存储迁移,fsync 由 500–800ms 降至 9–12ms |
| 13:20 | 修复启动告警(MailProg / http_parser)与幂等缺陷,复跑验证零变更 |
四、根因¶
以下 10 个阻塞点按"环境差异 / 配置语义 / 代码缺陷"三类归因,均附证据。
A. 环境差异类(4 项)¶
A1. munge-devel 不在默认仓库
- 证据:
dnf install -y munge munge-devel ...→Error: Unable to find a match: munge-devel - 根因:Rocky/RHEL 9 的
-devel包集中在 CRB 仓库,该仓库默认disabled(dnf repolist --all显示crb ... disabled)
A2. tar/gzip 未安装
- 证据:
tar: command not found - 根因:Rocky 9 最小化安装不含
tar/gzip,而打包与解压依赖它们
A3. firewalld 只放通 ssh
- 证据:.16 上
ss -lntp | grep 6817显示监听0.0.0.0:6817,但 .18 侧/dev/tcp/slurm-master-01/6817返回 CLOSED;firewall-cmd --list-all仅cockpit dhcpv6-client ssh - 根因:Rocky 默认启用 firewalld 且不放通 6817/6818/6819
A4. 运行库随编译环境缺失
- 证据:
ldd slurmd | grep 'not found'→libhwloc.so.15; 修正检查范围后又发现libhttp_parser.so.2、libibmad.so.5、libibumad.so.3 - 根因:编译节点的
-devel包不会随产物分发到计算节点
B. 配置语义类(3 项)¶
B1. --with-mysql_config 应传目录
- 证据:
configure: error: *** mysql_config not found - 根因:Slurm 的该参数接收目录,它在该目录下查找
mysql_config/mariadb_config; 传入二进制文件路径会导致探测失败
B2. munge key 权限必须 400
- 证据:
munged: Error: Keyfile is insecure: "/etc/munge/munge.key" should not be readable or writable by group or world - 根因:误判"SlurmUser 需要读 key"而设为 640。实际 Slurm 经 munge socket 认证, 不需要直接读 key,munged 强制要求 key 仅属主可读
B3. QoS 必须先于 slurmctld 存在
- 证据:
fatal: Partition interactive has an invalid qos (interactive), please check your configuration - 根因:
slurm.conf的PartitionName引用了 QOS,启动时会校验其存在性; 原实现把 QoS 初始化放在启动之后,形成死锁(启动需要 QoS,建 QoS 需要 slurmdbd)
C. 代码缺陷类(3 项)¶
C1. 状态判据过浅,出现"假一致"
- 证据(分发):
.19上lib/slurm/无cgroup_v2.so,但部署器判定"目标版本已安装"而跳过分发 - 证据(编译):
WITH_LIBHTTP_PARSER_TRUE='#'(未启用),但 install_dir 已存在且版本号匹配, 使编译被跳过 - 根因:判据只看版本号与目录存在性,未校验产物内容/构建输入
C2. 零变更检测遗漏关键状态
- 证据(服务):
sync_status判定 19 条全 SKIP、直接退出,但当时slurmdbd仍处于 restart 循环 - 证据(挂载):挂载源已变(
/srv/nfs/k8s-hdd→/data/nfs/slurm-state), 但只判断mountpoint -q为 MOUNTED 即 SKIP - 根因:
sync_status只检查文件/版本,不检查服务运行态与挂载源
C3. 渲染结果含时间戳,破坏幂等
- 证据:连续两次部署,第二次仍报"配置漂移,需重写";
渲染的
slurm.confbanner 含# 生成时间: <每次不同的时间戳> - 根因:配置 SHA256 每次都变,漂移检测永久判为有变更,幂等彻底失效
附带发现(非阻塞,但会造成静默失效)¶
D1. timer 用 Requires=slurmctld.service
- 证据:一次部署(含 slurmctld 重启)后
systemctl is-active slurm-cluster-health.timer→inactive - 根因:
Requires是强依赖,slurmctld 停止会连带停止 timer,健康巡检静默失效(无任何报错)
D2. 凭据经命令行泄露到日志
- 证据:部署日志中出现
mysqldump ... -u slurm -p'<明文>'与 base64 编码的 cnf 内容 - 根因:早期实现用命令行传参;虽为内网测试环境,仍属必须消除的隐患
五、处置过程¶
| 问题 | 处置动作 | 是否已固化为自动能力 |
|---|---|---|
| A1 CRB 仓库 | 检测到 -devel 包时自动 dnf config-manager --set-enabled crb |
✅ 是 |
| A2 tar/gzip | 加入 base_packages,所有节点安装 |
✅ 是 |
| A3 firewalld | 按 slurm.firewall_ports 自动放通并 reload |
✅ 是 |
| A4 运行库 | ldd 探测 sbin/* + lib/slurm/*.so,dnf repoquery --whatprovides 反查包名安装 |
✅ 是 |
| B1 mysql_config | 探测 mariadb_config/mysql_config 并取其目录 |
✅ 是 |
| B2 munge key | 固定 chown munge:munge + chmod 400;且无论 key 是否一致都确保 munged 运行 |
✅ 是 |
| B3 QoS 顺序 | 启动顺序固定为 slurmdbd → cluster/QoS/账户 → slurmctld → slurmd | ✅ 是 |
| C1 假一致 | 引入编译输入指纹(版本+依赖+configure 参数),变化即重编译重分发 | ✅ 是 |
| C2 零变更遗漏 | sync_status 增加服务运行态、挂载源比对、配置内容漂移检测 |
✅ 是 |
| C3 时间戳 | 移除渲染结果中的时间戳,并在代码中写明约束 | ✅ 是 |
| D1 timer 依赖 | 改 Requires= → Wants=;巡检同时校验 enabled 与 active |
✅ 是 |
| D2 凭据泄露 | 数据库操作改 0600 临时 cnf 传参;文件写入改走 SFTP;已清理含凭据日志 | ✅ 是 |
| 首次 state 初始化 | 一次性 systemd override 注入 slurmctld -i,完成后立即移除 |
✅ 是 |
| 共享存储性能 | 宿主机新建 async 专用导出(避开 k8s 共用的卷) | ⚠️ 手工操作,已写入 SOP 第 5.6 节 |
止血与回滚动作:本次未执行整体回滚。每轮失败均发生在部署早期(装包、编译、服务启动),
失败即中止且不切换 symlink,因此未对系统造成半成品状态;期间仅手工清理过 1 处测试残留
(.16 上试验 -i 时创建的 systemd override 目录)。
六、恢复验证¶
# 集群与主备
/usr/local/slurm/bin/sinfo -N -o '%N %T %C' | sort -u
# 预期:slurm-work-01/02/03 均 idle
/usr/local/slurm/bin/scontrol ping
# 预期:Slurmctld(primary) at slurm-master-01 is UP / (backup) at slurm-master-02 is UP
# 共享存储
findmnt -o TARGET,SOURCE,FSTYPE /mnt/slurm-shared
# 预期:/mnt/slurm-shared 192.168.31.249:/data/nfs/slurm-state nfs4
# 告警归零
journalctl -u slurmctld --since '10 min ago' --no-pager | grep -c 'Saving to StateSaveLocation' # 0
journalctl -u slurmctld -n 50 --no-pager | grep -cE 'http_parser|plugin_load' # 0
# 端到端作业
cd /tmp && printf '#!/bin/bash\nhostname\necho JOB_OK\n' > t.sh
/usr/local/slurm/bin/sbatch -N1 -o /tmp/t_%j.out t.sh && sleep 15 && cat /tmp/t_*.out
/usr/local/slurm/bin/sacct -n -P -o JobID,State,ExitCode --starttime today | tail -1
# 预期:COMPLETED 0:0
# 幂等
cd /home/rain/Documents/slurm_ins
.venv/bin/python main.py --config config/slurm_deploy.yaml 2>&1 | tail -3
# 预期:零变更,无需部署(全跳过)
实测结果:以上全部符合预期;共享存储 fsync 由 500–800ms 降至 9–12ms。
七、复盘¶
有效的做法
- 先定位再动手:每次失败都先取证据(journalctl 原文、
ldd输出、config.log 变量值), 避免了"猜测式重试"。例如 http_parser 问题是二次定位(先装 devel 包、再发现运行库缺失)才见底。 - dry-run 前置:
--dry-run会真实读取节点状态,因此能提前看到"挂载源变更""配置漂移"这类 只靠静态阅读发现不了的项。 - 幂等复跑作为验收手段:正是"第二次仍报配置漂移"暴露了时间戳缺陷;
正是"服务没起来却判零变更"暴露了
sync_status过浅。 - 自动补齐而非固定清单:运行库用
ldd+dnf repoquery推导,而非维护包名清单, 本次一次性发现并补齐了 4 个缺失库。
拖慢恢复的因素
- 每轮重跑成本高:
sync_status串行查询 5 个节点、单轮约 5–6 分钟, 加上编译 8 分钟,导致验证循环长。若早期就并发化查询,可显著缩短。 - 判据修复存在连带性:修好"运行库检查覆盖插件"后,又暴露"分发判据不校验插件", 属于同类问题分两次才发现——根因是缺少统一的"产物完整性"概念。
- cgroup v2 的报错信息不够直白:
cannot create cgroup context未指出缺的是插件还是库, 需要翻config.log与插件目录才能定位。
八、行动项¶
| 事项 | 责任人 | 期限 | 状态 |
|---|---|---|---|
把 sync_status 的节点查询并发化,缩短单轮巡检耗时 |
部署执行人 | 下次迭代 | 待办 |
补一次 --rollback 的真实演练(当前仅验证了幂等,未验证回滚) |
部署执行人 | 2026-09-25 | 待办 |
评估 slurmdbd 双活方案,消除记账单点 |
部署执行人 | 按需 | 待办 |
| 在 RUNBOOK 中补充"共享存储单点"的容量与故障预案 | 部署执行人 | 2026-09-25 | 待办 |
清理宿主机 /etc/exports 的 2 个历史备份文件(对照 backup/README.md) |
用户 | 自行决定 | 待确认 |
清理集群侧 /var/backups/slurm/ 的 66 个历史备份(对照 backup/README.md) |
用户 | 自行决定 | 待确认 |
来源:
/home/rain/Documents/slurm/slurm_ins/docs/INCIDENT-20260918-slurm-26.05部署排障.md| 最后更新:2026-09-24 21:30(由build/sync.py同步,请勿在站点侧修改)