跳转至

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。

目录

  1. 背景 · 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 后续分步部署」。

二、目标

  1. Tier1 新增三个共享目录并挂载到三台计算节点:/projects(rw)、/tools(ro)、/pdk(ro)
  2. /projects 下按 LDAP 8 个小组建目录(2775 root:<组>)
  3. /tools、/pdk 建根目录(755 root:root),空壳待填
  4. Tier0 建 /mnt/lustre/scratch/{users,projects,tmp}(tmp 为 1777),fstab 补 noatime
  5. 幂等:连续执行两次,第二次零变更、全跳过

不在本次范围:工具/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 同步,请勿在站点侧修改)