SOP — EDA 存储架子(Tier1 共享目录 + Tier0 scratch 结构)¶
变更日期:2026-09-24 实现体:
storage_layout_deployer.py+storage_layout_assets.py(工程根/home/rain/Documents/slurm/slurm_ins) 配置:config/slurm_deploy.yaml的storage_layout段 执行目录:/home/rain/Documents/slurm/slurm_ins本文第 5 章为实现等价的操作序列,以实现体为准;幂等、备份与回滚由实现体保证。 同主题的另一次变更(本地 scratch + Lustre 清理)见SOP.md。
目录¶
- 背景 · 2. 目标 · 3. 前置条件 · 4. 影响范围 · 5. 分步操作 · 6. 验证 · 7. 回滚 · 8. 风险说明 · 附录
一、背景¶
EDA 存储标准的架子(目录语义、挂载、权限、统一视图)与内容(工具二进制、PDK、License)本就解耦:
- 旧集群《存储目录行业标准设计》1.1 的核心规则是「工具/PDK 只读;与 modulefiles 解耦,多版本并存用
module切换」; - 既有 modulefile 已内置该约定(
Core/*.lua里的isDir守卫 +install_dir占位),空壳时module load会给出明确提示。
本集群三层骨架此前只有 Tier1 的家目录与 modulefiles,缺:
| 缺口 | 影响 |
|---|---|
无 /projects |
项目工作区缺失,无法按团队共享设计数据 |
无 /tools /pdk |
客户端无统一视图,工具无处安放 |
| Tier0 只有挂载点 | scratch 无标准目录结构,临时数据无序 |
| 无生命周期清理 | 另项待办(本变更不做,见第八节) |
触发条件:用户确认「先把架子搭起来,工具与 License 后续分步部署」。
二、目标¶
- Tier1 新增三个共享目录并挂载到三台计算节点:
/projects(rw)、/tools(ro)、/pdk(ro) /projects下按 LDAP 8 个小组建目录(2775 root:<组>)/tools、/pdk建根目录(755 root:root),空壳待填- Tier0 建
/mnt/lustre/scratch/{users,projects,tmp}(tmp为 1777),fstab 补noatime - 幂等:连续执行两次,第二次零变更、全跳过
不在本次范围:工具/PDK 内容、License 服务化、生命周期清理、控制节点挂载。
三、前置条件¶
| # | 条件 | 检查方式(只读) | 本次实测 |
|---|---|---|---|
| 1 | 宿主 sudo 免密可用 |
sudo -n true |
✅ |
| 2 | 可读写 /etc/exports |
sudo cat /etc/exports |
✅(已有 7 条导出) |
| 3 | 目标节点 SSH 可达 | ssh root@192.168.31.18 echo OK |
✅ 三台 |
| 4 | 客户端网段可确定 | 配置 client_cidr 或由现有导出推导 |
✅ 192.168.31.0/24 |
| 5 | /data 空间充足 |
df -h /data |
✅ 余 1.3T |
| 6 | LDAP 8 组可解析 | ssh … "getent group design" |
✅ 2000/3000/4000/5000/6000/6100/6200/6220 |
| 7 | Lustre 已挂载(Tier0 前身) | findmnt -M /mnt/lustre |
✅ 三台 |
| 8 | 宿主无同名导出冲突 | sudo exportfs -v |
✅ 三路径此前均未导出 |
1–4 已由实现体
pre_check()落为可执行门禁:任一项不通过即终止,不做任何变更。
四、影响范围¶
| 项 | 内容 |
|---|---|
| 涉及主机 | 宿主 192.168.31.249(部署机自身);计算节点 .18/.19/.20 |
| 是否需停服 | 否。不改 Slurm 配置、不重启任何 Slurm 守护进程 |
| 在跑作业 | 运行中作业不受影响;新挂载点为全新路径 |
| NFS 影响面 | ⚠️ 宿主共用 NFS 服务(/srv/nfs/k8s、/srv/nfs/k8s-hdd 供 k8s 使用)→ 导出采用 exportfs -o 单条追加,不使用 exportfs -ra 全量重载,避免瞬时打断 k8s PVC |
| 窗口期 | 无需专门窗口(逐台串行) |
| 不可逆点 | 无(不删数据、不格式化) |
五、分步操作¶
对应实现:
storage_layout_deployer.py(HostExportsManager/StorageLayoutInstaller/StorageLayoutDeployer),以实现体为准。
5.1 预演与执行¶
cd /home/rain/Documents/slurm/slurm_ins
.venv/bin/python main.py --config config/slurm_deploy.yaml --storage-layout --dry-run
.venv/bin/python main.py --config config/slurm_deploy.yaml --storage-layout
实现体内部顺序(宿主先行,节点分批):
# —— 宿主侧(本机,sudo 执行)——
mkdir -p /data/nfs/projects /data/nfs/tools /data/nfs/pdk # 必须先建目录,否则 exportfs 报错
# ⚠️ 高危:改 /etc/exports 前自动备份(见第七章)
printf '%s\n' '/data/nfs/projects 192.168.31.0/24(rw,async,no_subtree_check,no_root_squash)' >> /etc/exports
exportfs -o rw,async,no_subtree_check,no_root_squash 192.168.31.0/24:/data/nfs/projects # 单条追加,不重载全部
chown root:root /data/nfs/tools && chmod 755 /data/nfs/tools # 只读层权限在宿主侧设置
# (客户端 ro 挂载无法 chown)
# —— 节点侧(SSH 到各计算节点)——
mkdir -p /projects
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 # 按挂载点字段精确替换,不用无边界通配
mount /projects
# /projects 按 LDAP 逐组建目录(可写层,用组名解析)
for g in design dv custom layout cad sre pnr signoff; do
mkdir -p /projects/$g && chown root:$g /projects/$g && chmod 2775 /projects/$g
done
# /tools、/pdk 同理挂载(ro),权限由宿主侧设置,不在客户端 chown
# —— Tier0 ——
mkdir -p /mnt/lustre/scratch/{users,projects,tmp}
chmod 1777 /mnt/lustre/scratch/tmp
# fstab: <source> /mnt/lustre lustre defaults,noatime,nofail 0 0
mount -o remount /mnt/lustre
六、验证¶
# 1. 幂等复跑:第二次必须零变更、全跳过
.venv/bin/python main.py --config config/slurm_deploy.yaml --storage-layout
# 预期:变更记录总数 15 / 待执行变更 0 / 幂等跳过 15 / 退出码 0
# 2. 三台挂载状态与读写性
for h in 18 19 20; do ssh root@192.168.31.$h '
for mp in /projects /tools /pdk; do printf "%-11s " $mp; findmnt -no OPTIONS -M $mp | cut -d, -f1; done
touch /projects/.w && echo 可写 && rm -f /projects/.w || echo 不可写'; done
# 预期:/projects rw 可写;/tools、/pdk ro
# 3. 组目录
ssh root@192.168.31.18 "ls -1 /projects | wc -l; ls -l /projects | head -3"
# 预期:8 个目录,drwxrwsr-x root <组>(2775)
# 4. Tier0
ssh root@192.168.31.18 "ls -1 /mnt/lustre/scratch; findmnt -no OPTIONS -M /mnt/lustre | grep -o noatime"
# 预期:projects tmp users;noatime
# 5. 宿主导出
sudo exportfs -v | grep -A1 "nfs/projects"
# 预期:192.168.31.0/24(async,…,rw,…,no_root_squash)
本次实测(2026-09-24 22:12–22:28):1–5 全部通过。
七、回滚¶
备份位置¶
| 备份对象 | 位置 | 说明 |
|---|---|---|
宿主 /etc/exports |
/var/backups/slurm/storage_layout_<时间戳>/exports.bak |
由实现体 backup() 自动创建 |
各节点 /etc/fstab |
/var/backups/slurm/storage_layout_<时间戳>/fstab |
同上 |
| 工程改动前文件 | eda_storage_gap/backup/layout_fix/ |
main.py、config/slurm_deploy.yaml(.example) |
| 共享库改动前文件 | eda_storage_gap/backup/layout_fix/idempotent_utils.py.bak.* |
见附录 C |
完整台账见 eda_storage_gap/backup/README.md。
回滚步骤¶
.venv/bin/python main.py --config config/slurm_deploy.yaml --storage-layout --rollback
顺序(不可颠倒):先卸节点挂载并移除 fstab 条目 → 再 exportfs -u 撤销宿主导出。
回滚不删除任何数据:/data/nfs/{projects,tools,pdk} 与 /mnt/lustre/scratch 的内容保留。
回滚后验证¶
for h in 18 19 20; do ssh root@192.168.31.$h \
'findmnt -M /projects || echo "未挂载"; grep -c "nfs/projects" /etc/fstab || true'; done
sudo exportfs -v | grep -c "nfs/projects" # 预期 0
八、风险说明¶
| # | 风险 | 缓解 |
|---|---|---|
| 1 | 宿主 NFS 服务与 k8s 共用:exportfs -ra 全量重载会瞬时打断所有客户端 |
实现体用 exportfs -o 单条追加,不碰其它导出;变更前自动备份 /etc/exports |
| 2 | NFS 的 ro/rw 无法 remount 修正 |
参数不符时卸载重挂(见附录 B-5);首次挂载若服务端导出尚未生效会降级为 ro |
| 3 | 只读挂载点无法在客户端改权限 | /tools、/pdk 的属主与权限一律在宿主侧设置(见附录 B-3) |
| 4 | actimeo=30 被内核展开为 acregmin/acregmax/acdirmax |
共享库按「选项名」跳过此类项(附录 B-4),否则每次执行都判不符、反复重挂 |
| 5 | 挂载参数热改影响运行中作业 | 新挂载点无历史包袱;重挂仅针对参数不符的点 |
遗留(本变更不做,已登记待办)¶
- scratch 生命周期清理:
Epilog不清理/local_scratch与/mnt/lustre/scratch,TaskProlog未注入TMPDIR(对比旧集群第 5 条判定缺口)。 profile.d曾错误设置TMPDIR:已在本轮移除(附录 B-2),TMPDIR改由后续 TaskProlog 注入。/tools、/pdk为空壳;工具就位时需按/tools/<厂商>/<工具>/<版本>填充并改 modulefile 的install_dir。
附录 A:交付物清单¶
| 文件 | 说明 |
|---|---|
storage_layout_deployer.py |
实现体:宿主导出 + 节点挂载 + 目录权限 + 三态幂等 + 分批 + 回滚 |
storage_layout_assets.py |
配置解析与渲染(fstab 行、exports 行、校验) |
main.py |
新增 --storage-layout 子命令 |
config/slurm_deploy.yaml / .example |
新增 storage_layout 段 |
utils/idempotent_utils.py |
修复 mount_options_matched 对 name=value 形式的误判(共享库) |
附录 B:执行过程中的问题与修复¶
| # | 现象 | 根因 | 修复 |
|---|---|---|---|
| 1 | exportfs 报目录不存在 |
实现体漏了建导出目录 | ensure_export 先 mkdir -p 再导出 |
| 2 | 节点 mktemp 报 No such file or directory |
上一轮下发的 profile.d 把 TMPDIR 指向尚未创建的作业目录,且 profile 会被 SSH 会话加载 |
① eda_scratch.sh 不再设置 TMPDIR(留给 TaskProlog);② 部署器内 mktemp 显式 -p /tmp |
| 3 | chown: Read-only file system |
/tools、/pdk 是 ro 挂载,客户端无法改权限 |
只读层的权限改由宿主侧设置(set_dir_attrs,幂等比对 stat) |
| 4 | health_check 报 9 项参数不符 | mount_options_matched 用 "actimeo=30" 去查只含 "actimeo" 的豁免集合 → 永远判不符 |
改为按「选项名」(= 前部分)判断豁免;已回归 node_env(45 条 0 变更) |
| 5 | /projects 挂成 ro 且不可写 |
首次挂载时服务端导出尚未生效 → NFS 降级为 ro;而 remount 无法改变 NFS 的 ro/rw |
apply_tier1 参数不符时改为 umount; mount(卸载重挂) |
经验:共享库的行为修改必须回归所有挂载工程 —— 本次改
mount_options_matched后,逐一确认node_env仍为零变更。
附录 C:实测记录(2026-09-24)¶
| 项 | 结果 |
|---|---|
| 首次 dry-run | 30 项待变更,退出码 0 |
| 正式执行(含修复迭代) | 宿主 3 条导出 + 每节点 9 项(3 挂载点 + 权限 + scratch + Lustre 参数) |
| 幂等复跑 | 15 条记录 / 待执行 0 / 跳过 15 / 退出码 0 |
| 三台实机 | /projects rw 可写、8 个组目录 2775;/tools /pdk ro;Tier0 三子目录齐备 |
| 共享库回归 | node_env 45 条 0 变更,退出码 0 |
来源:
/home/rain/Documents/slurm/slurm_ins/eda_storage_gap/SOP-存储架子.md| 最后更新:2026-09-24 22:34(由build/sync.py同步,请勿在站点侧修改)