SOP — Lustre 挂载自愈扩面(纳入 LSF 执行节点 .25–.27)¶
- 主题目录:
lustre_mount_selfheal_extend_20261007/ - 执行日期:2026-10-07
- 类型:C 类变更(自愈对象扩面 + 部署器缺陷修复 + 节点间免密补齐)
- 关联:
lustre_insHANDOFF §3.1 #17(本变更结案);slurm_insHANDOFF §3 #16–17 移交项
1. 背景¶
机制 B(控制节点 .16 上的 slurm-cluster-health.timer,15 min)会巡检 Lustre 客户端挂载并在 failed 时自愈,但巡检对象只含 Slurm 侧节点(.18/.19/.20/.28)。LSF 执行节点 .25–.27 与它们同源配置、同批于 2026-09-29 挂载失败,却不在巡检范围内,潜伏 8 天无人察觉(lustre_ins HANDOFF §3.1 #14/#17)。
执行中另外查出两个根因(均本次修复):
sync_status()不比对cluster.json:该文件只在execute()阶段下发,配置源改动会被「零变更 → 幂等跳过」整段吞掉 → 改配置静默失效。首次 dry-run 即报「零变更」暴露此问题。- 节点间免密缺失 + 探测失败被静默吞掉:
.16/.17→.25–.27的 root 免密不存在;而_ensure_lustre_mounts()对 SSH 探测失败与「非 failed」的判据混同(都continue),导致自愈形同虚设且无任何痕迹——注入验证时首次巡检完全不报,才查出此点。
连带纠正一处历史误判:此前把「
Warning: Permanently added ...出现在首行」当作免密成功(head -1只取到警告行),实际第二行是Permission denied (publickey)。探测只取首行会误判。
2. 目标¶
| 项 | 可验证状态 |
|---|---|
| 巡检对象 | .16 上 /etc/slurm-health/cluster.json 的 lustre_guards 含 7 台(原 4 台 + .25/.26/.27) |
| 自愈有效 | 对 .25–.27 任一制造 failed,巡检能 ⚠️ 触发并 ✅ 恢复 |
| 免密 | .16/.17 → .25/.26/.27 root 免密可用(严格模式亦通过) |
| 判据三分 | 探测失败(SSH 不可达)与「非 failed」分别报出,不再静默 |
| 幂等 | 复跑零变更;注入后已还原,无残留 |
| 边界 | 不改自愈动作逻辑、不改调度状态、不重启节点 |
3. 前置条件¶
- root 免密可达
.16/.17(控制节点)与.25–.27(LSF 执行节点) .16上slurm-cluster-health.timer已enabled + active(机制 B 已就位)- 工程 venv:
/home/rain/Documents/slurm/slurm_ins/.venv/ - 注入验证前须确认目标节点无在跑作业:本次核
.27(bjobs -u all -m lsf-work-03→No unfinished job found)
4. 影响范围¶
| 对象 | 变更内容 | 停服 | 窗口 |
|---|---|---|---|
.16 / .17 |
下发新的 cluster.json(+3 台)与 cluster_health_check.py(判据三分) |
否 | 秒级 |
.16/.17 → .25–.27 |
追加 root 公钥到 authorized_keys(.17 另补 known_hosts) |
否 | 秒级 |
.27 |
注入验证:临时改 fstab 挂载源 → failed → 自愈恢复(期间 /mnt/lustre 不可用约 5 分钟) |
否 | 约 5 min |
- 不重启任何节点、不动 Lustre 服务端、不改自愈动作逻辑;
.18–.20/.28行为不变 - 注入窗口已确认
.27无在跑作业
5. 分步操作¶
步骤 1:扩展自愈对象清单(工程侧)¶
health_assets.py::lustre_guards() 由「compute + submit」扩为「compute + submit + health_ensure.lustre_extra_guards」——后者用于不在本工程 nodes 清单内、但同源配置的主机。
# 配置侧(config/slurm_deploy.yaml 的 slurm.health_ensure 段)
# lustre_extra_guards:
# - {hostname: "lsf-work-01", ip: "192.168.31.25"}
# - {hostname: "lsf-work-02", ip: "192.168.31.26"}
# - {hostname: "lsf-work-03", ip: "192.168.31.27"}
坑:lustre_guards() 的去重键是 ip,清单里重复 IP 会被静默去重——新增对象时须核对 ip 字段。
步骤 2:补 sync_status() 对 cluster.json 的比对(缺陷修复)¶
该文件此前只在 execute() 下发,配置改动会被幂等短路吞掉。修法:在 watchdog 分支内按同一口径(sha256 比对 /etc/slurm-health/cluster.json)登记 ChangeRecord。
# 等价核对命令(部署器对每台控制节点执行的判据)
sha256sum '/etc/slurm-health/cluster.json' | awk '{print $1}'
预期:与本地渲染结果不一致时登记 [CONFIG],dry-run 应显示「待执行变更 ≥ 1」。
失败判断:dry-run 仍报「零变更」→ 比对未生效,不得继续。
步骤 3:探测失败三分开报(缺陷修复)¶
slurm_health_ensure/cluster_health_check.py::_ensure_lustre_mounts() 原判据:
systemctl is-failed mnt-lustre.mount >/dev/null 2>&1; echo RC=$?
原来仅以 "RC=0" not in out 判断,把「SSH 不通(输出为空)」也当作「非 failed」静默跳过。现增加 "RC=" not in out 分支并记 WARNING。
# 手工核对某台是否真的可探测(注意:不要只看首行,known_hosts 警告会盖住错误行)
ssh -o BatchMode=yes root@<控制节点> \
"ssh -o BatchMode=yes -o ConnectTimeout=5 root@<目标机> \
'systemctl is-failed mnt-lustre.mount >/dev/null 2>&1; echo RC=\$?'"
预期:输出 RC=0(failed)或 RC=1(非 failed);输出为空或含 Permission denied 即免密缺失。
步骤 4:补齐节点间 SSH 免密¶
# ① 取控制节点公钥(.16 与 .17)
ssh root@192.168.31.16 'cat /root/.ssh/id_*.pub' | head -1 > /tmp/k16.pub
ssh root@192.168.31.17 'cat /root/.ssh/id_*.pub' | head -1 > /tmp/k17.pub
# ② 备份并追加到三台目标机
for t in 25 26 27; do
scp /tmp/k16.pub /tmp/k17.pub root@192.168.31.$t:/tmp/
ssh root@192.168.31.$t "cp -n /root/.ssh/authorized_keys /root/.ssh/authorized_keys.bak.\$(date +%Y%m%d-%H%M%S); \
mkdir -p /root/.ssh && chmod 700 /root/.ssh && touch /root/.ssh/authorized_keys; \
cat /tmp/k16.pub /tmp/k17.pub >> /root/.ssh/authorized_keys; \
sort -u /root/.ssh/authorized_keys -o /root/.ssh/authorized_keys; \
chmod 600 /root/.ssh/authorized_keys"
done
# ③ `.17` 首次连接需写入 known_hosts(否则严格模式报 Host key verification failed)
ssh root@192.168.31.17 'for ip in 25 26 27; do \
ssh -o StrictHostKeyChecking=no -o BatchMode=yes root@192.168.31.$ip hostname; done'
坑:authorized_keys 必须 600、目录 700,否则 sshd 拒绝;sort -u 后写回可去重。巡检脚本用 StrictHostKeyChecking=no,故 known_hosts 只影响人工核查。
步骤 5:预演与下发¶
cd /home/rain/Documents/slurm/slurm_ins
.venv/bin/python main.py --config config/slurm_deploy.yaml --health-ensure --dry-run
.venv/bin/python main.py --config config/slurm_deploy.yaml --health-ensure
.venv/bin/python main.py --config config/slurm_deploy.yaml --health-ensure # 幂等复跑
预期:第 1 次「待执行变更 ≥ 1」(cluster.json / cluster_health_check.py),第 3 次「待执行 0、幂等跳过」。
步骤 6:验证(见第 6 章)¶
6. 验证¶
① 清单生效
ssh root@192.168.31.16 'python3 -c "import json;d=json.load(open(\"/etc/slurm-health/cluster.json\"));print([g[\"ip\"] for g in d[\"lustre_guards\"]])"'
实测:['.18', '.19', '.20', '.28', '.25', '.26', '.27'](7 台)✅
② 端到端自愈(注入验证,核心验收)
| 阶段 | 操作 | 实测结果 |
|---|---|---|
| 注入 | .27 挂载源改为 192.168.31.199@tcp:/edafs(不存在)→ systemctl start |
start_rc=1、is_failed=failed ✅ |
| 巡检(源仍错) | --fix |
⚠️ lsf-work-03: mnt-lustre.mount 处于 failed,执行自愈 + ❌ 自愈失败,需人工介入 ✅ |
| 还原 | cp /etc/fstab.bak.inject.* /etc/fstab(不手动 restart,保持 unit 待自愈) |
fstab 复原、fstab_lines=1 ✅ |
| 巡检(源已对) | --fix |
⚠️ lsf-work-03: ... 执行自愈 + ✅ lsf-work-03: /mnt/lustre 已恢复 ✅ |
| 终态 | .27 |
active、选项含 noatime、rain01 写入 WRITE_OK ✅ |
③ 判据三分(负向验证):临时把 cluster.json 中 .27 改为不可达 .199 后跑 --fix →
⚠️ lsf-work-03(192.168.31.199): 无法探测 mnt-lustre.mount(SSH 不可达?)——已跳过,请检查控制节点到该机的免密
随后已还原(残留 199 计数 = 0)✅
④ 幂等:部署器复跑「待执行 0、幂等跳过 5~14」;.27 复跑 systemctl start 零变更。
7. 回滚¶
备份位置(逐条见 backup/README.md;远程原位 + 本目录回传副本):
| 备份 | 位置 |
|---|---|
| 工程三文件 | backup/slurm_ins/(health_assets.py、config/slurm_deploy.yaml、slurm_health_ensure/cluster_health_check.py) |
.25–.27 authorized_keys |
backup/<IP>/root/.ssh/authorized_keys.bak.20261007-092641(远程原位同名) |
.27 注入前 fstab |
backup/192.168.31.27/etc/fstab.bak.inject.20261007-092355(远程原位同名) |
.16 cluster.json |
/root/cluster.json.bak.20261007-093035(远程原位,负向验证用,已还原) |
# A. 回滚工程文件
cd /home/rain/Documents/slurm/slurm_ins
ts=20261007-092159 # 见 backup/slurm_ins/ 实际时间戳
cp lustre_mount_selfheal_extend_20261007/backup/slurm_ins/health_assets.py.bak.$ts health_assets.py
cp lustre_mount_selfheal_extend_20261007/backup/slurm_ins/config/slurm_deploy.yaml.bak.$ts config/slurm_deploy.yaml
# B. 回滚管理端(恢复旧脚本与旧 cluster.json)
.venv/bin/python main.py --config config/slurm_deploy.yaml --health-ensure
# C. 回滚目标机免密
for t in 25 26 27; do
ssh root@192.168.31.$t "cp /root/.ssh/authorized_keys.bak.20261007-092641 /root/.ssh/authorized_keys"
done
回滚后验证:cluster.json 的 lustre_guards 回到 4 台;.16 巡检脚本恢复旧版;.25–.27 的 authorized_keys 无 .16/.17 公钥。
回滚触发条件(量化):① 部署器 dry-run 报出预期外的变更;② 复跑非零变更;③ 巡检脚本报错或对 .18–.20 误报;④ 任一目标机 /mnt/lustre 由 active 变非 active。任一命中即回滚。
8. 风险说明¶
| 风险 | 缓解 |
|---|---|
改 authorized_keys 出错导致锁死 SSH |
先备份;-n 不覆盖;ssh-copy-id 式追加而非替换;本机 .249 侧通道始终可用 |
注入验证期间 .27 不可用 |
事前确认无在跑作业;窗口约 5 min;不重启节点 |
| 自愈脚本误判导致误 start | 判据仍为「仅 failed 才动」,未放宽;reset-failed + start 对 active 单元是 no-op |
| 三态判据改动引入新误报 | 负向验证已覆盖(不可达 → WARNING);常规巡检无新增告警 |
9. 遗留¶
.21未纳入:lustre_ins的.21(MGS+MDT 同机客户端)同样有过挂载 failed,但属 Lustre 服务端节点,是否纳入本巡检需决策(纳入即lustre_extra_guards多加一行)。- 免密未进实现体:节点间免密目前是手工步骤(既有 SOP 步骤 4),部署器
pre_check不校验——建议加「自愈对象 SSH 可达性」预检,把本次这类静默失效挡在部署前。 LUSTRE_GUARDS注入方式:脚本经render_watchdog_py()渲染注入_CFG.get("lustre_guards"),模板源内无该常量——后续改模板时勿在模板里直接引用未定义全局名。
来源:
/home/rain/Documents/slurm/slurm_ins/lustre_mount_selfheal_extend_20261007/SOP.md| 最后更新:2026-10-07 10:20(由build/sync.py同步,请勿在站点侧修改)