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 %}