Slurm / 指令 / srun, sbatch, squeue, sacct === ###### tags: `Slurm` ###### tags: `Slurm`, `HPC`, `Linux`, `Slinky`, `SlinkyProject`, `sbatch`, `squeue`, `sacct`, `enroot` <br> [TOC] <br> ## 檢查當前可用資源 ``` # 檢查當前可用資源 $ sinfo -N -l Mon Dec 15 07:22:57 2025 NODELIST NODES PARTITION STATE CPUS S:C:T MEMORY TMP_DISK WEIGHT AVAIL_FE REASON c2m4-0 1 cpu-set* idle 88 2:22:2 515856 0 1 c2m4,c2m none c4m16-0 1 cpu-set* idle 88 2:22:2 515856 0 1 c4m16,c4 none ``` <br> --- <br> ## srun 範例 -- 基本操作 > 最基本指令操作 ### 查詢主機名稱 ``` $ srun hostname esc8000a-1 ``` <br> ### 進入節點互動 ```bash $ srun --pty bash $ srun --pty bash -i # -i: interactive shell, 強制成互動 (預設可忽略 -i ) ``` - `--pty`: pseudo-terminal(偽終端機) - 與遠端執行的 shell 進行互動,輸入命令並立即看到輸出 > 當您在 Slurm 環境中使用 `srun` 運行一個作業時,通常情況下,您的作業會作為一個批次程序在後台或遠端節點上執行,其標準輸入/輸出 (stdin/stdout) 會被重新導向到日誌檔案。 > > 添加 `--pty` 選項會強制 `srun` 為您啟動的任務(在這個例子中是 `bash -i`,一個互動式 shell)分配一個**互動式的偽終端介面**。 > > 簡而言之,--pty 將您的批次作業變成了一個可以即時對話的互動式會話。 - `-i`: interactive shell - 強制成互動 (預設可忽略 -i ) - 差異: - `bash`:看到自己連在 pseudo-tty 上 → 自動判斷為互動 - `bash -i`:再明講一次「我要互動」→ 結果一樣是互動 <br> ### 攜帶環境變數,傳到 srun 任務 - ### 在指令前面加 `VAR=...` ```bash XDG_CACHE_HOME=/tmp/xdg-cache srun ... your_cmd # 或 env XDG_CACHE_HOME=/tmp/xdg-cache srun ... your_cmd ``` - ### 用 Slurm 官方的 `--export`(最推薦、也最清楚) > [slurm.schedmd.com](https://slurm.schedmd.com/srun.html) > - `--export` 可以指定要傳哪些變數,或直接帶值。 - **未指定時預設是 `--export=ALL`** - **範例1**: ```bash srun --export=ALL,FOO=bar,BAZ=123 ... your_cmd ``` - 新增 `FOO` 和 `BAZ` 環境變數 (或蓋掉既有的值) - **範例2**:也可以只傳部分(會自動帶 `SLURM_*` 再加你指定的): ```bash srun --export=EDITOR,ARG1=test ... your_cmd ``` - 傳遞過去的環境變數只會包含:使用者環境中的 `EDITOR` 變數、所有 `SLURM_*` 環境變數,以及 `ARG1=test`。 - **範例3**:不會傳遞任何使用者環境變數。 ```bash srun --export=NONE ... your_cmd ``` <br> ### 指定特定的 node > - **使用參數**: > ``` > -w, --nodelist=hosts... request a specific list of hosts > ``` ```bash $ srun -w c2m4-0 hostname $ srun --nodelist c2m4-0 hostname $ srun --nodelist=c2m4-0 hostname ``` - **如果節點不存在,則會出現底下錯誤**: ``` $ srun -w c2m4-0 hostname srun: error: Unable to allocate resources: Invalid node name specified ``` - **要改用請求 partition,等待資源建立**: ``` $ srun -p cpu-set hostname srun: Requested partition configuration not available now srun: job 164 queued and waiting for resources srun: job 164 has been allocated resources c2m4-0 ``` - **如果某個 partition 有多種 flavor 的 nodeset 可選擇**: - **無法透過 `-p` (`--partition`) + `-w` (`--nodelist`)** ``` $ srun -p cpu-set -w c2m4-0 hostname srun: error: Unable to allocate resources: Invalid node name specified ``` - **要改用:`-p` (`--partition`) + `-C` (`--constraint`)** > - **使用參數**: > ``` > -C, --constraint=list specify a list of constraints > ``` ``` $ srun -p cpu-set --constraint c2m4 srun: Requested partition configuration not available now srun: job 164 queued and waiting for resources srun: job 164 has been allocated resources c2m4-0 ``` - **當前行為**: - partition 下的多個 nodeset ,都會被喚醒 (scale: 0 -> 1) - c2m4-0 節點會被喚醒 - c4m16-0 節點會被喚醒 <br> ### 指定特定的 partition > - **使用參數** > ``` > -p, --partition=partition partition requested > ``` ```bash $ srun -p cpu-set hostname ``` <br> ### 指定特定的 feature > - **使用參數** > ``` > -C, --constraint=list specify a list of constraints > ``` ```bash $ srun -C c2m4 hostname $ srun -C a30 hostname ``` - ### 注意事項 - **Partition 優先於 Feature**: - Slurm 先根據 partition 確定候選節點池,再用 feature 過濾 - **預設 Partition 陷阱**: - `-C` 約束不會跨 partition 搜尋節點 - 如果沒有指定 `-p`,會自動挑選 default partition ``` $ scontrol show partitions PartitionName=a30-set AllocNodes=ALL Default=NO QoS=N/A PartitionName=cpu-set AllocNodes=ALL Default=YES QoS=N/A <-- default partition ``` - 如果某個資源不在 default partition,需要明確指定 `-p <partition-name>` 才能使用 - 沒有配對到相對應的資源,會出現底下的錯誤: ``` srun: error: Unable to allocate resources: Requested node configuration is not available ``` <br> ### 指定 CPU 需求 > - **使用參數** > ``` > -c, --cpus-per-task=ncpus number of cpus required per task > ``` ```bash # 明確指定使用 1 個 core 的 CPU $ srun -c 1 hostname c2m4-0 c2m4-0 ``` - ### 注意事項 - **在指定 `-c 1`,會預帶參數 `-n 2`,因此會印出兩筆** ``` -n, --ntasks=ntasks number of tasks to run ``` - 當你明確指定 `--cpus-per-task` 時,Slurm 會**重新評估** `--ntasks` 的預設值 - 在某些 Slurm 配置下,明確指定 `-c` 會觸發**預設 ntasks=2** 的行為 - 可能根據節點配置(Sockets=2)重新計算預設的 `--ntasks` 值 - 結果:執行 **2 次** `hostname`(因為 ntasks=2) - **明確設定預設 ntasks 行為:** 1. 編輯 `slurm.conf`,明確設定預設 ntasks 行為: ```conf # 在 slurm.conf 中加入或修改 DefCpuPerTask=1 ``` 2. 重新載入 Slurm 配置: ```shell scontrol reconfigure ``` 3. 驗證修正結果: ```shell srun -c 1 hostname # 應該只輸出一次 ``` <br> ### 指定記憶體需求 > - **使用參數** > ``` > --mem=MB minimum amount of real memory > ``` ```bash # 明確指定使用 1G 的記憶體 $ srun --mem=1G hostname $ srun --mem-per-cpu=1G hostname ``` <br> ### 查詢 GPU 狀態 ``` $ srun nvidia-smi ``` <br> ### 根據 GPU 需求配置節點 ``` $ srun --gres='gpu:8' nvidia-smi -L ``` <br> ### 指定 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> --- <br> ## srun 範例 -- 以容器方式執行 > 跑 [pyxis](https://github.com/NVIDIA/pyxis) 容器 ### 預備知識 - `--container-*` 參數,由 pyxis plugin 提供,例如: - `--container-image=docker://ubuntu:24.04` - `--container-env=NAME[,NAME...]` <br> ### 簡易範例 > https://github.com/SlinkyProject/slurm-operator/issues/41 - ### 不需要 GPU 情況 ```bash # 不需要 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) $ srun -p cpu-set -C c4m16 --container-image ubuntu:24.04 hostname pyxis: importing docker image: ubuntu:24.04 pyxis: imported docker image: ubuntu:24.04 c4m16-0 # 要等 7 分鐘? ``` - ### 需要 GPU 情況 ```bash # 需要 GPU 情況: $ srun --container-image nvcr.io/nvidia/pytorch:23.10-py3 --pty bash ``` <br> ### 環境變數傳遞流程 - 預備知識 <br> ### 環境變數傳遞 - ### 環境變數傳遞過程 ``` login 節點 -> (透過 `--export`) -> Slurm 計算節點 -> (透過 `--container-env`) -> 容器內部 ``` - ### 階段一:login 節點 -> 計算節點/(Slurm 世界:slurm node)/(Slinky 世界: worker pod) > Slurm 會決定要把你的任務丟到哪幾台計算節點。此時,`--export` 參數決定了哪些變數要從你現在的螢幕前傳到那幾台計算節點上。 - 由 `--export=...` 控制 - 預設值:`--export=ALL` - **優先權**:login 節點 > `--export=...` ``` export XYZ=123 srun --export=XYZ=789 ... -> 最終結果:XYZ=123 ``` - 有定義過,就不會再重新賦值 - If "ALL" is specified, then all user environment variables will be loaded and will take precedence over any explicitly given environment variables. ([slurm.schedmd.com](https://slurm.schedmd.com/sbatch.html)) - ### 階段二:計算節點/(Slurm 世界:slurm node)/(Slinky 世界: worker pod) -> 容器 - 由 `--container-env=NAME[,NAME...]` 控制 - 預設值:`--container-env=all` - pyxis 的定義:「**只接受變數名稱**」,不是用來做 `NAME=value` 指派的 ([GitHub](https://github.com/NVIDIA/pyxis?tab=readme-ov-file#usage)) - **優先權**: - **預設**:容器環境變數 > 計算節點環境變數 (避免容器內的環境變數,被外面的世界影響) - **使用 `--container-env=NMAE1[,NAME2...]` 參數**:計算節點環境變數 `NAME` > 容器環境變數 (明確定義:由外面世界的環境變數,蓋掉容器內的環境變數) - ### 範例:在階段一(login 節點 -> 計算節點):控制**傳入**/**不傳入** - ### `--export` 不使用 `ALL` 和 `NONE` ``` $ export XYZ=xyz $ srun --export=XYZ=abc \ /usr/bin/bash -c 'env | egrep "XYZ|PATH" || true' XYZ=abc ``` ``` $ export XYZ=xyz $ srun --export=XYZ=abc,ALL \ /usr/bin/bash -c 'env | egrep "XYZ|PATH" || true' PATH=/usr/local/sbin:/usr/local/bin:/usr/sbin:/usr/bin:/sbin:/bin:/usr/games:/usr/local/games:/snap/bin XYZ=xyz ``` - ### `--export=NONE` (不傳入任何環境變數) ``` $ srun --export=NONE,XYZ=789 \ /usr/bin/bash -c 'env | egrep "XYZ|PATH" || true' (沒有任何結果) $ srun --export=XYZ=789,NONE \ /usr/bin/bash -c 'env | egrep "XYZ|PATH" || true' XYZ=789 ``` ``` # 階段一:--export=NONE (不傳入任何環境變數) $ export XYZ=xyz $ srun \ --export=NONE \ --container-image=docker://ubuntu:24.04 \ --container-env=XYZ \ --pty bash -c 'env | grep XYZ' _SLURM_SPANK_OPTION_pyxis_container_env=XYZ ``` - ### `--export=ALL` (傳入所有環境變數) ``` # 階段一:--export=ALL $ export XYZ=xyz $ srun \ --export=ALL \ --container-image=docker://ubuntu:24.04 \ --container-env=XYZ \ --pty bash -c 'env | grep XYZ' _SLURM_SPANK_OPTION_pyxis_container_env=XYZ XYZ=xyz ``` ``` # 階段一:不存在 XYZ 環境變數 $ unset XYZ $ srun \ --export=ALL \ --container-image=docker://ubuntu:24.04 \ --container-env=XYZ \ --pty bash -c 'env | grep XYZ' _SLURM_SPANK_OPTION_pyxis_container_env=XYZ ``` ``` # 階段一:不使用 export 關鍵字 $ XYZ=xyz $ XDG_CACHE_HOME=/tmp srun \ --export=ALL \ --container-image=docker://ubuntu:24.04 \ --container-env=XYZ \ --pty bash -c 'env | grep XYZ' _SLURM_SPANK_OPTION_pyxis_container_env=XYZ ``` - ### 範例:在階段二(計算節點 -> 容器):控制**傳入**/**不傳入** - ### 觀察 ABC 和 XYZ ``` # 階段一:--container-env=ABC (只列 ABC,不列 XYZ) $ export ABC=abc $ export XYZ=xyz $ srun \ --export=ALL,PATH=/this/is/login/path,FOO=bar \ --container-image=docker://ubuntu:24.04 \ --container-env=ABC \ --pty bash -c 'env | egrep "ABC|XYZ|PATH|FOO"' _SLURM_SPANK_OPTION_pyxis_container_env=ABC FOO=bar PATH=/usr/local/sbin:/usr/local/bin:/usr/sbin:/usr/bin:/sbin:/bin (容器內的值) XYZ=xyz (依舊有輸出 XYZ) ABC=abc ``` - ### 觀察 PATH,並比較優先權:login 節點 vs `--export=PATH` ``` # [case 1A] 階段一:--export=ALL,PATH + --container-env=ABC,PATH $ export ABC=abc $ export XYZ=xyz $ srun \ --export=ALL,PATH=/this/is/login/path,FOO=bar \ --container-image=docker://ubuntu:24.04 \ --container-env=ABC,PATH \ --pty bash -c 'env | egrep "ABC|XYZ|PATH|FOO"' _SLURM_SPANK_OPTION_pyxis_container_env=ABC,PATH FOO=bar PATH=/usr/local/sbin:/usr/local/bin:/usr/sbin:/usr/bin:/sbin:/bin:/usr/games:/usr/local/games:/snap/bin (為 login 節點內的值) XYZ=xyz ABC=abc ``` ``` # [case 1B] 階段一:--export=PATH,ALL + --container-env=ABC,PATH $ export ABC=abc $ export XYZ=xyz $ srun \ --export=PATH=/this/is/login/path,ALL,FOO=bar \ --container-image=docker://ubuntu:24.04 \ --container-env=ABC,PATH \ --pty bash -c 'env | egrep "ABC|XYZ|PATH|FOO"' _SLURM_SPANK_OPTION_pyxis_container_env=ABC,PATH FOO=bar PATH=/usr/local/sbin:/usr/local/bin:/usr/sbin:/usr/bin:/sbin:/bin:/usr/games:/usr/local/games:/snap/bin (依舊是 login 節點內的值) XYZ=xyz ABC=abc ``` ``` # [case 2] 階段一:--export=PATH,ALL + --container-env=ABC,PATH $ export ABC=abc $ export XYZ=xyz $ PATH=/this/is/login/path1 \ /usr/bin/srun \ --export=PATH=/this/is/login/path2,ALL,FOO=bar \ --container-image=docker://ubuntu:24.04 \ --container-env=ABC,PATH \ --pty bash -c 'env | egrep "ABC|XYZ|PATH|FOO"' [2025-12-26T08:12:10] error: execve(): bash: No such file or directory srun: error: c2m4-0: task 0: Exited with exit code 2 ``` <br> --- ### 完整範例 ``` srun -p cpu-set -C c4m16 \ --container-image ubuntu:24.04 \ --container-mounts=/work:/mnt/work \ --container-remap-root \ --pty bash ``` - `/work`: 當前 user 在 login pod 中的路徑,不是 user 所在的 host path ``` ``` <br> --- ### 透過 `enroot` 指令 ``` /home/tj_tsai$ export XDG_CACHE_HOME=/home/tj_tsai tj_tsai@slurm-login-slinky-597f646d-m4szz:/home/tj_tsai$ enroot import -o ubuntu-24.04.sqsh 'docker://ubuntu:24.04' [INFO] Querying registry for permission grant [INFO] Authenticating with user: <anonymous> [INFO] Authentication succeeded [INFO] Fetching image manifest list [INFO] Fetching image manifest [INFO] Found all layers in cache [INFO] Extracting image layers... 100% 1:0=0s 20043066d3d5c78b45520c5707319835ac7d1f3d7f0dded0138ea0897d6a3188 [INFO] Converting whiteouts... 100% 1:0=0s 20043066d3d5c78b45520c5707319835ac7d1f3d7f0dded0138ea0897d6a3188 [INFO] Creating squashfs filesystem... Could not create destination file: Permission denied ``` <br> --- ### 情境1:用 `srun` 跑一個 Ubuntu 的映像檔,掛載主機的 `/work`,使用 root 身份執行 - ### gpt-5.2 (2025/12/15) 情境大概像這樣: - 用 `srun` 跑一個 Ubuntu 的映像檔(例如 enroot / OCI image) - 把主機的 `/work` 掛進容器裡(通常也是掛到 `/work`) - 用 `--container-remap-root` 讓容器內變成 root 身份 典型指令長這樣(依你實際的 image 名稱調整): ```bash srun \ --container-image=docker.io/library/ubuntu:22.04 \ --container-mounts=/work:/work \ --container-remap-root \ --pty /bin/bash ``` ### 說明: - ### `--container-image=...` 指定要用的容器映像檔(例如 Ubuntu)。 - ### `--container-mounts=/work:/work` 格式是:`<host_path>:<container_path>` 這裡是把「主機的 `/work`」掛到「容器裡的 `/work`」。 - 如果你想掛到別的路徑,例如 `/mnt/work`,就改成: ```bash --container-mounts=/work:/mnt/work ``` - 如果你有多個目錄要掛載,可以用逗號分隔: ```bash --container-mounts=/work:/work,/home:/home ``` - ### `--container-remap-root` 啟用 root remap,讓你在容器內看到的 UID/GID 是 root(0),但外面仍然用實際的 user 身份去存取檔案(配合 enroot 的 user-mapped root 機制)。 ### 執行範例 ```bash $ srun -p cpu-set -C c4m16 \ --container-image ubuntu:24.04 \ --container-mounts=/work:/mnt/work \ --container-remap-root \ --pty bash srun: Required node not available (down, drained or reserved) srun: job 357 queued and waiting for resources srun: job 357 has been allocated resources pyxis: importing docker image: ubuntu:24.04 pyxis: imported docker image: ubuntu:24.04 # 等待 7-8 分鐘 root@c4m16-0:/# root@c4m16-0:/# cd /mnt/work/ root@c4m16-0:/mnt/work# id uid=0(root) gid=0(root) groups=0(root) root@c4m16-0:/mnt/work# cd root/ bash: cd: root/: Permission denied ``` <br> ### srun: error: Unable to allocate resources: Invalid account or account/partition combination specified - ### 設定1 ```conf AccountingStorageEnforce: associations,limits,safe EnforcePartLimits: ALL ``` ```bash $ srun -p c8m64gt1 --pty bash srun: error: Unable to allocate resources: Invalid account or account/partition combination specified ``` - ### `us.anthropic.claude-sonnet-4-5-20250929-v1:0` (2026/01/19) 根據錯誤訊息 `Invalid account or account/partition combination specified` 和您提供的設定,問題的根本原因是: ### 主要原因參數 **`AccountingStorageEnforce: associations,limits,safe`** 這個參數啟用了帳戶關聯(associations)強制驗證,要求: 1. 使用者必須屬於某個有效的 **Account** 2. 該 Account 必須與指定的 **Partition** 有關聯 3. 必須在 Slurm 資料庫中預先建立這些關聯 ### 為什麼會失敗 當您執行 `srun -p c8m64gt1 --pty bash` 時: - 您沒有使用 `-A` 或 `--account` 參數指定帳戶 - Slurm 嘗試使用您的預設帳戶(或無帳戶) - 由於啟用了 `associations` 強制驗證,Slurm 檢查發現: - 您的使用者沒有與 `c8m64gt1` partition 關聯的有效帳戶 - 或者根本沒有設定帳戶關聯 ### 解決方案 #### 方案 1:建立帳戶關聯(建議) 在 controller 上執行: ```bash # 建立帳戶 sacctmgr add account <account_name> # 將使用者加入帳戶並關聯到 partition sacctmgr add user <username> account=<account_name> partition=c8m64gt1 # 檢查關聯 sacctmgr show assoc where user=<username> ``` 然後使用帳戶提交任務: ```bash srun -A <account_name> -p c8m64gt1 --pty bash ``` #### 方案 2:移除強制驗證(不建議) 如果不需要帳戶管理功能,可以調整設定: ```yaml # 移除 associations 驗證 AccountingStorageEnforce: limits,safe # 或完全移除此行 EnforcePartLimits: ALL ``` ### 輔助參數說明 `EnforcePartLimits: ALL` 本身不是直接原因,但它會: - 強制執行 partition 層級的資源限制 - 配合 `AccountingStorageEnforce` 一起作用 **結論**:核心問題參數是 `AccountingStorageEnforce: associations`,需要建立使用者與 partition 的帳戶關聯才能使用。 - ### 設定2:`AllowAccounts=ALL` ``` $ scontrol show partition PartitionName=c8m64gt1 AllowGroups=ALL AllowAccounts=ALL AllowQos=ALL AllocNodes=ALL Default=NO QoS=N/A DefaultTime=NONE DisableRootJobs=NO ExclusiveUser=NO ExclusiveTopo=NO GraceTime=0 Hidden=NO MaxNodes=UNLIMITED MaxTime=UNLIMITED MinNodes=0 LLN=NO MaxCPUsPerNode=UNLIMITED MaxCPUsPerSocket=UNLIMITED NodeSets=c8m64gt1 Nodes=c8m64gt1-0 PriorityJobFactor=1 PriorityTier=1 RootOnly=NO ReqResv=NO OverSubscribe=NO OverTimeLimit=NONE PreemptMode=OFF State=UP TotalCPUs=88 TotalNodes=1 SelectTypeParameters=NONE JobDefaults=(null) DefMemPerNode=UNLIMITED MaxMemPerNode=UNLIMITED TRES=cpu=8,mem=515856M,node=1,billing=8,gres/gpu=1 ``` 有設定 `AllowAccounts=ALL`,這樣還是會限制有關聯? - ### `us.anthropic.claude-sonnet-4-5-20250929-v1:0` (2026/01/19) 是的,即使設定了 `AllowAccounts=ALL`,當您啟用 `AccountingStorageEnforce: associations` 時,**仍然會要求使用者至少要加入到某個帳戶(account)**。 ### 原因解析 - ### `AllowAccounts=ALL` 的作用 這個參數的意思是: - 允許**所有已建立的帳戶**使用這個 partition - 但**前提是使用者必須屬於某個帳戶** - 它不會自動繞過 `AccountingStorageEnforce: associations` 的檢查 - ### `AccountingStorageEnforce: associations` 的作用 這個參數強制要求: 1. ✅ 使用者必須在 Slurm 資料庫中有帳戶關聯記錄 2. ✅ 使用者必須明確屬於某個 Account 3. ✅ 該 Account 必須有權限使用目標 partition ### 驗證方式 檢查目前的使用者關聯狀態: ```bash # 查看使用者是否有帳戶關聯 sacctmgr show assoc where user=$USER format=user,account,partition # 查看所有帳戶 sacctmgr show account ``` 如果輸出為空或沒有相關記錄,就會出現您遇到的錯誤。 ### 解決方案比較 - ### 選項 1:建立最小帳戶關聯(推薦) 保持安全控制,建立基本的帳戶結構: ```bash # 建立預設帳戶 sacctmgr -i add account default_account Description="Default Account" # 將使用者加入預設帳戶(不限制 partition) sacctmgr -i add user $USER account=default_account # 這樣就可以使用了 srun -p c8m64gt1 --pty bash ``` - ### 選項 2:關閉關聯強制驗證 如果確定不需要帳戶管理功能: ```yaml # 移除 associations,只保留資源限制驗證 AccountingStorageEnforce: limits,safe EnforcePartLimits: ALL ``` - ### 選項 3:完全關閉強制驗證 最寬鬆的設定: ```yaml # 完全移除帳戶驗證(不推薦生產環境) # AccountingStorageEnforce: "" EnforcePartLimits: ALL ``` ### 參數相互關係 ``` AllowAccounts=ALL (partition 層級) ↓ 允許所有已存在的帳戶 ↓ AccountingStorageEnforce: associations (全域層級) ↓ 強制使用者必須有帳戶關聯 ↓ 結果:使用者必須屬於「某個」帳戶,才能使用任何 partition ``` **結論**:`AllowAccounts=ALL` 不會繞過帳戶關聯要求,您需要: 1. 移除 `associations` 驗證(簡單但不安全) 2. 或建立基本的使用者-帳戶關聯(推薦) <br> --- <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> --- ### 參數:`--exclusive` - ### gpt-5.2 (2025/12/17) `--exclusive` 的意思是:**這個 job 拿到的每一個 Slurm node,都要「整台/整個 node 專屬給這個 job 用」**,不允許其他 job 在同一個 node 上再分到任何資源(CPU/記憶體/GPU 等)。 你可以把它想成:**把 node 鎖起來,只給我這個作業用**。 ### 對 user 來說有什麼用? * **避免跟別人的 job 共用同一台 node**(減少互相干擾、效能更穩定) * **需要完整獨占硬體時**(例如怕別人也用同一張 GPU、或你要做效能測試/benchmark) * **確保你的工作不會被「塞在同一台 node 的剩餘空間」**(有些系統允許多個 job 共享同一個 node,只要資源還夠) ### 代價 / 副作用 * **更難排到**:因為你要求「整台」而不是「一部分」,排隊時間可能變長 * **可能浪費資源**:你只用到 node 的一小部分,也會把整台卡住,別人不能用 ### 什麼時候可能「看起來沒差」? * 如果你們的 Slurm node 本來就設定成不共享(例如 partition / node 預設就是 exclusive),那你加不加 `--exclusive` 可能結果一樣。 * 在某些 Slurm-on-K8s 設計裡,一個 Slurm compute “node” 本質上就是一個 worker pod(資源切得很死),共享本來就不常見;但如果一個 Slurm node/pod 仍可能承載多個 job step(或資源有剩可分配),`--exclusive` 仍然有意義。 ### 小例子 * 沒有 `--exclusive`:你拿到 3 個 nodes,但每個 node 可能還會再跑別人的 job(只要資源夠)。 * 有 `--exclusive`:你拿到的 3 個 nodes 會被標記成「被你獨占」,別人不能再分到上面。 如果你願意貼一下 `scontrol show node <其中一個node>` 的輸出(看 `State`、`AllocTRES`、`CfgTRES`、`Partitions`),我也可以告訴你在你們這套環境下 `--exclusive` 是否真的會改變行為、還是其實本來就獨占了。 <br> --- --- <br> ## Squeue Pending 常見的原因 > by gpt-5 (2025/09/15) 下面是把 **`squeue` 顯示為 `PENDING (PD)`** 時最常見的 `REASON` 做成速查表(含意思、常見成因、快速檢查、解法)。 建議常用顯示格式: ```bash # 一眼看到原因、QoS、需求與開始時間 squeue --states=PD -o "%.18i %.9P %.10T %10Q %20R %12S %8M %4C %8m %b %E" # 或看單一工作完整細節 scontrol show job <JOBID> -o ``` --- ### PD 常見 REASON 對照表(含排查建議) | REASON | 代表意思(為什麼在等) | 常見成因 | 快速檢查 | 可能解法 | | ------ | ------------------ | -------- | ------ | -------- | | **Resources**| 等資源釋放(CPU/記憶體/GPU/節點不足) | 叢集被其他工作占滿、你要的 TRES 太大| `sinfo -S+%e`、`sinfo -Nel` 看可用節點/TRES| 降低資源需求(`--cpus-per-task/--mem/--gpus`/`--nodes`)、改較空的 partition、放寬 `--constraint`、分割成多個小 job | | **Priority** | 有更高優先序的工作在前面| Fairshare/age/QoS 造成優先度較低| `sprio -j <JOBID>`、`scontrol show job` 看 `Priority`| 等排程、改用較高 **QoS**(`-q`),或請管理員調整優先序/權重 | | **Dependency** | 設了相依(`--dependency`)尚未滿足| 等前置 job 結果或狀態| `scontrol show job` 看 `Dependency=`| 等完成/移除依賴:`scontrol update JobId=<id> Dependency=`| | **PartitionConfig**| 要求不符合 partition 設定| 要 GPU 但該 partition 無 GPU、超過 partition 限制 | `scontrol show partition <P>` 看 `Allow*`/`DefaultTime/MaxTime/State`/Features| 改到合適 partition(`-p`)、調整需求、移除不相容 `--constraint/--gres`| | **BeginTime**| 設了延後啟動(`--begin=...`) | 手動排程到未來、或系統規則造成| `squeue -j <id> -o "%i %S %R"` | 立刻開始:`scontrol update JobId=<id> BeginTime=now`| | **JobHeldUser**| 你把 job hold 住 | 用了 `--hold` 或 `scontrol hold`| `scontrol show job` 看 `Hold` | 解除:`scontrol release <id>` | | **JobHeldAdmin** | 管理員把 job hold | 管理維護、配額控管| 同上 | 找管理員解除或等待| | **Licenses** | 需要軟體授權數量不足| 併發超過 license 數 | `scontrol show licenses`(若有啟用) | 等待、降低併發、改時段、增購/調整 license| | **ReqNodeNotAvail**| 指定的節點目前不可用| 指名 `--nodelist`/`--constraint` 的節點 **down/drain/reserved** | `sinfo -R`、`sinfo -Nel` 看節點狀態| 移除指定、放寬條件、等節點恢復| | **QOSMaxCpuPerUser** | 你的 **QoS** 對「每使用者 CPU 上限」已滿 | 同一 QoS 下開太多 CPU| `sacctmgr show qos <qos> format=Name,MaxTRESPU,MaxCPUsPU,GrpCPUs`| 降需求、改 QoS(`-q`)、請調高 QoS 限制 | | **QOSMaxJobsPerUser**| QoS 對「每使用者同時工作數」達上限 | 同一 QoS 下開太多 job| `sacctmgr show qos <qos> format=Name,MaxJobsPU`| 減少併發、改 QoS、讓既有 job 跑完| | **QOSGrpCpuLimit** | **QoS 群組級 CPU 上限**已滿| 同組別的人把 CPU 用滿| `sacctmgr show qos <qos> format=Name,GrpCPUs`| 等待、改 QoS、請調高群組上限 | | **QOSGrpNodeLimit**| **QoS 群組級節點數上限**已滿| 同組別併發太多節點| `sacctmgr show qos <qos> format=Name,GrpNodes` | 同上 | | **AssociationJobLimit**| 你的帳號關聯(User/Account/Partition)**job 數上限**到頂 | assoc 上設了 MaxJobs/MaxSubmit| `sacctmgr list assoc where user=<u> format=User,Account,Partition,MaxJobs,MaxSubmit` | 降併發、改帳號/partition、請調整 assoc 限制 | | **AssociationCpuLimit**| 關聯的 **CPU 上限**已滿| 同上 | `sacctmgr list assoc ... format=...,MaxCPUs,MaxTRESPerUser,MaxTRESPerJob`| 同上或降需求 | | **AssociationNodeLimit** | 關聯的 **節點數上限**已滿 | 同上 | 同上 | 同上 | | **AssocGrpJobsLimit**| 關聯群組層級 **job 數上限**已滿| team/project 併發太多| `sacctmgr list assoc ... format=...,GrpJobs` | 等待、請調高、分批提交| > 小提醒:`sacctmgr show`/`list assoc` 通常需要管理權限;若無權限,可改跟管理員確認你所在的 **Account / QoS / Partition** 配額。 --- ### 快速排查流程(實務版) 1. **先看原因** ```bash squeue -j <JOBID> -o "%i %T %Q %R %S %b %E" scontrol show job <JOBID> -o ``` 2. **看 partition 與節點狀態**(是否 down/drain/資源足夠) ```bash sinfo -s sinfo -Nel | grep -E "down|drain|alloc|mix|idle" sinfo -p <PART> -o "%P %a %l %c %m %G %f" ``` 3. **檢查你要的資源是否太大/條件過嚴** * 有沒有過度限定 `--constraint/--nodelist/--gres`? * CPU/MEM/GPU 是否能降低或改多 job 拆分? 4. **若顯示 Priority**: ```bash sprio -j <JOBID> ``` 等公平排程或改 QoS / 請調權重。 5. **若顯示 QoS / Association 限制**: 檢查 QoS 與 assoc 的 Max/Grp 限制(見上表),調整 QoS、降需求、或請管理員調整。 6. **若是 Dependency / BeginTime / Hold**: * `Dependency`:確認前置 job 狀態,或移除相依。 * `BeginTime`:`scontrol update JobId=<id> BeginTime=now`。 * `Hold`:`scontrol release <id>`(Admin hold 需管理員)。 --- ### 提交時預防小技巧 * 提前用 `sinfo` 選對 partition、確認有支援的 GPU/Features。 * 避免過度狹隘的 `--constraint/--nodelist`。 * 合理切分工作:大量 CPU/GPU 需求可拆成多個較小 job。 * 對 license 服務軟體(如商業求解器)避開尖峰時段或排程到夜間(`--begin=22:00`)。 * 用合適的 **QoS**(`-q`)對應你的使用情境與配額。 <br> --- --- <br> ## Slurm srun 如何把環境變數帶到 worker 的 task process > by gpt-5.2 (2025/12/30) ### Slurm `srun` 如何把環境變數帶到 worker 的 task process 在 Slurm 的執行模型裡,「環境變數的傳遞」不是 worker 端去讀 login pod 的環境,而是 **login pod 上的 `srun` 先把這次要傳的環境變數清單整理好**,再把它作為 **step 啟動參數的一部分**,透過 Slurm 的 RPC 送到執行端,最後由 `slurmstepd` 在 `execve()` 啟動 task 時把這份 env 注入到 process。 #### 一個更精準的端到端流程(login pod 執行 `srun`) ```text (login pod) 你的 shell 環境 │ ▼ srun 依 --export 規則,組出「這次 step 要用的環境變數清單」 │ (打包:包含你指定要傳的 key/value) ▼ (slurmctld / controller) 分配節點 + 協調建立 step(RPC 協調與狀態管理) │ ▼ (worker pod) slurmd 收到 launch step/task 的請求 │ ▼ slurmstepd (root) 建立 step、設定 cgroup/limits、準備執行環境 │ ▼ execve() 啟動你的 task process(用你的 UID),並把那份 env 清單帶進去 ``` 這裡的**關鍵角色**就是:**`srun`(client)負責決定「要傳哪些環境變數」**;worker 端只是接收並在啟動 task 時使用。 --- ### `--export` 的本質:決定「打包進 step 的 env 清單」 `--export` 影響的是 `srun`(或 `sbatch`/`salloc`)在提交 step/job 時,**要不要把目前 shell 的哪些環境變數,打包成一份 env list**。 常見直覺落差在於: * 你在 login pod 的 shell 裡 `export FOO=bar` **不等於** worker 端會「自己去讀」到這個變數 * 真正會被帶過去的是:`srun` **當下**依 `--export` 規則整理出的那一份清單 所以環境變數的傳遞是「一次性快照」: * `srun` 打包當下的 env 清單 → 送出 → worker 啟動 task * 之後 login 那邊再改 env,不會回頭影響已啟動的 step/task --- ### `slurmstepd` 與 task process 的環境:目標是 task,不是 stepd 在 worker pod 端,`slurmstepd`(通常是 root)負責把 step 的執行環境準備好,最後 `execve()` 啟動你的 task process(用你的 UID)。要注意兩個常被誤會的點: 1. **`--export` 的目標是「你的 task process」** `slurmstepd` 自己(那個 root 的 daemon)不需要、也不一定會擁有你那份 `--export` 的 env。 2. **worker 端不會回去讀 login pod 的 env** 傳遞完全依賴 `srun` 當下打包的清單;不是動態同步。 --- ### 在 worker 上驗證「task process 實際收到哪些 env」 最直接、最不會被 shell/啟動腳本誤導的方法,是看該 task process 的 `/proc/<pid>/environ`。 常用做法(示意): * 先在 `srun` 內執行一個會停住的程式(例如 `sleep`),拿到 PID * 在 worker 上讀: * `/proc/<pid>/environ`(NUL 分隔) * 或在 task 裡直接 `env | sort` 印出來 這能確認「step 啟動時被注入的 env」到底有哪些,特別適合你在追的那種 **XDG/ENROOT 之類變數干擾**問題。 --- ### 實務上還可能混進 env 的來源(容易讓人以為是「直接繼承」) 即使你把 `--export` 控得很嚴,task 的最終環境仍可能包含其他來源的影響,例如: * Slurm 自動加的 `SLURM_*` 相關變數 * 系統/容器映像內的預設環境(例如 `/etc/profile`, `bash -lc` 行為) * Prolog/Epilog、SPANK plugins(若有啟用) * 站台設定或 wrapper(有時候是你們自訂的 entrypoint/啟動腳本) 所以排查時,建議以「task process 的 `/proc/<pid>/environ`」作為準繩,再回推到底是哪一段把變數放進去:是 `srun --export` 打包的、還是 worker 端啟動鏈(shell/profile/scripts/plugins)額外加的。 <br> --- --- <br> ## sacct > - 用來顯示 job 的執行狀況 > - 只能看到自己帳號內的 job ``` $ sacct JobID JobName Partition Account AllocCPUS State ExitCode ------------ ---------- ---------- ---------- ---------- ---------- -------- 12 nvidia-smi tn 1 RUNNING 0:0 12.extern extern 1 RUNNING 0:0 12.0 nvidia-smi 1 RUNNING 0:0 13 nvidia-smi tn 0 CANCELLED+ 0:0 14 nvidia-smi tn 1 COMPLETED 0:0 14.extern extern 1 COMPLETED 0:0 14.0 nvidia-smi 1 COMPLETED 0:0 ``` **進一步查詢 job 12** ``` $ scontrol show job 12 JobId=12 JobName=nvidia-smi UserId=tj_tsai(10001) GroupId=gid10000(10000) MCS_label=N/A Priority=1 Nice=0 Account=(null) QOS=normal JobState=RUNNING Reason=None Dependency=(null) Requeue=1 Restarts=0 BatchFlag=0 Reboot=0 ExitCode=0:0 RunTime=01:03:07 TimeLimit=UNLIMITED TimeMin=N/A SubmitTime=2025-10-16T08:41:08 EligibleTime=2025-10-16T08:41:08 AccrueTime=Unknown StartTime=2025-10-16T08:41:08 EndTime=Unknown Deadline=N/A SuspendTime=None SecsPreSuspend=0 LastSchedEval=2025-10-16T08:41:08 Scheduler=Main Partition=tn AllocNode:Sid=slurm-login-slinky-765f696cc5-5vkfs:1362 ReqNodeList=esc8000a-0 ExcNodeList=(null) NodeList=esc8000a-0 BatchHost=esc8000a-0 StepMgrEnabled=Yes NumNodes=1 NumCPUs=1 NumTasks=1 CPUs/Task=1 ReqB:S:C:T=0:0:*:* ReqTRES=cpu=1,mem=4G,node=1,billing=1,gres/gpu=1 AllocTRES=cpu=1,mem=4G,node=1,billing=1,gres/gpu=1 Socks/Node=* NtasksPerN:B:S:C=0:0:*:* CoreSpec=* MinCPUsNode=1 MinMemoryCPU=4G MinTmpDiskNode=0 Features=(null) DelayBoot=00:00:00 OverSubscribe=OK Contiguous=0 Licenses=(null) LicensesAlloc=(null) Network=(null) Command=nvidia-smi WorkDir=/mnt/data/sqsh TresPerNode=gres/gpu:1 ``` - 可以查其他不屬於自己的 job <br> --- --- <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 %}