Slurm / srun, sbatch === ###### tags: `Slurm` ###### tags: `Slurm`, `HPC`, `Linux`, `Slinky`, `SlinkyProject`, `sbatch` <br> [TOC] <br> ## srun 範例 - ### 最基本指令 -- 不限定特定 node - ### 查詢主機名稱 ``` $ srun hostname esc8000a-1 ``` - ### 查詢 GPU 狀態 ``` $ srun nvidia-smi ``` - ### 進入節點互動 ``` $ srun --pty bash -i ``` - ### 根據 GPU 需求配置節點 ``` $ srun --gres='gpu:8' nvidia-smi -L ``` - ### 以容器方式執行 > https://github.com/SlinkyProject/slurm-operator/issues/41 ``` # 不需要 GPU 情況: $ srun --container docker://alpine:latest id uid=0(root) gid=0(root) groups=0(root) $ srun --container-image alpine:latest id pyxis: importing docker image: alpine:latest pyxis: imported docker image: alpine:latest uid=0(root) gid=0(root) groups=0(root) ``` ``` # 需要 GPU 情況: $ srun --container-image nvcr.io/nvidia/pytorch:23.10-py3 --pty bash ``` - ### 指定 partition (分區的任意 node) + GPU 需求 ``` $ srun -p debug --gres='gpu:8' nvidia-smi -L ``` ``` $ srun -p tn --gres='gpu:8' bash -c "hostname & nvidia-smi -L" esc8000a-1 GPU 0: NVIDIA A40 (UUID: GPU-35729da9-1b69-c8f6-9f22-************) GPU 1: NVIDIA A40 (UUID: GPU-157a6555-49d1-07bc-bf97-************) GPU 2: NVIDIA A40 (UUID: GPU-14c00e59-b533-e691-f568-************) GPU 3: NVIDIA A40 (UUID: GPU-228d9110-2bf1-6707-1afe-************) GPU 4: NVIDIA A40 (UUID: GPU-755ec026-8359-581c-b638-************) GPU 5: NVIDIA A40 (UUID: GPU-960a7fde-5e36-47d9-64e0-************) GPU 6: NVIDIA A40 (UUID: GPU-9c40d7e3-7322-d916-c6a9-************) GPU 7: NVIDIA A40 (UUID: GPU-b42813b5-fbfe-100d-d062-************) ``` - ### 指定 node + GPU 需求 ``` $ srun --nodelist=esc8000b-0 --gres='gpu:8' nvidia-smi -L ``` - ### 指定 partition + 限定 GPU 類型 + GPU 需求 ``` $ srun -p debug --nodelist=esc8000b-0 --gres='gpu:8' nvidia-smi -L ``` <br> ## sbatch 範例 ### `hello.sbatch` ```bash= #!/bin/bash #SBATCH --job-name=hello # 作業名稱(會出現在佇列與輸出檔) #SBATCH --partition=debug # 指定要丟到哪個 Partition(依你的環境調整) #SBATCH --ntasks=1 # 啟動 1 個任務(process) #SBATCH --cpus-per-task=1 # 每個任務使用 1 顆 CPU #SBATCH --output=slurm-%x-%j.out # 輸出檔名:slurm-<jobname>-<jobid>.out ##SBATCH --time=00:05:00 # (選用) 最長執行時間,超時會被 Slurm 終止 ##SBATCH --gres=gpu:1 # (選用) 需要 1 張 GPU;需叢集支援 GPU 資源管理 echo "=== Job started on $(hostname) at $(date) ===" echo "SLURM_JOB_ID=$SLURM_JOB_ID" echo "SLURM_JOB_NODELIST=$SLURM_JOB_NODELIST" # 方式 A:直接在批次環境中執行一個最簡單的 hello srun bash -lc 'echo "Hello from $(hostname)"; sleep 1' # 方式 B:(選用)在容器裡跑 nvidia-smi -L ,需叢集有 Pyxis/Enroot # srun --container-image=nvcr.io/nvidia/pytorch:23.10-py3 nvidia-smi -L #(如果要把目前目錄掛進容器,可加) # --container-mounts="$PWD:/workspace" echo "=== Job finished at $(date) ===" ``` - ### 每一行在做什麼? * `#!/bin/bash` 指定用 bash 來執行這支批次腳本。 * `#SBATCH --job-name=hello` 設定作業名稱,便於在 `squeue`、輸出檔中辨識。 * `#SBATCH --partition=debug` 指定投遞到哪個 Partition(資源池)。沒有這個 partition 會 Pending;可用 `sinfo` 查看可用的 partition。 * `#SBATCH --ntasks=1` 要啟動的「任務數」。一般 CPU 單機工作一個就夠;MPI 或多任務才會大於 1。 * `#SBATCH --cpus-per-task=1` 每個任務綁定的 CPU 數。若你的程式會用到多執行緒,這裡要調大。 * `#SBATCH --output=slurm-%x-%j.out` 指定標準輸出與錯誤輸出要寫到哪個檔案(`%x`=job 名稱,`%j`=job ID)。 * `##SBATCH --time=00:05:00`(註解掉=暫不生效) 最長執行時間。建議給個合理值,能幫排程器安排資源並避免無限卡住。 * `##SBATCH --gres=gpu:1`(註解掉=暫不生效) 要求 GPU;需叢集已配置 GPU 與對應的 QOS/Partition 支援。 * `echo ...` 打出開始/結束時間與節點資訊,方便除錯與審計。 * `srun bash -lc 'echo "Hello from $(hostname)"; sleep 1'` 用 `srun` 在分配到的資源裡執行命令。即使在 `sbatch` 腳本內,建議用 `srun` 來啟動實際工作,能確保與資源配置的一致性(特別是多任務/多節點時)。 * (選用)`srun --container-image=... nvidia-smi -L` 在容器(Enroot `.sqsh`)中跑 `nvidia-smi -L` 列出 GPU。需要叢集有 **Pyxis/Enroot** 外掛;沒有就把這行保持註解狀態。 想把工作目錄掛進容器再加:`--container-mounts="$PWD:/workspace"`。 --- - ### 如何執行? 1. 存檔 把內容存成 `hello.sbatch`(檔案不必 `chmod +x`,`sbatch` 會直接讀取)。 2. 提交作業 ```bash sbatch hello.sbatch ``` 會回覆類似: ``` Submitted batch job 123456 ``` 3. 查看排程狀態 ```bash squeue -j 123456 # 看這個 job 的狀態 squeue -u $USER # 看自己所有 job sinfo -s # 看各 Partition 概況 ``` 4. 追蹤輸出檔(最即時) ```bash tail -f slurm-hello-123456.out ``` (若你沒自訂 `--output`,預設檔名是 `slurm-123456.out`) 5. 查歷史紀錄與資源使用 ```bash sacct -j 123456 \ --format=JobID,JobName,Partition,State,Elapsed,AllocTRES,MaxRSS,NodeList ``` 或看更詳細: ```bash scontrol show jobid -dd 123456 ``` 6. 取消作業(若卡住或不需要) ```bash scancel 123456 ``` --- - ### 小提醒 / 常見坑 * **Partition 名稱**要真實存在;用 `sinfo` 確認。 * 若執行容器那行出現 `pyxis` 相關錯誤,代表叢集沒裝 **Pyxis/Enroot**,請改用非容器的 `srun` 指令或用叢集支援的容器方式。 * 要 GPU 請確保使用了對應的 **Partition/QOS** 且帳號有權限,否則會長時間 Pending(`Reason=QOSMaxGRES`、`(Priority)` 等)。 * `--time` 沒設定時會用 Partition 或叢集預設上限;建議給一個合理值,利於排程。 <br> ## 討論 ### 如何查看 sbatch 的執行結果? - ### Question ``` $ sbatch -A tj-account -p debug -N1 -n1 --wrap='hostname && whoami' Submitted batch job 959 ``` 要如何查看執行結果? - ### gpt-5 (2025/08/28) 最直接的方法有三種:看 **狀態**、找 **輸出檔**、查 **帳務紀錄**。 ### 1) 先看工作狀態 ```bash # 只看這個工作 squeue -j 959 # 看詳細資訊(含原因、輸出路徑等) scontrol show job 959 | egrep 'JobState|Reason|NodeList|StdOut|WorkDir' ``` - **執行範例**: ``` $ scontrol show job 959 JobId=959 JobName=wrap UserId=tmp1(20011) GroupId=tj-account(1002) MCS_label=N/A Priority=1 Nice=0 Account=tj-account QOS=normal JobState=FAILED Reason=RaisedSignal:53(Real-time_signal_19) Dependency=(null) Requeue=1 Restarts=0 BatchFlag=1 Reboot=0 ExitCode=0:53 RunTime=00:00:01 TimeLimit=UNLIMITED TimeMin=N/A SubmitTime=2025-08-28T07:07:53 EligibleTime=2025-08-28T07:07:53 AccrueTime=2025-08-28T07:07:53 StartTime=2025-08-28T07:07:53 EndTime=2025-08-28T07:07:54 Deadline=N/A SuspendTime=None SecsPreSuspend=0 LastSchedEval=2025-08-28T07:07:53 Scheduler=Main Partition=tn AllocNode:Sid=slurm-login-6fb5d948d6-5mcvp:193068 ReqNodeList=(null) ExcNodeList=(null) NodeList=esc8000b-0 BatchHost=esc8000b-0 StepMgrEnabled=Yes NumNodes=1 NumCPUs=2 NumTasks=1 CPUs/Task=1 ReqB:S:C:T=0:0:*:* ReqTRES=cpu=1,mem=240G,node=1,billing=1 AllocTRES=cpu=2,mem=240G,node=1,billing=2 Socks/Node=* NtasksPerN:B:S:C=0:0:*:* CoreSpec=* MinCPUsNode=1 MinMemoryNode=0 MinTmpDiskNode=0 Features=(null) DelayBoot=00:00:00 OverSubscribe=OK Contiguous=0 Licenses=(null) LicensesAlloc=(null) Network=(null) Command=(null) WorkDir=/home/tmp1 StdErr=/home/tmp1/slurm-959.out StdIn=/dev/null StdOut=/home/tmp1/slurm-959.out ``` ### 2) 讀取輸出檔(預設在提交指令的目錄) `sbatch` 預設把 stdout/stderr 寫到 `slurm-<JobID>.out`。 你的例子應該是: ```bash ls -l slurm-959.out cat slurm-959.out # 即時追蹤(工作還在跑也看得到) tail -f slurm-959.out ``` > 不確定檔案在哪?用這招查路徑: > `scontrol show job 959 | grep StdOut`(同時也可看 `WorkDir`) ### 3) 查完成後的帳務/結果(含退出碼) ```bash # 工作結束後可用(需要 slurmdbd 正常) sacct -j 959 \ --format=JobID,JobName%18,Partition,Account,User,State,ExitCode,Elapsed,NodeList ``` - **執行範例**: ``` $ sacct -j 959 \ --format=JobID,JobName%18,Partition,Account,User,State,ExitCode,Elapsed,NodeList JobID JobName Partition Account User State ExitCode Elapsed NodeList ------------ ------------------ ---------- ---------- --------- ---------- -------- ---------- --------------- 959 wrap tn tj-account tmp1 FAILED 0:53 00:00:01 esc8000b-0 959.batch batch tj-account CANCELLED 0:53 00:00:01 esc8000b-0 959.extern extern tj-account COMPLETED 0:0 00:00:01 esc8000b-0 ``` --- #### 小技巧 * 之後可以自訂輸出檔路徑與名稱,方便找: ```bash sbatch -A tj-account -p tn \ -o /shared/slurm-logs/%x-%j.out -e /shared/slurm-logs/%x-%j.err \ --wrap='hostname && whoami' ``` 其中 `%x`=JobName、`%j`=JobID。 * 若卡在 `PENDING`,用: ```bash scontrol show job 959 | egrep 'JobState|Reason|Partition|QOS|Account|TRES' ``` 看 `Reason`(例如資源不足、QOS/配額限制等)。 <br> ### 沒有看到 sbatch 的執行結果? > :warning: **關鍵點**: > - compute node 的 user id ,要跟 login node 的 user id 一致 > - gid 不一致好像不影響 - ### Question ``` $ sbatch -A tj-account -p debug -N1 -n1 --wrap='hostname && whoami' Submitted batch job 961 ``` 執行了 sbatch, 但在 login 節點或是 compute 節點,都沒看到 961.out ``` tmp1@slurm-login-6fb5d948d6-5mcvp:~$ scontrol show job 961 JobId=961 JobName=wrap UserId=tmp1(20011) GroupId=tj-account(1002) MCS_label=N/A Priority=1 Nice=0 Account=tj-account QOS=normal JobState=FAILED Reason=RaisedSignal:53(Real-time_signal_19) Dependency=(null) Requeue=1 Restarts=0 BatchFlag=1 Reboot=0 ExitCode=0:53 RunTime=00:00:01 TimeLimit=UNLIMITED TimeMin=N/A SubmitTime=2025-08-28T07:13:57 EligibleTime=2025-08-28T07:13:57 AccrueTime=2025-08-28T07:13:57 StartTime=2025-08-28T07:13:57 EndTime=2025-08-28T07:13:58 Deadline=N/A SuspendTime=None SecsPreSuspend=0 LastSchedEval=2025-08-28T07:13:57 Scheduler=Main Partition=debug AllocNode:Sid=slurm-login-6fb5d948d6-5mcvp:193068 ReqNodeList=(null) ExcNodeList=(null) NodeList=e900-0 BatchHost=e900-0 StepMgrEnabled=Yes NumNodes=1 NumCPUs=2 NumTasks=1 CPUs/Task=1 ReqB:S:C:T=0:0:*:* ReqTRES=cpu=1,mem=240G,node=1,billing=1 AllocTRES=cpu=2,mem=240G,node=1,billing=2 Socks/Node=* NtasksPerN:B:S:C=0:0:*:* CoreSpec=* MinCPUsNode=1 MinMemoryNode=0 MinTmpDiskNode=0 Features=(null) DelayBoot=00:00:00 OverSubscribe=OK Contiguous=0 Licenses=(null) LicensesAlloc=(null) Network=(null) Command=(null) WorkDir=/home/tmp1 StdErr=/home/tmp1/slurm-961.out StdIn=/dev/null StdOut=/home/tmp1/slurm-961.out ``` ``` root@slurm-login-6fb5d948d6-5mcvp:/tmp# ll /home total 36 drwxr-xr-x 1 root root 4096 Aug 28 06:42 ./ drwxr-xr-x 1 root root 4096 Aug 26 03:44 ../ drwxr-x--- 2 tmp1 tj-account 4096 Aug 28 07:09 tmp1/ root@slurm-login-6fb5d948d6-5mcvp:/tmp# ll /home/tmp1 total 24 drwxr-x--- 2 tmp1 tj-account 4096 Aug 28 07:09 ./ drwxr-xr-x 1 root root 4096 Aug 28 06:42 ../ -rw------- 1 tmp1 tj-account 260 Aug 28 07:09 .bash_history -rw-r--r-- 1 tmp1 tj-account 220 Mar 31 2024 .bash_logout -rw-r--r-- 1 tmp1 tj-account 3771 Mar 31 2024 .bashrc -rw-r--r-- 1 tmp1 tj-account 807 Mar 31 2024 .profile ``` ``` $ kubectl -n slurm exec -it pod/slurm-compute-e900-0 -- bash root@e900-0:/tmp# ll /home/ total 8 drwxr-xr-x 1 root root 4096 Aug 26 09:26 ./ drwxr-xr-x 1 root root 4096 Aug 5 14:13 ../ ``` - ### gpt-5 (2025/08/28) 你這個症狀其實已經「自白」了: * `scontrol show job 961` 顯示 * `StdOut=/home/tmp1/slurm-961.out` * `WorkDir=/home/tmp1` * `BatchHost=e900-0` * 但 **compute 節點 pod `slurm-compute-e900-0` 裡根本沒有 `/home/tmp1`(甚至 `/home/` 是空的)** * 結果:Slurm 在 **e900-0** 要建立/寫入 `/home/tmp1/slurm-961.out` 時 I/O 失敗,工作被即時訊號殺掉 → `JobState=FAILED Reason=RaisedSignal:53(Real-time_signal_19)`;這類代碼常見成因就是 **stdout/stderr 路徑不存在或無法寫入**。([Stack Overflow][1], [bugs.schedmd.com][2], [Reddit][3]) 換句話說:**login pod 有 `/home/tmp1`,compute pod 沒有**;/home 沒有做共享掛載。 --- ### 立刻確認 / 取得輸出(快速救急) 1. 直接用 `srun` 偵錯(會把輸出寫回終端,不依賴檔案): ```bash srun -A tj-account -p debug -N1 -n1 bash -lc 'hostname && whoami' ``` - 這能快速看出是否是路徑/權限問題(`sbatch` 常把這類錯誤吞掉)。([Stack Overflow][1]) - `bash -lc 'hostname && whoami'` - `-l`:代表 **login shell**,會讓 `bash` 模擬使用者登入時的環境(讀取 `/etc/profile`、`~/.bash_profile` 等設定檔)。 - `-c`:代表 **command**,後面接要執行的字串命令。 - **指令意思**: 啟動一個登入型的 bash,再執行 `'hostname && whoami'` 這串命令。 - ### :warning: Error: couldn't chdir to `/home/tmp1': Permission denied: going to /tmp instead ``` $ srun -A tj-account -p debug -N1 -n1 bash -lc 'hostname && whoami' [2025-08-28T07:30:02.233] error: couldn't chdir to `/home/tmp1': Permission denied: going to /tmp instead [2025-08-28T07:30:02.235] error: couldn't chdir to `/home/tmp1': Permission denied: going to /tmp instead /usr/bin/bash: /home/tmp1/.bash_profile: Permission denied e900-0 tmp1 ``` - **原因**:login pod 的 user id,跟 compute pod 的 user id 不一致 - **解法**:建立 user OS 帳號時,需指定相同 uid (`-u 20011`) ``` sudo useradd -m -u 20011 -s /bin/bash tmp1 ``` 2. 用存在的目錄當輸出與工作目錄(在 **compute** 一定存在的如 `/tmp`)再試一次: ```bash sbatch -A tj-account -p debug \ --chdir=/tmp \ -o /tmp/slurm-%j.out -e /tmp/slurm-%j.err \ --wrap='hostname && whoami' ``` - 其中 `%j`=JobID 、 `%x`=JobName (`%x='wrap'`)。 跑完到 **compute 節點 pod** 取檔: ```bash kubectl -n slurm exec -it pod/slurm-compute-e900-0 \ -- bash -lc 'ls -l /tmp/slurm-*.out; tail -n +1 /tmp/slurm-*.out' ``` 3. 查帳務記錄(看退出碼/狀態): ```bash sacct -j 961 --format=JobID,State,ExitCode,NodeList,StdOut,WorkDir ``` - **執行範例**: ``` $ sacct -j 961 --format=JobID,State,ExitCode,NodeList,StdOut,WorkDir JobID State ExitCode NodeList StdOut WorkDir ------------ ---------- -------- --------------- -------------------- -------------------- 961 FAILED 0:53 e900-0 /home/tmp1/slurm-%j+ /home/tmp1 961.batch CANCELLED 0:53 e900-0 961.extern COMPLETED 0:0 e900-0 ``` > 遇到 Linux 訊號終止(含 real-time signals),Slurm 會把訊號號碼記錄在 ExitCode 後半部。([Slurm][4]) --- ### 正解:把 **/home** 做成共享掛載(login 與 compute 都要同一份) 目前你在 login pod 看得到 `/home/tmp1`,但在 compute pod 看不到 → **/home 未共享**。要修好: 1. 準備一個可共享的儲存(NFS 或 PVC)並放使用者家目錄: * 例:NFS 伺服器上 export `/nfs/home`,或 K8s 建 `home-pvc`(容量依需求)。 2. **同時**把這個卷掛到 * login pod:`mountPath: /home` * 所有 slurmd 的 compute pods:`mountPath: /home` 3. 確保目錄與擁有者一致(UID/GID 在 login/compute 一致)。你的 `tmp1` 是 `uid=20011`、`gid=tj-account(1002)`,所以在共享卷上要: ```bash # 在共享卷上(一次就好) mkdir -p /home/tmp1 chown 20011:1002 /home/tmp1 chmod 750 /home/tmp1 ``` > 具體怎麼在 Helm values 設置要看你用的 chart/版本,但原則就是:**同一個 PVC/NFS 同時掛到 login 與 slurmd pods 的 `/home`**。若暫時無法調整,至少在每個 compute pod 先建立目錄(僅測試用,pod 重建就沒了): ```bash kubectl -n slurm exec -it pod/slurm-compute-e900-0 \ -- bash -lc 'mkdir -p /home/tmp1 && chown 20011:1002 /home/tmp1' ``` --- ## 之後的最佳實務 * 明確指定輸出位置到**共享**路徑(好找又持久): ```bash sbatch -A tj-account -p debug \ -o /home/tmp1/slurm/%x-%j.out \ -e /home/tmp1/slurm/%x-%j.err \ --wrap='hostname && whoami' ``` - 其中 `%j`=JobID 、 `%x`=JobName (`%x='wrap'`)。 (先 `mkdir -p /home/tmp1/slurm`) * 若看到 `RaisedSignal:53` 或 `.out` 檔不見蹤影,**第一時間檢查輸出路徑是否存在/可寫、配額是否滿**。([bugs.schedmd.com][2], [HPC Community][5]) --- ### 為什麼你剛剛兩邊都找不到 `slurm-961.out`? 因為 Slurm 試圖在 **e900-0** 的 `/home/tmp1/` 建檔,但 **那個路徑不存在**,工作一開始就因 I/O 問題被結束;自然就沒有任何 `.out` 可以在 login 或 compute 的 `/home` 找到。這正是社群常見案例:**stdout 目錄不存在 → 失敗且常看不到明確錯誤**。([Stack Overflow][1], [bugs.schedmd.com][2]) 需要的話,我可以幫你把目前的 Helm values 片段貼過來,給你對應的 `extraVolumes/extraVolumeMounts`(或 chart 自帶的 home 共享設定)範例,直接套用到 login 與 slurmd。 [1]: https://stackoverflow.com/questions/77642713/all-slurm-jobs-fail-silently-with-exit-code-053?utm_source=chatgpt.com "All slurm jobs fail silently with exit code 0:53" [2]: https://bugs.schedmd.com/show_bug.cgi?id=8895&utm_source=chatgpt.com "Slurm job output to non-existent directory result into silent ..." [3]: https://www.reddit.com/r/HPC/comments/1fklwa6/need_help_slurm_error_code_053/?utm_source=chatgpt.com "Need Help SLURM Error Code 0:53 : r/HPC" [4]: https://slurm.schedmd.com/job_exit_code.html?utm_source=chatgpt.com "Job Exit Codes - Slurm Workload Manager - SchedMD" [5]: https://hpc-community.unige.ch/t/cpu-gpu-job-failing/3432?utm_source=chatgpt.com "CPU/GPU job failing" <br> {%hackmd vaaMgNRPS4KGJDSFG0ZE0w %}