Singularity & Slurm
===
###### tags: `TWCC`
###### tags: `TWCC`, `HPC`, `Singularity`, `Slurm`, `SIF`, `OTP`, `IDExpert`, `sinfo`, `sinfo`, `sacct`, `srun`, `sbatch`
<br>
[TOC]
<br>
## 登入
### 如何登入
> 主機密碼加上OTP動態碼
```
$ ssh 主機帳號@ln01.twcc.ai
#####################################################
# #
# ~~ WELCOME TO TAIWANIA 2 ~~ #
# #
# How to log in? #
# https://docs.twcc.ai/docs/login-logout/ #
# #
#####################################################
Please select the 2FA login method.
1. Mobile APP OTP
2. Mobile APP PUSH
3. Email OTP
Login method: 1
Password: <--- 主機帳號所對應的密碼
OTP: 750880 <--- OTP 密碼
[PASS] The OTP verification succeeded.
```
- 如何登入
https://docs.twcc.ai/docs/login-logout/
- 建立 OTP 載具
https://docs.twcc.ai/docs/system-account-password-otp#判斷是否已建立-otp-載具
- 手機下載 「`IDExpert` 」APP
- Google Play連結:
https://play.google.com/store/apps/details?id=com.changingtec.idexpert
- Apple App Store 連結:
https://apps.apple.com/tw/app/idexpert/id1447069966
<br>
### 登入後的提示
```
Dear User,
To run your jobs, use Slurm commands:
step 1: Prepare your job script first and specify Queue and ProjectID in it.
$ vim job.sh
step 2: Submit your job script to Slurm and then you'll get the job id.
$ sbatch job.sh
step 3: Trace job id and monitor your job.
$ squeue -u ${USER}
$ sacct -j $job_id
Other handy Slurm commands:
Display the information about Slurm nodes and partitions.
$ sinfo
Terminate your job.
$ scancel job_id
Other useful query commands:
$ wallet (check your project id and wallet balance)
$ wallet $PROJECT_ID (specify a project)
$ cd /home/${USER} (change directory to your home folder)
$ cd /work/${USER} (change directory to your work folder)
=================================================
Note:
Do NOT use the login nodes for computation.
No Bitcoin Mining!
Please follow the rules !
Otherwise, We will block your account :)
=================================================
```
<br>
<hr>
<br>
## 下載 ubuntu image,並透過 slurm 執行調度
### 下載 image: `ubuntu:20.04`
```bash=
# 下載公開的 docker image
$ singularity pull docker://ubuntu:20.04
# or
$ singularity pull ubuntu:20.04
# 查看 sif 檔
$ ls ubuntu_20.04.sif
```
<br>
### 執行 sif 檔
```bash=
$ singularity exec ubuntu_20.04.sif bash
Singularity> cat /etc/os-release
NAME="Ubuntu"
VERSION="20.04.4 LTS (Focal Fossa)"
ID=ubuntu
ID_LIKE=debian
PRETTY_NAME="Ubuntu 20.04.4 LTS"
VERSION_ID="20.04"
HOME_URL="https://www.ubuntu.com/"
SUPPORT_URL="https://help.ubuntu.com/"
BUG_REPORT_URL="https://bugs.launchpad.net/ubuntu/"
PRIVACY_POLICY_URL="https://www.ubuntu.com/legal/terms-and-policies/privacy-policy"
VERSION_CODENAME=focal
UBUNTU_CODENAME=focal
```
<br>
### 透過 slurm 執行調度
- ### 準備 query_os_info.sh
```bash
#!/bin/bash
echo '>>>>>'
singularity exec ubuntu_20.04.sif cat /etc/os-release
echo '<<<<<'
```
- 沒有 `#!/bin/bash` 資訊,執行時會有錯誤訊息:
```
$ sbatch --account=ENT110209 query_os_info.sh
sbatch: error: This does not look like a batch script. The first
sbatch: error: line must start with #! followed by the path to an interpreter.
sbatch: error: For instance: #!/bin/sh
```
- ### slurm 透過 `slurm` 執行調度
```
$ sbatch --gpus-per-node=1 --account=ENT21**** query_os_info.sh
sbatch: INFO: It is recommended to specify `--nodes` and `--ntasks-per-node` together
Submitted batch job 628675
```
- job ID 為 **628675**
- 後面可查看 job 的狀態
- 沒有 `--gpus-per-node=<num>` 參數,執行時會有錯誤訊息:
```
sbatch: error: Missing assigned gpus, try to use --gpus-per-node=<num>
sbatch: error: Batch job submission failed: Unspecified error
```
- `<num>` 只能填 1~8
```
sbatch: error: --gpus-per-node=<num> only accept 1,2,3,4,5,6,7,8
sbatch: error: Batch job submission failed: Unspecified error
```
- 專案不存在時,執行時會有錯誤訊息:
```
sbatch: error: Looks like ENT110209 is a non-existent project id o.O
sbatch: error: Or you don't belong to this project
sbatch: error: Please check the wallet information below :)
sbatch: error: ----------------------------------- wallet info -----------------------------------
sbatch: error: PROJECT_ID: ENT21****, PROJECT_NAME: T01-*******, SU_BALANCE: *****
sbatch: error: PROJECT_ID: ENT21****, PROJECT_NAME: T01-*******, SU_BALANCE: *****
sbatch: error: PROJECT_ID: GOV11****, PROJECT_NAME: OneAI******, SU_BALANCE: *****
sbatch: error: -----------------------------------------------------------------------------------
sbatch: error: Batch job submission failed: Unspecified error
```
- ### slurm 產出
```
$ ll
-rw-r--r-- 1 <主機帳號> ENT21**** 120 Jul 17 16:02 query_os_info.sh
-rw-r--r-- 1 <主機帳號> ENT21**** 382 Jul 17 16:03 query_os_info.sh.log
-rw-r--r-- 1 <主機帳號> ENT21**** 394 Jul 17 16:03 slurm-628678.out
```
- 輸出結果為 `slurm-628678.out`
```bash=
$ cat slurm-628678.out
>>>>>
NAME="Ubuntu"
VERSION="20.04.4 LTS (Focal Fossa)"
ID=ubuntu
ID_LIKE=debian
PRETTY_NAME="Ubuntu 20.04.4 LTS"
VERSION_ID="20.04"
HOME_URL="https://www.ubuntu.com/"
SUPPORT_URL="https://help.ubuntu.com/"
BUG_REPORT_URL="https://bugs.launchpad.net/ubuntu/"
PRIVACY_POLICY_URL="https://www.ubuntu.com/legal/terms-and-policies/privacy-policy"
VERSION_CODENAME=focal
UBUNTU_CODENAME=focal
<<<<<
```
- query_os_info.sh.log
> 將 terminal 輸出的 log,導向到指定檔案
<br>
### 確認 slurm 任務狀態
> [[TWCC] 確認任務狀態](https://man.twcc.ai/@twccdocs/doc-twnia2-main-zh/https%3A%2F%2Fman.twcc.ai%2F%40twccdocs%2Fguide-twnia2-job-state-zh)
- ### sacct
> displays accounting data for all jobs and job steps in the Slurm job accounting log or Slurm database
>
```
$ sacct
JobID JobName Partition Account AllocCPUS State ExitCode
------------ ---------- ---------- ---------- ---------- ---------- --------
628675 query_os_+ gp2d ent21**** 1 RUNNING 0:0
628675.exte+ extern ent21**** 1 RUNNING 0:0
```
- 狀態有:COMPLETE、PENDING 或是 FAILED
- 若ExitCode的開頭不為「0」,則表示此任務是錯誤狀態。
- 生命週期

<br>
<hr>
<br>
## 下載私有 docker image,並透過 slurm 執行調度
### 1. 建立 dockerhub 的 token
1. **點選帳號圖示,再點選 Account settings**

---
2. **點選 Security**

---
3. **點選 New Access Token**

<br>
### 2. 下載私有 docker image
```bash
export SINGULARITY_DOCKER_USERNAME=mycloud
export SINGULARITY_DOCKER_PASSWORD=dckr_pat_abcdefghijklmnopqrstuvwxyz0123456789
singularity pull mycloud/llm-benchmark:v0.1
```
- 查看當前目錄,會有 `llm-benchmark_v0.1.sif`
```
$ ls -ls
48656 -rwxr-xr-x 1 主機帳號 ENT21**** 49811456 Jul 17 16:46 llm-benchmark_v0.1.sif
```
<br>
### 3. 透過 singularity 容器,來執行 `llm-benchmark_v0.1.sif`
```
$ singularity exec \
--env API_KEY=********-****-****-****-************ \
--env MODEL=llama3-70b-0520 \
--env OUTPUT_DIR=`pwd`/llama3-70b-0520-output \
llm-benchmark_v0.1.sif \
bash -c "cd /workspace/src && python main.py"
```
<br>
### 4. 透過 slurm 調度,來執行 `llm-benchmark_v0.1.sif`
- 建立 `run_benchmark.sh`
```bash
#!/bin/sh
# Set environment variables via `SINGULARITYENV_<key>=<value>`
export SINGULARITYENV_API_KEY=********-****-****-****-************
# 執行 llm-benchmark_v0.1.sif
# - Set environment variables via `--env`
singularity exec \
--env MODEL=llama3-70b-0520 \
--env OUTPUT_DIR=`pwd`/llama3-70b-0520-output \
llm-benchmark_v0.1.sif \
bash -c "cd /workspace/src && python main.py"
```
- 透過 slurm 執行調度
```
$ sbatch --gpus-per-node=1 --account=ENT21**** run_benchmark.sh
sbatch: INFO: It is recommended to specify `--nodes` and `--ntasks-per-node` together
Submitted batch job 628720
```
- 查看 slurm 調度狀態
- `$ sacct` (查看執行 slurm 調度的歷史紀錄)
- `$ sacct -j 628720` (查看某個 job 的調度狀態)
```
$ sacct -j 628720
JobID JobName Partition Account AllocCPUS State ExitCode
------------ ---------- ---------- ---------- ---------- ---------- --------
628720 run_bench+ gp2d ent21**** 1 RUNNING 0:0
628720.exte+ extern ent21**** 1 RUNNING 0:0
```
- `$ scontrol show job` (查看執行 job 的參數)
```
$ scontrol show job 628720
JobId=628720 JobName=run_benchmark.sh
UserId=<主機帳號>(15444) GroupId=ENT21****(200231) MCS_label=N/A
Priority=10004785 Nice=0 Account=ent21**** QOS=normal
JobState=RUNNING Reason=None Dependency=(null)
Requeue=1 Restarts=0 BatchFlag=1 Reboot=0 ExitCode=0:0
RunTime=00:03:44 TimeLimit=2-00:00:00 TimeMin=N/A
SubmitTime=2024-07-17T17:15:46 EligibleTime=2024-07-17T17:15:46
AccrueTime=2024-07-17T17:15:46
StartTime=2024-07-17T17:15:47 EndTime=2024-07-19T17:15:47 Deadline=N/A
PreemptTime=None SuspendTime=None SecsPreSuspend=0
LastSchedEval=2024-07-17T17:15:47
Partition=gp2d AllocNode:Sid=ln01-twnia2:97861
ReqNodeList=(null) ExcNodeList=(null)
NodeList=gn1214
BatchHost=gn1214
NumNodes=1 NumCPUs=1 NumTasks=1 CPUs/Task=1 ReqB:S:C:T=0:0:*:*
TRES=cpu=1,mem=90G,node=1,billing=1,gres/gpu=1
Socks/Node=* NtasksPerN:B:S:C=1:0:*:* CoreSpec=*
MinCPUsNode=1 MinMemoryNode=90G MinTmpDiskNode=0
Features=(null) DelayBoot=00:00:00
OverSubscribe=OK Contiguous=0 Licenses=(null) Network=(null)
Command=/home/<主機帳號>/run_benchmark.sh
WorkDir=/home/<主機帳號>
StdErr=/home/<主機帳號>/slurm-628720.out
StdIn=/dev/null
StdOut=/home/<主機帳號>/slurm-628720.out
Power=
TresPerNode=gpu:1
```
- `$ squeue` (查看 queue 的狀態)
```
$ squeue
JOBID PARTITION NAME USER ST TIME NODES NODELIST(REASON)
...
628720 gp2d run_benc <主機帳號> R 6:18 1 gn1214
...
```
- `$ scancel 628720` (取消 job 的執行)
`$ scancel <job_id>`
<br>
## 客製化 image 建立
> https://hackmd.io/@praexisio/BJdzfcEGY/%2F%40praexisio%2Fbuild
### 待驗證
```
$ singularity build new_image.sif my_container
```
<br>
### 將 sandbox 轉換為 SIF
1. 建立可寫的 sandbox 容器
使用 `--sandbox` 參數建立一個可修改的容器。例如:
```bash
singularity build --sandbox my_sandbox docker://ubuntu
```
2. 在 sandbox 容器中進行修改
啟動容器後,你可以進行安裝或其他修改:
```bash
singularity shell --writable my_sandbox
```
修改完成後退出容器。
3. 將 sandbox 轉換為 SIF 文件
最後,用 `singularity build` 指令將修改後的 sandbox 轉換為新的 SIF 鏡像:
```bash
singularity build new_image.sif my_sandbox
```
這樣你就能從一個容器中存出一個新的 SIF 文件了。
<br>
### Docker image 直接生成 SIF
> 待驗證
```
$ singularity build new_image.sif docker://ubuntu
```
這樣 Singulariy 會直接從指定來源(此例為 Docker Hub 上的 Ubuntu 映像)建構並輸出新的 SIF 文件,而無需先建立 sandbox。
<br>
<hr>
<br>
## 討論
### singularity 如何導入環境變數
- ### Question
`singularity exec llm-benchmark_v0.1.sif bash`
執行 singularity 要如何把環境變數帶入?
- ### ChatGPT-4o
在使用 Singularity 容器時,可以使用 `--env` 或 `-e` 選項將環境變數傳入容器內。這裡有幾種方法來傳遞環境變數:
### 1. 使用 `--env` 選項
你可以直接在命令行中使用 `--env` 選項來傳遞環境變數,例如:
```bash
singularity exec --env MY_VAR=value llm-benchmark_v0.1.sif bash
```
### 2. 使用 `SINGULARITYENV_` 前綴
另一種方法是使用 `SINGULARITYENV_` 前綴來設定環境變數。這些變數將在容器內被識別並應用。例如:
```bash
export SINGULARITYENV_MY_VAR=value
singularity exec llm-benchmark_v0.1.sif bash
```
### 3. 使用環境變數檔案
如果有多個環境變數要傳遞,可以將它們放在一個檔案中,然後在執行容器時載入這個檔案。例如,你可以創建一個 `.env` 檔案,內容如下:
```bash
MY_VAR1=value1
MY_VAR2=value2
```
然後在執行容器時使用 `source` 命令載入這個檔案:
```bash
source .env
singularity exec llm-benchmark_v0.1.sif bash
```
以上這些方法都可以幫助你在使用 Singularity 容器時傳遞環境變數。根據你的具體需求選擇最適合的方法即可。
<br>
### 執行 singularity 容器時,如何切換到指定目錄,再執行 python ?
- ### Question
`singularity exec llm-benchmark_v0.1.sif cd /workspace/src && python main`
我要如何切換到指定目錄,再執行 python ?
- ### ChatGPT-4o
在 Singularity 容器中,你可以使用 `exec` 命令並指定多個指令,以便先切換到指定目錄,再執行 Python 腳本。你可以使用 `&&` 來串接多個命令。以下是具體的命令範例:
```bash
singularity exec llm-benchmark_v0.1.sif bash -c "cd /workspace/src && python main"
```
這裡的 `bash -c` 允許你傳遞一個包含多個指令的命令字串。整個指令會在 Singularity 容器內執行。
<br>
### 如何查看 Slurm 的 log
- ### Question
`sbatch --gpus-per-node=1 --account=ENT210000 run_benchmark.sh`
假設 job_id 為 628746
我要如何查看 job_id=628746 的 log?
- ### ChatGPT-4o
要查看特定作業的日誌(假設作業 ID 為 628746),你可以使用以下命令:
```bash
sacct -j 628746 --format=JobID,State,Elapsed,ExitCode
```
這將顯示作業的狀態和基本信息。要查看作業的輸出和錯誤日誌,通常可以找到作業提交時指定的輸出和錯誤文件,這些文件通常會在提交腳本中指定,例如:
```bash
#SBATCH --output=output_%j.log
#SBATCH --error=error_%j.log
```
`%j` 會被替換為作業 ID,所以在這種情況下,你可以查看 `output_628746.log` 和 `error_628746.log` 這些文件。
你可以使用以下命令來檢查這些日誌文件:
```bash
cat output_628746.log
cat error_628746.log
```
如果你沒有指定輸出和錯誤日誌文件,默認情況下,它們通常會在你提交作業的目錄中,文件名為 `slurm-<job_id>.out`。所以你可以用以下命令來查看日誌:
```bash
cat slurm-628746.out
```
如果日誌文件很大,你也可以使用 `less` 或 `tail` 來查看部分內容,例如:
```bash
less slurm-628746.out
tail -n 50 slurm-628746.out
```
這些命令可以幫助你方便地檢查和分析作業的日誌文件。
<br>
## 如何掛載 HPC storage 進來
### 安裝 sshfs
```
sudo apt-get update -y
sudo apt-get install sshfs
```
### 執行掛載 HPC storage
- `/mnt/mywork/myfolder` <--> HPC: `主機帳號@ln01.twcc.ai/home/主機帳號`
```
$> mkdir /mnt/mywork/myfolder
$> sshfs 主機帳號@xdata1.twcc.ai:/home/主機帳號 myfolder # 掛載自己的 home 到當前環境
```
### 卸載 HPC storage
- `$ unmount /mnt/mywork/myfolder`
<br>
## 參考資料
- [[TWCC] 如何登入](https://docs.twcc.ai/docs/login-logout/)
- [[TWCC] 確認任務狀態](https://man.twcc.ai/@twccdocs/doc-twnia2-main-zh/https%3A%2F%2Fman.twcc.ai%2F%40twccdocs%2Fguide-twnia2-job-state-zh)
- [HPC 高速運算任務](https://man.twcc.ai/@twccdocs/doc-hpc-job-main-zh#Slurm-%E5%9F%BA%E6%9C%AC%E6%8C%87%E4%BB%A4%E7%B0%A1%E4%BB%8B)
- 若需使用 **8 顆以上 GPU** 或執行跨節點高速運算,請使用台灣杉二號(命令列介面),並參考以下教學案例:
- [HowTo:建立 TWNIA2 容器](https://www.twcc.ai/doc?page=howto-twnia2-create-sglrt-container)
- [HowTo:容器跨節點高速運算-AI Benchmark](https://www.twcc.ai/doc?page=howto-twnia2-run-parallel-job-container)
- [Conda 更新規劃 & 操作範例](https://hackmd.io/@kmo/twcc_hpc_conda)
- [[docs] singularity exec](https://docs.sylabs.io/guides/3.3/user-guide/cli/singularity_exec.html)
<br>
<hr>
<br>
## 討論
### 可以不要掛載 `/home/<USER>` 目錄?
- Question
在 HPC 中使用 Singularity,似乎會自動掛載 /home 目錄,有辦法不要掛載嗎?
- gpt-4o-2024-08-06
在 HPC 中使用 Singularity 時,預設會自動掛載使用者的 `/home` 目錄,以便讓使用者可以在容器內存取自己的主目錄。如果你希望在啟動容器時不要掛載 `/home` 目錄,可以使用 Singularity 的 `--no-home` 或 `--contain` 選項來避免掛載主機的 `/home` 目錄。
### 解決方法:
1. **使用 `--no-home` 選項**:
使用此選項來避免將主機的 `/home` 目錄掛載到容器中。
```
singularity exec --no-home your_image.sif python your_script.py
```
此選項會禁用將主機 `/home` 目錄掛載到容器的行為,並使用容器內的 `/home` 路徑(如果有的話)。
2. **使用 `--contain` 選項**:
如果你想要更隔離的環境,除了不掛載 `/home` 目錄以外,`--contain` 還會將 `/tmp`、`/var/tmp` 等其他目錄也隔離,並且只允許預設的 `/dev` 設置。
```
singularity exec --contain your_image.sif python your_script.py
```
使用此選項會創建一個更乾淨的容器環境,避免主機上的大部分目錄被自動掛載進去。
3. **使用 `--bind` 自定義掛載點**:
如果你希望掛載其他自定義目錄,而不掛載 `/home`,你可以使用 `--bind` 選項來指定掛載點。例如:
```
singularity exec --no-home --bind /my/custom/dir:/mnt your_image.sif python your_script.py
```
這樣可以確保 `/home` 沒有被掛載,同時你可以掛載其他自定義目錄進容器。
### 小結:
- 使用 `--no-home` 可以避免掛載 `/home` 目錄。
- 使用 `--contain` 可以創建更隔離的環境,不僅不掛載 `/home`,還隔離其他目錄。
- 使用 `--bind` 可以指定掛載自定義的目錄,同時避免 `/home` 被掛載。
- ### 參考資料
- [singularity run options](https://docs.sylabs.io/guides/3.4/user-guide/cli/singularity_run.html#options)