当 Slurm 节点宕机时如何恢复正在运行的容器作业

解读

在国内超算中心、高校 HPC 平台及 AI 训练集群里,Slurm 仍是事实标准的资源调度器,而 Docker 容器作业(尤其是 GPU 训练、MPI 并行任务)越来越普遍。
节点宕机(主板、GPU、系统盘故障或机房断电)后,容器进程随节点内核一起消失,但作业在 Slurm 视角仍处于 RUNNING 状态,直到 Slurm 通过 slurmd 心跳超时(默认 30 s)判定节点 DOWN,再把作业标记为 FAILED。
面试官真正关心的是:

  1. 你是否理解 Slurm 与 Docker 的生命周期差异
  2. 能否在 不破坏调度语义 的前提下,把作业“原地复活”或“漂移到其他节点继续跑”;
  3. 是否具备 数据一致性、日志可回溯、重跑不重复消耗配额 的工程闭环思维。

知识点

  1. Slurm 作业状态机:RUNNING → NODE_FAIL/FAILED → 重调度策略(JobRequeue、ResumeTimeout、OverTimeLimit)。
  2. Docker 容器持久化:--restart=always 对节点宕机无效,必须依赖外部 checkpoint/restore 机制或业务级断点续训
  3. CRIU(Checkpoint/Restore In Userspace)在 3.x 内核后已进主线,但 国内生产内核普遍关闭 CONFIG_CHECKPOINT_RESTORE;因此基于 CRIU 的 docker checkpoint 在多数超算中心不可用
  4. Slurm 的 JobContainerType=jobscript_tmpfsProlog/Epilog 钩子,可在作业启动前挂载共享盘、注入环境变量,用于保存断点。
  5. 共享存储:Lustre、GPFS、NFS、CephFS,必须保证所有 Compute Node 挂载同一目录且 UID/GID 一致,否则容器重启后读不到断点。
  6. Slurm Requeue 机制:scontrol requeue 可把 FAILED 作业重新排队,配合 --requeue 提交参数与 --no-kill,实现“节点挂→作业失败→自动重排队”。
  7. 日志与指标:作业内部把 epoch/step 写入 /jobdir/.checkpoint,同时通过 slurm_spank 插件 把 GPU 利用率、节点 UUID 写入 SlurmDBD,方便二次调度时排除故障节点。
  8. 安全合规:国内等保 2.0 要求 容器镜像仓库必须开启镜像签名与漏洞扫描,恢复时禁止回退到有 CVE 的旧镜像。

答案

分三层回答,先给结论再给落地细节,面试时可直接背诵。

第一层:原则
“让作业可重跑,而不是让容器原地复活。”——因为国内生产内核普遍禁用 CRIU,Docker 容器一旦节点宕机即无法热迁移,所以必须把“作业状态”与“容器运行时”解耦,靠业务级断点 + Slurm 重排队实现恢复。

第二层:落地四步

  1. 提交作业时显式加 --requeue--no-kill,并挂载共享目录:
    sbatch --requeue --no-kill --gres=gpu:4 \
           --job-dir=/lustre/share/job_$SLURM_JOB_ID \
           docker_run.sh
    
  2. 在 docker_run.sh 的 Prolog 阶段先检查 /lustre/share/job_$SLURM_JOB_ID/.checkpoint,若存在则从最近 epoch 开始续训;否则从头训练。
  3. 训练循环每 10 min 调用一次 torch.save(checkpoint) 到共享盘,checkpoint 文件名带 epoch 与 global_step,确保幂等。
  4. 节点宕机后,Slurm 判定作业为 NODE_FAIL,自动 requeue 到新的可用节点;新节点启动容器后,Prolog 检测到旧 checkpoint,直接加载继续训练,实现“宕机-恢复”对业务透明。

第三层:运维兜底

  • 通过 scontrol update NodeName=failed-node State=DOWN Reason=HWfault 把故障节点立即置 DOWN,防止调度器继续分配。
  • 若作业因 超过 ResumeTimeout(默认 60 s) 仍无法重跑,则触发告警,人工介入检查共享盘损坏或镜像拉取失败。
  • 恢复后使用 sacct -j <job_id> -o jobid,exitcode,ncpus,nnodes,state%20 输出审计,保证资源计费不重复。

拓展思考

  1. 如果集群采用 Singularity 而非 Docker,是否可以用 singularity instance checkpoint?——国内多数超算中心仍关闭 CRIU,结论相同,仍需业务级断点
  2. 若作业是 MPI 多节点并行容器,宕机后只能整体重跑,因为 MPI 通信上下文无法重建;此时需把 --requeuePMIX_MCA_psec=native 结合,并在 OpenMPI 启动参数里加 --mca mpi_ft_checkpoint false,避免 MPI 层误拦截 SIGTERM。
  3. 未来可调研 KubeSlurmSlurm-on-K8s 混合部署,把长作业放到 K8s StatefulSet + Volcano,利用 etcd 保存 Pod 元数据,实现“节点宕机-Pod 漂移-容器重启”自动化,但需解决国内 HPC 网络拓扑(OPA/InfiniBand)在 K8s 下 RDMA 插件成熟度不足的问题。