SOP — hpc-submit(.28)NFS 挂载持久化补漏¶
变更编号:
fstab_persist_fix_20261007|执行日期:2026-10-07|主机:仅 192.168.31.28(hpc-submit) 类型:C 类变更(改配置源判据 + 补 fstab 条目)|结果:已验证通过,幂等复跑零变更
1. 背景¶
对集群 NFS 挂载做例行核对时发现:hpc-submit(192.168.31.28)的 /tools 与 /projects
运行时确实挂着、参数也对,但 /etc/fstab 里没有这两条——重启即丢。
排查根因,落在实现体上:
# storage_layout_deployer.py(变更前)
def judge_tier1(self, probe, source, options):
if probe.get("SRC") != source: # 未挂载
if probe.get("FSTAB_SRC") == source:
return STATE_PENDING, "fstab 已有条目,待挂载"
return STATE_PENDING, "尚未挂载"
if not mount_options_matched(options, probe.get("OPT", "")):
return STATE_PENDING, "挂载参数待补齐"
return STATE_DONE, "已挂载且参数匹配" # ← 只判这里,不判 fstab
判据只看挂载状态与挂载参数,不看 fstab 条目。挂载点一旦已挂上且参数匹配,
即判 DONE,随后 apply_tier1() 被整体跳过——其中写入 fstab 的那一步也跟着被跳过。
于是只要发生「先挂载、后丢 fstab 条目」(手工挂载、或它方工程重写 fstab),
部署器就会长期认为该节点已达标,永不补齐。.28 的三个 Tier1 挂载点中 /pdk 在 fstab、
/projects 与 /tools 不在,正是这种「部分在」的形态。
2. 目标¶
| 项 | 可验证状态 |
|---|---|
| fstab 持久化 | .28 的 /etc/fstab 含 /projects、/tools 两条,且 serve 源与挂载参数与配置源一致 |
| 挂载不受扰动 | 两处挂载点保持挂载(本变更不 umount) |
| 幂等 | 复跑 --storage-layout,待执行变更 0、全部幂等跳过 |
| 判据修复 | 同类「已挂载但 fstab 缺失」后续会被识别为 PENDING 并被补齐 |
3. 前置条件¶
- 部署机对
192.168.31.28有 root 免密 SSH(本项目既有条件) - 项目 venv 可用:
/home/rain/Documents/slurm/slurm_ins/.venv/ - 配置源
config/slurm_deploy.yaml的storage_layout.node_groups含submit(即.28在纳管范围内) - 变更前完成备份(见第 7 章)
4. 影响范围¶
| 项 | 内容 |
|---|---|
| 主机 | 仅 192.168.31.28;.18–.20 经预演确认为幂等跳过,不受影响 |
| 组件 | .28:/etc/fstab(追加两条);本工程 storage_layout_deployer.py(判据) |
| 是否停服 | 否。不重启、不 umount、不碰任何 daemon(.28 本身无 slurmd) |
| 窗口期 | 无要求;单次执行约数秒 |
| 在跑作业 | 不涉及——不触碰调度与挂载状态 |
5. 分步操作¶
实现体:storage_layout_deployer.py(judge_tier1 / apply_tier1 / _write_fstab_entry),
入口 --storage-layout。以下为等价底层操作,便于复核与手工复现。
步骤 1:修判据(源码改动,一处三行)¶
在 judge_tier1() 的「已挂载」分支中,补入 fstab 条目检查——排在参数检查之前,
因为 fstab 缺失比参数不匹配更严重(前者重启即丢)。
坑:新判据必须放在「已挂载」分支内、mount_options_matched 之前;
若放在最前,会把「未挂载但 fstab 已有条目」的既有分支覆盖掉,改变原语义。
--- a/storage_layout_deployer.py
+++ b/storage_layout_deployer.py
@@ judge_tier1
return STATE_PENDING, "尚未挂载"
+ if probe.get("FSTAB_SRC") != source:
+ return STATE_PENDING, "已挂载但 fstab 缺条目(重启会丢)"
if not mount_options_matched(options, probe.get("OPT", "")):
预期:语法正确,judge_tier1 新增一条 PENDING 出口。
失败判断:若 py_compile 报错或预演结果异常 → 第 7 章回滚实现体。
步骤 2:预演(确认影响面只有 .28 两条)¶
等价于先探测各节点挂载态与 fstab 条目,与配置源比对:
# 逐台核对:挂载源 / 挂载参数 / fstab 中该挂载点的源
ssh root@192.168.31.28 'findmnt -no SOURCE -M /projects; findmnt -no OPTIONS -M /projects; \
awk -v mp=/projects "$2 == mp {print \$1}" /etc/fstab'
预期(变更前):SOURCE 与 OPTIONS 正常,fstab 一行都打不出来(即缺条目)。
失败判断:若 fstab 已含该条目,则本变更对这台已不必要,跳过即可。
步骤 3:写入 fstab(由部署器执行)¶
部署器对每个「已挂载但 fstab 缺条目」的挂载点,执行按挂载点字段精确替换 + 追加。 等价手工命令(高危:动 fstab 前必备份):
# 高危:修改前先备份
ssh root@192.168.31.28 'cp -p /etc/fstab /etc/fstab.bak.$(date +%Y%m%d-%H%M%S)'
# 按挂载点精确替换(先删同挂载点旧行,再追加新行)
ssh root@192.168.31.28 'tmp=$(mktemp -p /tmp) && \
awk -v mp=/projects "\$2 != mp" /etc/fstab > "$tmp" && \
printf "%s\n" "192.168.31.249:/data/nfs/projects /projects nfs rw,hard,timeo=600,retrans=2,noatime,actimeo=30,_netdev 0 0" >> "$tmp" && \
cp "$tmp" /etc/fstab && rm -f "$tmp"'
# /tools 同法,参数为 ro(服务端只读导出)
坑:① 用 awk '$2 != mp' 按挂载点字段过滤,不得用无边界通配删除;
② 只写 fstab,不 umount——挂载当前是好的,动它只会制造中断;
③ /tools 固定 ro,与 .18–.20 及服务端 ro 导出保持一致。
预期:/etc/fstab 新增两行,行数由 20 增至 22(含注释)。
失败判断:写入后 findmnt --verify 出现 parse error → 第 7 章回滚 fstab。
步骤 4:后置校验¶
部署器 health_check 阶段复探「存储架子」,确认 Tier1/Tier0 均达标。
6. 验证¶
变更后实测(2026-10-07):
# 1) fstab 两条到位、参数与配置源一致
ssh root@192.168.31.28 'grep -E " /projects | /tools " /etc/fstab'
# 预期:
# 192.168.31.249:/data/nfs/projects /projects nfs rw,hard,timeo=600,retrans=2,noatime,actimeo=30,_netdev 0 0
# 192.168.31.249:/data/nfs/tools /tools nfs ro,hard,timeo=600,retrans=2,noatime,actimeo=30,_netdev 0 0
# 2) 挂载未受扰动
ssh root@192.168.31.28 'findmnt -M /projects -o TARGET,SOURCE -n; findmnt -M /tools -o TARGET,SOURCE -n'
# 预期:两行分别指向 192.168.31.249:/data/nfs/{projects,tools}
# 3) fstab 语法校验
ssh root@192.168.31.28 'findmnt --verify 2>&1 | tail -3'
# 预期:0 parse errors, 0 errors(2 warnings 均指向 /mnt/lustre 的 lustre 类型,属既有现象、与本次无关)
# 4) 幂等复跑
cd /home/rain/Documents/slurm/slurm_ins && .venv/bin/python main.py --config config/slurm_deploy.yaml --storage-layout --dry-run
# 预期:变更记录总数 19 / 待执行变更 0 / 幂等跳过 19
实测结果:四项全部符合预期,待执行变更 0。
7. 回滚¶
备份位置与台账:fstab_persist_fix_20261007/backup/README.md(两份:部署器源码、.28 的 fstab)。
# 回滚 fstab(回到注入前)
scp fstab_persist_fix_20261007/backup/192.168.31.28/etc/fstab.bak.20261007-084904 root@192.168.31.28:/etc/fstab
# 回滚实现体判据
cp fstab_persist_fix_20261007/backup/slurm_ins/storage_layout_deployer.py.bak.20261007-084904 \
slurm_ins/storage_layout_deployer.py
回滚后验证:.28 两处挂载点仍在且可访问(ls /projects、ls /tools);
--storage-layout --dry-run 回到变更前的清单形态。
回滚触发判据:findmnt --verify 出现 parse error;或挂载点变为不可访问;或 --storage-layout 复跑出现非零待执行变更。
8. 风险说明¶
| 风险 | 缓解 |
|---|---|
| 改判据影响其它节点判定 | 新判据只在「已挂载但 fstab 缺失」时触发;.18–.20 实测 fstab 与挂载一致 → 仍判 DONE。预演已逐一确认 |
| 写 fstab 出错导致重启挂不上 | 仅追加、按字段精确替换;写前备份;写后 findmnt --verify 校验 |
| 写 fstab 时误 umount 造成中断 | 实现体在「已挂载且参数匹配」分支不执行 mount/umount,只补 fstab |
| 与它方工程对同一 fstab 的写入冲突 | 本变更只动 /projects、/tools 两个挂载点;/mnt/lustre 的跨工程冲突属既有独立议题(见 BASELINE.md §2) |
未做且不应做的动作:未 umount 任何挂载点、未重启主机或服务、未改 /etc/exports、未动 .18–.20。
来源:
/home/rain/Documents/slurm/slurm_ins/fstab_persist_fix_20261007/SOP.md| 最后更新:2026-10-07 08:51(由build/sync.py同步,请勿在站点侧修改)