目标
在自有的 V100 机队上跑通 MiniMax-H3 FL2VA,产出一段 30 秒、1080p、24 fps、带连续音频的视频。
H3 是 33B 的视频生成模型,同时产出画面和声音,checkpoint 144 GB,需要多卡张量并行。把它放到这批硬件上,硬约束有四条:
| 约束 | 后果 |
|---|---|
| V100 是 SM70,无 BF16 | H3 的发布路径偏向 BF16,精度策略和 attention kernel 都得换 |
| 单卡 16 GB | 33B 权重必须 TP8 切分,activation 稍大就八卡同时 OOM |
| 12/14 台节点归 K3s | 没有能做多节点多卡分配的调度器 |
共享存储的 /data 挂不上 | 144 GB checkpoint 没有分发路径,模型服务 CrashLoop |
所以在碰模型之前要先补四层:一个真的能挂的共享存储、一致的 GPU 运行时、一个能做设备隔离和多卡分配的调度器,以及把节点从 K3s 手里接过来。
完成的定义
sinfo 能看到节点、srun hostname 能返回,这两条不足以支撑上面的目标。这次的标准定在七条:
- 14 台节点、112 张 V100 全部被调度器正确识别
- GPU、CPU、内存和设备访问受 cgroup 约束
- 模型只读、任务数据可写,失败任务不污染共享目录
- Accounting 记录 generic 和 typed GPU TRES
- Web 页面从 Tailnet 可访问,管理面不直接暴露
- K3s 的 12 个可达节点、workload intent、hostPath 与 PostgreSQL 数据都有实际恢复证明
- H3 作业跑通,并且产出的成片通过语义验收
机队现状
| 项目 | 状态 |
|---|---|
| 在线计算节点 | 14 台,每台 80 CPU、8×Tesla V100-SXM2-16GB |
| 不可达节点 | 1 台,网络原因,保持 pending |
| 节点归属 | 12 台跑 K3s,1 台 Slurm canary,1 台空闲 |
| GPU 基线 | 有漂移:3 台内核模块与用户态 NVML 版本不匹配,1 台仍在 570 驱动分支 |
| 共享存储 | /data 路径存在,客户端挂载失败 |
| 故障域 | 模型、运行时、输出、数据库、控制面全部落在同一台存储服务器 |
最终生产分区是 14 节点、1120 CPU 线程、2,576,000 MiB 调度内存、112 张 V100。
本文数字取自实际验收记录。主机名、地址、账户和变更 ID 用占位符替代。
数据面
H3 的 checkpoint 有 144 GB,要对 14 个节点只读可见,任务输出又要可写且互不污染。这两件事都落在共享存储上,而它当时是坏的。
这台存储原本有一个 ZFS 池,/data 是池上某个数据集的挂载点,NFS 从这里导出给计算节点。池后来不可导入,预期的 8 个成员只匹配到 4 个,超出 RAIDZ1 的冗余能力。池没挂上来,/data 就退回成根盘上的一个空目录,而目录本身还在。
NFS export 那一侧设了 mountpoint 条件,rpc.mountd 因此拒绝导出这个未挂载的目录。showmount 读的是配置视图,仍然列得出这一项。当时的维护探针只做 timeout 10 stat /data,目录存在就判定 responsive。
于是三个信号都是绿的:目录能 stat、export 配置在、showmount 有输出。客户端日志一直是 No such file or directory。
目录存在、export 配置存在、内核实际提供导出,探针要分别验:
# 服务端:路径必须真的是预期文件系统的挂载点
findmnt -T /path/to/export -o SOURCE,TARGET,FSTYPE,OPTIONS
# 服务端:配置视图与内核有效导出交叉检查
exportfs -v
cat /proc/fs/nfsd/exports
# 客户端:验证来源、文件系统类型和挂载参数
findmnt -M /mnt/data -o SOURCE,TARGET,FSTYPE,OPTIONS
# 业务层:验证 manifest 与权重可读
test -r /mnt/models/MODEL_ID/model_index.json
成员不完整时没有强行导入旧池,也没有为了让 NFS 看起来能挂而去掉 mountpoint 条件。去掉之后会把一个空的底层目录导出给客户端,故障从明确失败变成静默读空。
在健康池上重建了两个职责分离的数据集:
| 数据集 | 客户端权限 | 用途 |
|---|---|---|
ai/models | 只读 | canonical checkpoint、manifest |
ai/data | 读写 | jobs/、inputs/、outputs/ |
单节点 canary 的 1 GiB 顺序 I/O 实测 803 MB/s 写、1.5 GB/s 读。这个数字的作用是证明读写路径和权限合同成立。
GPU 基线
TP8 要求同一节点内的 8 张卡在驱动、CUDA runtime 和设备枚举上行为一致,跨节点的三段并行还要求 3 台机器之间也一致。
节点间驱动、CUDA、时钟和 cgroup 状态不一致的话,Slurm 会把这些差异包装成更难追踪的随机失败。所以先对 14 台统一并逐台复验:
- 8/8 GPU 可枚举,112 个 UUID 全集无重复
- 驱动统一到
580.173.02,CUDA toolkit12.9.1走共享只读路径 - 每台实际编译并运行 CUDA runtime probe,报告
runtime=12090、devices=8、sm70=yes - cgroup v2 的
cpuset、cpu、memory、io、pids控制器就位 - NTP 已同步,uncorrected ECC 为 0
- 不可达节点留在 pending,不用陈旧 inventory 强行入池
自建 Slurm 包
H3 用 TP8,需要 PMIx runtime;GPU 分配需要 NVML GRES;accounting 需要数据库插件。这几项的组合要能确定复现。
版本固定在 26.05.4(Debian 版本号 26.05.4-1+v1001),从固定源码哈希在 digest-pinned 的 Ubuntu 22.04 容器里构建 17 个 DEB,发布到 storage 上的版本化本地仓库。
自建包是为了同时控制这几项:Slurm 与 PMIx、NVML、JWT、数据库插件的构建组合;包名、版本号和依赖关系;所有节点安装同一批二进制;升级时先发布新版本目录再对 canary 滚动测试;已部署包可以 hold,避免系统更新混入另一套 Slurm。
构建产物带源码哈希、包清单、Packages.gz 和整棵 artifact tree 的校验记录。
Canary
Controller 放在 storage,slurmd 只装到那台没有 K3s 的 8 卡节点。仍受 K3s 管理的节点这时不交给 Slurm。
核心配置压成四类合同:
# 资源选择
SelectType=select/cons_tres
SelectTypeParameters=CR_Core_Memory
GresTypes=gpu
# 进程与设备隔离
ProctrackType=proctrack/cgroup
TaskPlugin=task/cgroup,task/affinity
# 身份认证
AuthType=auth/munge
CredType=cred/munge
# 调度
SchedulerType=sched/backfill
ReturnToService=1
DisableRootJobs=YES
# cgroup.conf
CgroupPlugin=autodetect
ConstrainCores=yes
ConstrainRAMSpace=yes
ConstrainSwapSpace=yes
ConstrainDevices=yes
AllowedSwapSpace=0
# gres.conf
AutoDetect=nvml
Name=gpu Type=v100 File=/dev/nvidia[0-7]
MUNGE 与 UID/GID 要在第一步固定
MUNGE key 一致只是第一层。跨主机运行时,slurm、munge 和业务账户的数值 UID/GID 也必须相容,否则会出现四类问题:controller 与 compute 对 spool/config 的所有权解释不同;NFS 上同一文件在不同节点解析成不同用户;重装后账户 ID 漂移导致旧状态读不出;回滚时删错或保留错误的账户目录。
所以部署前先冻结身份元数据,apply 和 rollback 都校验进入状态。
Canary 的验收内容
第一个真实作业要同时证明分配到的 GPU、可见设备数、cgroup 路径、只读模型可读、共享结果可写、退出码,以及任务结束后的显存释放:
srun -p "$CANARY" --nodes=1 --ntasks=1 \
--gres=gpu:v100:1 --cpus-per-task=8 --mem=20G \
bash -lc '
set -euo pipefail
[[ "$CUDA_VISIBLE_DEVICES" =~ ^[0-7]$ ]]
grep -Eq "/job_[0-9]+/" /proc/self/cgroup
test -r "$MODEL_MARKER"
probe="$JOB_ROOT/.probe-${SLURM_JOB_ID}"
trap "rm -f \"$probe\"" EXIT
printf verified > "$probe"
test "$(cat "$probe")" = verified
nvidia-smi -i "$CUDA_VISIBLE_DEVICES" \
--query-gpu=index,name --format=csv,noheader
'
这一步先后暴露出六个问题:
- NVML 的 per-device 信息写在 stderr,健康脚本只解析 stdout,形成假失败
- 构建时启用了 PMIx 插件,运行节点缺少对应 runtime,daemon 启动报插件错误
- systemd delegation 要同时校验 package unit 里有
Delegate=yes,以及systemctl show返回 live 的Delegate=yes - Ubuntu 上 MUNGE 的卸载后状态与预期不同,回滚逻辑不能假设 purge 等于完全消失
- 重新配置 controller 时缺少 staged config 和隔离验证,坏配置会直接打到生产 daemon
- 同一个变更 ID 重入时,不能重新生成 MUNGE key 或覆盖首次基线
这六项都写进了幂等和回滚合同。
Accounting
Canary 通过之后才加 accounting 层:
- MariaDB
11.4.13跑在 storage,主机只绑定 loopback,数据放独立 ZFS dataset slurmdbd只允许 loopback 和计算网段,继续用 MUNGEslurmrestd只监听 Unix socket,不开默认 TCP 端口- JWT signing key 只存在远端受限目录,短效 token 不进仓库和日志
JobAcctGatherType=jobacct_gather/cgroup
JobAcctGatherFrequency=30
AccountingStorageType=accounting_storage/slurmdbd
AccountingStorageTRES=gres/gpu,gres/gpu:v100
AuthAltTypes=auth/jwt
备份要证明能恢复
数据库备份最危险的状态是文件存在、哈希也对,但从未 restore 过。回滚顺序固定成七步:停止新的 accounting writer;生成带时间戳的 SQL dump;校验压缩流和 SHA-256;导入 scratch database;验证 schema、34 张表和历史 job row;restore proof 成功之后才移除 active dataset;reapply 先验 dump 哈希再恢复历史。
多次 rollback / reapply 之后旧作业记录仍在,新作业继续追加。
首次从无 accounting 的 controller state 接入新数据库时遇到 CLUSTER ID MISMATCH。这是 Slurm 对共享状态损坏的主动保护,删 state 文件绕过就失去了保护意义。处理方式是停掉 writer、保存原 clustername、以 DBD 注册项作为本次迁移的 authoritative ID,走受控流程让 controller 采用;rollback 恢复原 ClusterID,reapply 从已验证的数据库历史继续。
Web 与 Tailnet
Slurm-web 7.0.0 作为独立层部署,agent 通过 Unix socket 连 slurmrestd,gateway 才对外提供页面。容器用固定镜像 digest、非 root UID/GID、read-only rootfs、drop all capabilities、no-new-privileges、CPU/内存/PID 限制、secret 只读挂载,anonymous policy 只保留观察动作。
初次部署撞到两个陷阱:
- 镜像内
/var/lib/slurm-web的父目录属于镜像自带 UID,而容器跑在另一个固定非 root UID 上,读取单文件 secret 路径时出现确定性PermissionError。改成每组件只读目录挂载后父目录可遍历,secret 仍保持最小暴露 - Docker 的 solely-internal network 不发布 gateway 端口,需要单独的 ingress bridge,宿主端口仍绑在 loopback
Tailnet 暴露做成独立变更层:保留 SSH tunnel,只在指定 Tailnet 地址监听,LAN、agent 和 REST 端口继续关闭。一次 reapply 中 systemd watchdog 与 Compose recreate 发生竞争,用「暂停 timer → 等 watchdog 退出 → 共享锁 → 强制恢复 handler」解决。
这一层有自己的 marker、baseline 和 rollback,与 Web 安装分开。
K3s 迁移
H3 的三段并行要 3 个节点、24 张卡,而当时只有 2 台不属于 K3s。要凑够就得把节点接过来。
Canary、accounting 和观察面都稳定之后,才动那 12 台 K3s 节点。
硬件与所有权审计
扩容前对每台在线主机采集 CPU topology、内存、GPU UUID/型号/驱动、K3s/Slurm/MUNGE service、NFS、NTP、cgroup v2、根盘空间和 slurmd -C。
结果确认 14 台的调度关键资源一致:2×20×2 CPU topology、8 张同型号 V100、统一驱动,scheduler memory 取 184000 MiB。kernel 与根盘容量并不完全一致,但不影响调度。
这一步也把「当前谁拥有 GPU」记录清楚了。
保留式退役
K3s 的处理是退役并保留,二进制、datastore、hostPath 和恢复包都不删。停服务之前先保存 SQLite 在线备份和 API object export、Deployment/DaemonSet/CronJob 的 intent、hostPath 数据、PostgreSQL custom-format dump、服务与文件基线,以及一个带 SHA-256 的 recovery bundle。然后按 agent batches、server-last 的顺序停止并禁用服务,用 systemd condition 防意外重启。
第一次退役在 API state / SQLite 备份阶段中断,而该任务用了 no_log,记录不足以证明具体根因。处理方式是用同一变更 ID 续做:核对已有 marker、immutable baseline 和完成 seal,只补未完成的步骤。根因保持未知,没有补一个说得通的解释上去。
fail-closed 扩容
全量加入分三层验收。每节点注册并进入 IDLE 之前,验证 controller 签发的 MUNGE credential 能在 compute 端 unmunge、复制同一份冻结配置、8 个 NVML GRES、cgroup 配置与 live Delegate、mount source、K3s GPU 进程为空、已安装 package 版本。随后一个 all-node / all-GPU 作业实测 CUDA_VISIBLE_DEVICES、Slurm cgroup 路径、模型读取与任务目录写入。该作业连同 accounting / Web 验收通过之后,才 hold 精确包集合并记录各节点最终 config hash。
任意 all-node acceptance 失败,生产分区回到 INACTIVE,不带着部分成功的节点继续服务。
两次验收器自己的 bug
- apt simulation 生成的包名与
dpkg-query对 Multi-Arch 后缀的表示不同,原比较器又漏了两个传递依赖,形成 22 对 24 的假差异。修复是对架构后缀做 canonicalize,并冻结完整 transaction plan - 第一次 112-GPU 验收把
CUDA_VISIBLE_DEVICES里的七个逗号当成七张 GPU,14 个 task 全部退出 1。诊断表当时已经显示每台物理机都有 8 张卡、NFS 和 cgroup 也正常。修复 oracle 后按字段数计数;失败 rescue 仍取消残留 step 并把两个分区置为INACTIVE
最终一个作业同时拿到 14 个节点、每节点 8 张 GPU:
nodes=14
generic GPU TRES=112
typed v100 GPU TRES=112
visible_gpus_per_task=8
job_state=COMPLETED
exit_code=0:0
全链回滚实际执行过
- Slurm fleet 从 14 节点退回单节点 canary
- 单卡 canary 作业再次成功
- K3s 恢复 12 个可达 Ready 节点
- Deployment / DaemonSet / CronJob intent 恢复
- PostgreSQL:退役前 custom dump 已在 scratch database 证明 source 与 restored 都是 58 张用户表;K3s 回滚后恢复运行的实例同样回报 58 张
- 再用新的变更 ID 重做最终迁移
跑 MiniMax H3
下文用别名代替真实 scheduler Job ID:P0 是运行时打包,G* 是 GPU 推理尝试,C* 是清理恢复,R* 是 CPU 后处理。
模型只下载一次
快照固定到一个 revision,84 个文件合计 144,051,241,571 字节,含 29 个 Safetensors。下载器支持并发、续传和重试;84/84 manifest size 通过之后才原子发布,发布后再独立解析 model_index.json 和全部 29 个 Safetensors header。
14 个节点从只读 NFS 看到同一快照,写探针按预期失败。回滚下载器只移除 service 和 script,模型与 partial data 保留。
V100 兼容层
H3 的发布路径偏向 BF16,V100 是 SM70。canary runtime 的构成:
- FP16 主计算,sensitive 部分 FP32 累加
- original-format 权重的 streaming name mapping
- TP8 分片前完成 QKV 拆分和 gate/value 重排
- native / PyTorch attention,不复制 SM80+ 的 kernel 配置
- conditioner block offload
- DiT 完成后、VAE decode 前释放大模型阶段
- 每个 rank 输出 generated / release receipt
一个 5.167 秒的早期 canary 生成了 124 帧、960×544、24 FPS、AAC 双声道;每 rank 峰值 reserved 12,557,746,176 字节。这证明兼容层可用,没有证明 30 秒连续 FL2VA 的目标形状可用。
OOM 揭出的 geometry 缺陷
30 秒视频规划成三个 10 秒 FL2VA 段。每段用两张冻结锚点图,前一段末锚点和后一段首锚点是同一个文件同一个哈希,所以三段能在三个节点上并行。
第一个声明为 640×384×243 的 canary(G1)在八张卡上同时 OOM:
requested allocation: 1.49 GiB
GPU capacity: 15.77 GiB
in use: 15.43 GiB
free: 336.50 MiB
直觉是继续降分辨率。声明 512×320 的 G2/G3 提交上去,日志里的 packed layout 却完全不符合这个画布——从 packed layout 可以直接反推出实际用的是 1216×768。
根因在 launcher:构造 FL2VA input 对象时没有把 target_shape 放进去。JSON 里的目标尺寸是对的,真正进入 runner 的对象没有这个字段。G1 用的是同一个缺陷 launcher 并在同一 DiT 路径 OOM,但本地摘要没保留它的 resolved canvas,所以精确的 1216×768 只归于 G2/G3。
修复是给 launcher 加显式参数,并让每个 rank 在进入 DiT 前打印:
{
"stage": "request_geometry",
"task": "fl2av",
"target_shape": [384, 640],
"target_video_length": 243
}
G4 因为用了带同一缺陷的冻结资产被主动取消,不作为放行证据。修正后的 canary G5 在单节点 TP8 上通过:
shape=640x384
frames=243
text/audio/video/total rows=699/810/17760/19269
8/8 generated receipts
8/8 release receipts
peak reserved=13.086 GiB per GPU
state=COMPLETED
exit=0:0
这时才放行三节点 full render。
作业生命周期
推理跑成 Slurm 作业。canary 之前先由 P0 把已验证 runtime 打包成带哈希的 runtime.tar.zst,G1 通过 afterok:<P0> 启动并再次验证 archive hash。
三段 full render 的资源拓扑:
#SBATCH --partition=v100
#SBATCH --nodes=3
#SBATCH --ntasks=3
#SBATCH --ntasks-per-node=1
#SBATCH --cpus-per-task=80
#SBATCH --mem=176G
#SBATCH --gres=gpu:v100:8
#SBATCH --time=01:30:00
每个 outer task 占一个节点,节点内启一个 TP8 group。共享锚点预先冻结所以三段能并行;锚点如果来自上一段的真实输出,工作流就得改成 afterok 串行依赖。
生命周期拆三步:stage-runtime 验证共享 tar 和 hash、解到 node-local 路径;render 按 SLURM_PROCID 唯一映射 segment、运行 TP8;cleanup 由 node-local EXIT trap 清理当前 job 的 runtime 并确认 8 卡显存回落。
scancel 之后再创建 cleanup srun 并不可靠,事后用 SSH 清理也分不清哪些进程属于哪个作业,所以清理步骤跟着作业一起进节点。
正式生成 G6:3 个节点、24 张 V100、528 GiB 调度内存,13 分钟完成,三段媒体、done receipt 和 verification JSON 全部通过。
成片交付
模型跑通只解决了第七条标准的前半句。三段素材生成出来之后,问题转到成片本身。
接点连续性
最早的分段提示词保证不了场景连续。改成 first/last-frame conditioned FL2VA,让相邻段共享完全相同的 anchor 之后,10 秒和 20 秒接点的画面变化指标下降约 95%,狐狸姿态、楼梯、栏杆、天际线和船位在接点保持连续。
分段提示词能约束语义,接点的连续性靠的是冻结锚点这个共享输入。
音频接点
旧组装只在每段边缘做很短的 fade,形成明显的中心掉音。改成两次 0.75 秒 equal-power qsin crossfade,再整体 retime、pad/trim 到 960,000 个 32 kHz 时间样本。
| 接点 | 旧版 RMS 差 | 新版 | 改善 |
|---|---|---|---|
| 10 s | 3.394 dB | 0.112 dB | 96.7% |
| 20 s | 5.288 dB | 3.455 dB | 34.7% |
最终音频 -18.6 LUFS、true peak -4.3 dBFS,无削波、无 100 ms 以上静音,packet timeline 精确结束在 30.000 秒。
帧数:717 和 720 都可能不合格
每个模型段原生 243 帧,三段 30.375 秒。旧方案每段删三个内部帧凑到 720,在九个固定位置制造了运动跳步。改用轻微整体 retime 加 MCI/AOBMC 双向运动补偿之后,九个位置的三帧窗口变化指标平均下降 36.192%。
CPU 后处理阶段(R0–R6,都是 Slurm 调度的 CPU 作业,不重跑 GPU 推理)暴露了一串朴素问题:
- R0 立即失败——compute batch 的
PATH里没有 FFmpeg。SSH 登录后能运行,不代表 batch 环境能运行 - R1 改为引用 frozen runtime 里带哈希的 static FFmpeg 7,预检
minterpolate、acrossfade、PyAV 和三段输入 - R2 在
set -o pipefail下把长输出直接送给grep -q;grep 匹配到就提前退出,生产端收到 SIGPIPE,整个 capability check 被判失败。改成先捕获完整输出再匹配 - R3 的 MP4 已改用
$MEDIA_DIR,.done校验仍读默认目录,路径合同不统一
然后是版本行为差异:本机 FFmpeg 8 每段输出 240 帧,集群固定的 FFmpeg 7 在相同 minterpolate 链末尾只 flush 239 帧。R4 因此产出 717 帧,被结构 validator 拦下。
R5 用 tpad=clone 补三帧,形式上 720 帧、24 FPS、30 秒,validator 全过。但逐帧 QA 发现 frame 239/479/719 成了全片运动最低的三帧,10 秒前出现「停一帧再跳一步」的微顿挫。它通过了容器合同,破坏了动作语义,所以内部 HOLD 未发布。
R6 用确定性方案:
每段 = 前 239 个 MCI 输出 + 显式追加原始源 frame 242
[src] split [motion_input][endpoint_input]
[motion_input]
-> setpts(239/242)
-> minterpolate(24fps, MCI/AOBMC/BIDIR)
-> trim(239 frames)
[endpoint_input]
-> select(source frame 242)
[motion_239][source_endpoint]
-> concat(240 frames)
这样不依赖 FFmpeg 版本的 EOF flush 行为,同时保留了模型被锚点约束的真实末帧。
语义 gate
R6 在 720 帧和连续 PTS 之外加了一组语义门槛:6 个 remaster 段首尾对冻结 G6 源视频端点的 SSIM ≥ 0.996;10 秒 join SSIM ≥ 0.980;20 秒 join SSIM ≥ 0.970;完整音视频严格解码;黑帧、冻结、非静音、AAC packet end 检查;光流敏感区域的人工抽样(雨线、围巾、栏杆、快速腿部、遮挡、背景)。
6 endpoint SSIM: 0.996787 .. 0.998840
10 s join SSIM: 0.983828
20 s join SSIM: 0.976954
video: 1920x1080 / 24 fps / 720 frames / 30.000 s
audio: AAC / 32 kHz / stereo / 960000 ticks
state: COMPLETED / 0:0
发布与回滚
R6 用独立 attempt 目录,结构与语义 gate 全部通过后才原子改名,发布目录按 job ID 隔离。G6 源段同样按 attempt 隔离,但它的 wrapper 是先把 MP4 从 temp 改名、再做 post-generation 验证,验证成功才写 done receipt——这两条路径的顺序不同。
一个发布包含最终媒体、verification JSON、final.done、release.sha256。
回滚脚本只允许把当前 job 的发布目录原子移动到固定归档名,执行前断言:job 的 Slurm 状态和 exit code;发布目录 realpath、非 symlink、精确 allowlist;成片字节数与 SHA-256;原始 source segments 的哈希;前一版成片和被拒候选仍保持原哈希。回滚后再验 attempt、source、旧片的 hash 和 stat 均未改变。
对真实发布目录跑过 preview,在同构 fixture 上实际执行过 rollback,唯一变化是目标发布目录的 rename。
失败时间线
| 阶段 | 症状 | 根因 | 修复 |
|---|---|---|---|
| 存储 | /data 存在但客户端挂载失败 | 旧池不可用;普通目录不满足 NFS mountpoint 条件 | 在健康池上重建 models/data 合同 |
| Canary | GRES/daemon 假失败 | NVML per-device 记录写 stderr;PMIx 插件已构建但目标机缺 runtime | 合并 stdout/stderr;装 PMIx runtime;Delegate=yes 作独立门槛 |
| 配置验证 | slurmctld -t 只返回 usage,重入抢占 live 端口 | production-state isolation 不足 | 隔离端口/状态目录前台启动;live daemon 走 reconfigure/ping |
| Accounting | 首次接入后 controller 起不来 | 验证器先误判 slurmdbd wildcard listener;随后查出 controller state 与 DBD 的 ClusterID 真的对不上 | systemd policy 加正负连通性验证;受控采用 DBD ClusterID |
| Web | 页面端口不通 | solely-internal Docker 网络不发布端口 | 独立 ingress bridge,仅绑 loopback |
| Web reapply | Compose 临时容器竞争 | watchdog timer 与 recreate 并发 | pause/drain timer,共享锁,forced handler |
| 112-GPU 验收 | 每台 8 卡被判成 7 卡 | 七个逗号当成七个字段 | 修正计数 oracle,保留 fail-closed rescue |
| G1 | 声明 640×384 仍八卡 OOM | geometry 未进入 runtime request,自动大画布令 activation 超限 | 显式传 geometry,保留 TP8 与 sensitive FP32 |
| G2/G3 | 声明低分辨率仍 OOM | target_shape 没传入 runner,实际是默认大画布 | input object 显式传 geometry,并打印 packed layout |
| G4 | 试验无效 | 使用带 geometry 缺陷的冻结资产 | 主动取消,不包装成证据 |
| C1 | 取消后原 cleanup step 不可复用 | G4 已离开可创建 step 的状态 | 独立 cleanup recovery,只清该 job runtime |
| G5 | Canary 成功 | 真实 640×384×243 生效 | 8/8 receipts 与 13.086 GiB 峰值放行 full |
| G6 | 三段生成成功 | — | 三节点 TP8 并行,job-local cleanup |
| R0 | preflight 立即失败 | batch PATH 没有 FFmpeg | 固定 static binary 的绝对路径与哈希 |
| R2 | capability grep 失败 | pipefail + grep -q 触发上游 SIGPIPE | 先捕获完整输出再匹配 |
| R3 | 输入文件校验失败 | MP4 与 .done 用不同目录变量 | 统一 $MEDIA_DIR 合同 |
| R4 | 只有 717 帧 | FFmpeg 7 minterpolate EOF 行为不同 | 不依赖隐式 flush |
| R5 | 720 帧仍有微顿挫 | clone 尾帧掩盖缺帧 | 内部 HOLD,新增语义 gate |
| R6 | PASS | 239 MCI + 明确源末帧 | endpoint/join SSIM 与视听 QA 后发布 |
缺口
- 单故障域。 storage、controller、accounting 和 Web 仍集中在一台,没有 backup controller 和 backup DBD
- 备份代次不够。 MariaDB 只有本机和同一 storage 池内的恢复代次,需要异机、加密、定期演练
- Web 无身份。 Slurm-web 是 Tailnet 内 anonymous read-only 观察界面,没有 OIDC/LDAP 和逐用户审计
- 没开 association/limit enforcement。 QoS、多租户配额和公平分享都未完成
- pending 节点。 需要恢复网络并重新验证身份、GPU、NFS、时钟后才能加入
- Tailnet 提交作业只完成设计。 边界应该是 Tailnet ACL/身份校验 → loopback job broker → 固定 workflow allowlist →
sbatch,直接开放slurmrestd写接口或 anonymous Web 权限都不合适 - 快速腿部仍有轻微软化,末段角色风格漂移来自源生成内容,本轮没有重新推理消除
Slurm 基础设施验收通过、H3 runtime 跑通、媒体质量 PASS 是三个不同层次的结论。184000 MiB 是每节点 scheduler memory,与物理 RAM 是两个数。