[Enroot] Pyxis Guide
===
###### tags: `SlinkyProject / SPANK`
###### tags: `Kubernetes`, `k8s`, `app`, `slurm`, `SlinkyProject`, `SPANK`, `Slurm Plug-in`, `Pyxis`, `Enroot`
<br>
[TOC]
<br>
:::danger
:warning: 注意事項
- 不能有 `oci.conf`
- 未找到。
- 如果有,會跟 SPANK 的外掛功能產生衝突
-
:::
<br>
## Guide
### [[github][SlinkyProject] slurm-operator / docs / pyxis.md / Pyxis Guide](https://github.com/SlinkyProject/slurm-operator/blob/main/docs/usage/pyxis.md)
- ### Test
- 向 Slurm 節點提交作業。
```bash
$ srun --partition=debug grep PRETTY /etc/os-release
PRETTY_NAME="Ubuntu 24.04.2 LTS"
```
- 使用 pyxis 向 Slurm 節點提交作業,它將在其請求的容器中啟動。
```bash
$ srun --partition=debug --container-image=alpine:latest grep PRETTY /etc/os-release
pyxis: importing docker image: alpine:latest
pyxis: imported docker image: alpine:latest
PRETTY_NAME="Alpine Linux v3.21"
```
> 警告:SPANK 插件僅適用於已配置並已安裝這些插件的特定 Slurm 節點。最好使用`--partition=<partition>`、`--batch=<features>`和/或 限製作業的運作位置`--constraint=<features>`,以確保運算環境相容。
- 如果登入容器已啟用securityContext.privileged=true,則允許進行 enroot 活動。您可以使用以下命令測試該功能:
```bash
enroot import docker://alpine:latest
```
<br>
## Slurm
### SPANK
> https://hackmd.io/8KKO-q5AQH-rGa5itaw25w
- Slurm Plug-in Architecture for Node and job (K)control
(Slurm 節點與工作控制的外掛架構)
- **簡介**
SPANK 是 Slurm 的外掛架構,讓管理員可動態擴充與修改工作啟動行為。它支援多種執行環境(context)和多種插件回調函式,並提供擴充命令列選項的能力,方便自訂 Slurm 工作流程。
<br>
### Containers Guide
> https://slurm.schedmd.com/containers.html
- ### [Container support via Plugin](https://slurm.schedmd.com/containers.html#plugin)
> Slurm 允許容器開發者建立 SPANK 外掛,這些外掛可以在工作執行的不同階段被呼叫,以支援容器功能。任何使用這類外掛來啟動容器的系統,都**不應該有** `oci.conf` 配置檔。`oci.conf` 檔案會啟用 Slurm 內建的容器功能,可能會與基於 SPANK 的外掛功能產生衝突。
>
> 以下是設計用於 Slurm 的第三方容器解決方案,但這些方案尚未經 SchedMD 官方測試或驗證:
>
- ### Shifter
Shifter 是來自 NERSC 的容器專案,目標是提供具完整排程器整合的 HPC 容器環境。
- Shifter 提供完整的 Slurm 整合說明。
- 相關簡報包括:
- *Never Port Your Code Again* — 使用 Shifter 和 SLURM 提供 Docker 功能
- *Shifter: Containers in HPC Environments*
- ### ENROOT 與 Pyxis
> https://slurm.schedmd.com/containers.html#enroot1
>
Enroot 是 NVIDIA 贊助的使用者命名空間容器系統,支援:
- 透過 Pyxis 與 Slurm 整合
- 原生支援 Nvidia GPU
-更快的 Docker 映像匯入
- ### Sarus
Sarus 是由 ETH Zurich CSCS 贊助的特權容器系統,支援:
- 透過 OCI hook 與 Slurm 進行映像同步
- 原生支援 OCI 映像格式
- NVIDIA GPU 支援
- 與 Shifter 類似的設計
- ### :warning: 怎麼判斷 當前容器 有沒有 oci.conf 配置檔?
> by gpt-4o-mini, 2025/06/26
判斷當前系統或容器環境中是否有 `oci.conf` 配置檔,可以用以下方法:
---
### 1. 在容器主機(通常是計算節點或管理節點)上檢查
```bash
ls /etc/slurm/oci.conf
```
或
```bash
find /etc/slurm/ -name "oci.conf"
```
如果能找到該檔案,代表系統中有 `oci.conf` 配置。
---
### 2. 檢查 Slurm 配置是否引用該檔案
```bash
grep -r oci.conf /etc/slurm/
```
查看是否有配置文件或啟動腳本中明確指定使用 `oci.conf`。
---
### 3. 檢查環境變數或 Slurm 服務啟動參數
有時 `oci.conf` 的使用會透過啟動腳本或環境變數啟用,可以檢查 `slurmd` 或相關服務的啟動參數:
```bash
ps aux | grep slurmd
```
查找是否有與 `oci.conf` 相關的選項。
---
### 4. 在容器內判斷通常沒有這個檔案
`oci.conf` 是 Slurm 守護進程或管理節點的配置檔,**通常不會放在容器內部**,而是宿主機上的配置。
---
### 總結
* 直接在宿主機或 Slurm 節點 `/etc/slurm/` 目錄下尋找 `oci.conf` 即可判斷。
* 若找不到該檔案,或沒有相關配置啟用,就代表該系統未啟用 Slurm 內建 OCI 容器功能。
---
### 使用腳本自動檢查 (`check_oci_conf.sh`)
```bash=
#!/bin/bash
# check_oci_conf.sh
CONFIG_DIR="/etc/slurm"
CONFIG_FILE="oci.conf"
echo "檢查是否存在 ${CONFIG_DIR}/${CONFIG_FILE}..."
if [ -f "${CONFIG_DIR}/${CONFIG_FILE}" ]; then
echo "找到配置檔:${CONFIG_DIR}/${CONFIG_FILE}"
else
echo "未找到 ${CONFIG_FILE} 配置檔。"
fi
echo
echo "檢查 ${CONFIG_DIR} 目錄下是否有檔案內容包含 'oci.conf'..."
grep -r --color=auto "oci.conf" "${CONFIG_DIR}" 2>/dev/null
if [ $? -ne 0 ]; then
echo "未在配置檔中找到包含 'oci.conf' 的字串。"
fi
```
<br>
## NVIDIA
### pyxis
> https://github.com/NVIDIA/pyxis?tab=readme-ov-file#pyxis
- ### Summary
Pyxis 是 Slurm 的 SPANK 外掛,讓無特權使用者能用 srun 執行容器化工作,方便在叢集環境中運行容器任務。
- ### Description
Pyxis 是 Slurm 工作負載管理器(Slurm Workload Manager)的一個 SPANK 外掛。它允許無特權的叢集使用者透過 `srun` 指令執行容器化任務。
「Pyxis」一詞源自古代,意指一個小盒子或容器。
<br>
### enroot
> https://github.com/NVIDIA/enroot
- ### Summary
Enroot 是輕量無特權沙盒工具,類似加強版 chroot,保留檔案系統隔離,適合高效能且重視可攜性的環境,支援 Docker 映像。
- ### Description
一個簡單卻強大的工具,能將傳統的容器或作業系統映像檔轉換成 **無特權(unprivileged)** 的沙盒環境。
Enroot 可被視為一種增強版的無特權 `chroot(1)`。它採用與容器相同的底層技術,但移除了容器固有的大部分隔離功能,卻仍保有檔案系統的分離。
這種方式通常較適合用於對效能要求高或虛擬化環境中,重視可攜性與可重現性,但不需要額外隔離的情境。
Enroot 也類似於其他工具如 `proot(1)` 或 `fakeroot(1)`,但它利用了 Linux 核心較新的功能(例如使用者與掛載命名空間),並提供匯入常見容器映像格式(例如 Docker 映像檔)的功能。
- ### Usage example:
```
# Import and start an Ubuntu image from DockerHub
$ enroot import docker://ubuntu
$ enroot create ubuntu.sqsh
$ enroot start ubuntu
```
- ### Runtime configuration
> https://github.com/NVIDIA/enroot/blob/master/doc/configuration.md
>
| Setting | Default | Description |
| ------ | ------ | ------ |
| `ENROOT_LIBRARY_PATH` | `/usr/lib/enroot` | Path to library sources |
| `ENROOT_SYSCONF_PATH` | `/etc/enroot` | Path to system configuration files |
| `ENROOT_RUNTIME_PATH` | `${XDG_RUNTIME_DIR}/enroot` | Path to the runtime working directory |
| `ENROOT_CONFIG_PATH` | `${XDG_CONFIG_HOME}/enroot` | Path to user configuration files |
| `ENROOT_CACHE_PATH` | `${XDG_CACHE_HOME}/enroot` | Path to user image/credentials cache |
| `ENROOT_DATA_PATH` | `${XDG_DATA_HOME}/enroot` | Path to user container storage |
| `ENROOT_TEMP_PATH` | `${TMPDIR}` | Path to temporary directory |
- ### Requirements
> https://github.com/NVIDIA/enroot/blob/master/doc/requirements.md
- 檢查 enroot 所需的前置條件
透過執行指定版本的 enroot-check bundle,自動檢查所需的條件是否符合。
```
$ curl -fSsL -O https://github.com/NVIDIA/enroot/releases/download/v3.5.0/enroot-check_3.5.0_$(uname -m).run
$ chmod +x enroot-check_*.run
$ ./enroot-check_*.run --verify
$ ./enroot-check_*.run
Bundle ran successfully!
```
- 支援 Enroot 所需的功能(例如 cgroup 支援、BPF、namespace 等)
<br>
## Kubernetes (K8s)
- ### ontainer-level Security Context
> https://kubernetes.feisky.xyz/concepts/objects/security-context#container-level-security-context
```yaml=
apiVersion: v1
kind: Pod
metadata:
name: hello-world
spec:
containers:
- name: hello-world-container
# The container definition
# ...
securityContext:
privileged: true
```
<br>
## Linux
### squashfs
> https://www.kernel.org/doc/Documentation/filesystems/squashfs.txt
### BPF
- [初探 Linux Kernel 中的 BPF 與 XDP 技術:以 Tiny Load Balancer 為例](https://medium.com/starbugs/9428c7c1001b)
- **BPF 的核心概念**
讓 User Space 的應用程式可以透過額外的過濾程式來告訴作業系統它希望收到哪些網路封包,這麼做的好處顯而易見:系統可以在封包一進入到 Kernel Space 時就過濾掉沒有作用的封包,避免這些封包一路經過作業系統的 Networking Stack(網路堆疊)一路傳到 User Space 上面的應用程式。

<br>
## 其他參考
### [Using enroot and pyxis in Bright Cluster Manager](https://kb.brightcomputing.com/knowledge-base/using-enroot-and-pyxis-in-bright-cluster-manager/)
- ### 原理 (by gpt-4.1-mini, 2025/06/26)
在 Bright Cluster Manager 中使用 Enroot 和 Pyxis 執行 Docker 映像時,**無需額外設定特權**,即可讓無特權使用者運行容器化任務。這是因為 Enroot 和 Pyxis 利用 Linux 的命名空間(namespace)技術,提供無需 root 權限的容器執行環境。([kb.brightcomputing.com][1])
然而,為確保無特權使用者能順利執行,必須在叢集的主節點和計算節點上進行以下設定:
1. **啟用使用者命名空間**:在 GRUB 配置中加入 `namespace.unpriv_enable=1` 和 `user_namespace.enable=1`,並更新系統參數 `user.max_mnt_namespaces` 和 `user.max_user_namespaces`,以允許使用者創建命名空間。([kb.brightcomputing.com][1])
2. **安裝 Enroot 和 Pyxis**:下載並安裝 Enroot 和 Pyxis,並在 Slurm 的配置中載入 Pyxis 模組。
3. **配置 Slurm 插件**:在 Slurm 的 `plugstack.conf` 中加入 Pyxis 插件,設置適當的運行時路徑和選項。
完成上述設定後,無特權使用者即可透過 `srun` 指令執行容器化任務,而無需額外的特權設定。
如需詳細步驟,請參考 Bright Computing 的官方文件:[Using enroot and pyxis in Bright Cluster Manager](https://kb.brightcomputing.com/knowledge-base/using-enroot-and-pyxis-in-bright-cluster-manager/)。
[1]: https://kb.brightcomputing.com/knowledge-base/using-enroot-and-pyxis-in-bright-cluster-manager/?utm_source=chatgpt.com "Using enroot and pyxis in Bright Cluster Manager"
- ### Configure user namespaces.
- ### 作業系統應該支援使用者擁有的命名空間(user-owned namespaces):
- 需要設定
- `namespace.unpriv_enable=1`
- `user_namespace.enable=1`
- 在 `/etc/default/grub` 檔案中,修改對照:
- **原本範例(假設)**:
```bash
GRUB_CMDLINE_LINUX="quiet splash"
```
- **執行完後變成**:
```bash
GRUB_CMDLINE_LINUX="quiet splash namespace.unpriv_enable=1 user_namespace.enable=1"
```
- ### 此外,還有兩個 sysctl 選項:
- 需要設定
- `user.max_mnt_namespaces`
- `user.max_user_namespaces`
用來描述可供使用者使用的命名空間數量限制。
- `/etc/sysctl.d/10-enroot.conf`
```
user.max_mnt_namespaces = 32
user.max_user_namespaces = 32
```
- ### Check that enroot is working
```
enroot import docker://gcr.io#google-containers/debian-base:v2.0.0
enroot create google-containers+debian-base+v2.0.0.sqsh
enroot start google-containers+debian-base+v2.0.0 cat /etc/os-release
```
- ### GRUB_CMDLINE_LINUX
> by gpt-4.1-mini, 2025/06/26
`GRUB_CMDLINE_LINUX` 是用來設定 Linux 核心(Kernel)在開機時所接收的「開機選項(kernel boot parameters)」。
### 詳細說明:
* `GRUB_CMDLINE_LINUX` 通常定義在 `/etc/default/grub` 裡。
* 它裡面的參數會被 GRUB 引導程式讀取,並傳遞給 Linux 核心啟動時使用。
* 這些參數可以用來控制核心的行為,例如啟用某些功能、關閉硬體、調整資源限制等。
* 修改此參數後,通常需要執行 `update-grub` 或等同指令來更新 GRUB 設定,並重新開機才會生效。
### 舉例:
```bash
GRUB_CMDLINE_LINUX="quiet splash"
```
* `quiet`:減少開機訊息輸出。
* `splash`:顯示啟動畫面。
### 效果:
若您想讓核心啟用使用者命名空間,可以在這裡加入 `namespace.unpriv_enable=1 user_namespace.enable=1` 等參數。
<br>
<hr>
<br>
## Files
### `plugstack.conf`
```
root@esc8000a-0:~# find / -name plugstack.conf
/var/spool/slurmd/conf-cache/plugstack.conf
root@esc8000a-0:~# cat /var/spool/slurmd/conf-cache/plugstack.conf
include /usr/share/pyxis/*
```
### `/usr/share/pyxis/pyxis.conf`
```
root@esc8000a-0:/tmp# cat /usr/share/pyxis/pyxis.conf
required /usr/lib/x86_64-linux-gnu/slurm/spank_pyxis.so
```
### `/var/lib/dpkg/info/enroot.conffiles`
```
root@esc8000a-0:/tmp# cat /var/lib/dpkg/info/enroot.conffiles
/etc/apparmor.d/enroot
/etc/enroot/enroot.conf
/etc/enroot/enroot.conf.d/README
/etc/enroot/environ.d/10-terminal.env
/etc/enroot/hooks.d/10-aptfix.sh
/etc/enroot/hooks.d/10-cgroups.sh
/etc/enroot/hooks.d/10-devices.sh
/etc/enroot/hooks.d/10-home.sh
/etc/enroot/hooks.d/10-localtime.sh
/etc/enroot/hooks.d/10-shadow.sh
/etc/enroot/hooks.d/98-nvidia.sh
/etc/enroot/hooks.d/99-mellanox.sh
/etc/enroot/mounts.d/10-system.fstab
/etc/enroot/mounts.d/20-config.fstab
```
<br>
<hr>
<br>
## 如何執行 SquashFS 映像檔(`.sqsh`)?
### 官方設計原理:
- `.sqsh` 是 SquashFS 映像檔,類似 Docker image 的壓縮格式檔案。
- `enroot import` 是從遠端容器映像來源(如 Docker registry、Podman)匯入映像,並產生 `.sqsh` 映像檔,通常用於取得並保存容器映像。
- `enroot create` 是將 `.sqsh` 映像檔解壓展開,產生一個可被啟動的「容器根檔案系統目錄」。
- `enroot start` 則是用來啟動這個已展開的「容器目錄」作為容器執行環境,**不能直接接受壓縮的 `.sqsh` 映像檔作為參數**。
<br>
### `enroot import`
```
Usage: enroot import [options] [--] URI
Import a container image from a specific location.
Schemes:
docker://[USER@][REGISTRY#]IMAGE[:TAG] Import a Docker image from a registry
dockerd://IMAGE[:TAG] Import a Docker image from the Docker daemon
podman://IMAGE[:TAG] Import a Docker image from a local podman repository
Options:
-a, --arch Architecture of the image (defaults to host architecture)
-o, --output Name of the output image file (defaults to "URI.sqsh")
```
<br>
### `enroot create`
```
Usage: enroot create [options] [--] IMAGE
Create a container root filesystem from a container image.
Options:
-n, --name Name of the container (defaults to "IMAGE")
-f, --force Overwrite an existing root filesystem
```
<br>
### `enroot start`
```
Usage: enroot start [options] [--] NAME|IMAGE [COMMAND] [ARG...]
Start a container and invoke the command script within its root filesystem.
Command and arguments are passed to the script as input parameters.
In the absence of a command script and if a command was given, it will be executed directly.
Otherwise, an interactive shell will be started within the container.
Options:
-c, --conf CONFIG Specify a configuration script to run before the container starts
-e, --env KEY[=VAL] Export an environment variable inside the container
--rc SCRIPT Override the command script inside the container
-r, --root Ask to be remapped to root inside the container
-w, --rw Make the container root filesystem writable
-m, --mount FSTAB Perform a mount from the host inside the container (colon-separated)
```
<br>
<hr>
<br>
## 操作測試
### srun & enroot start
```
# root@tj-slurm4-login-754cbbc8dd-kqvlh:~
$ scontrol show nodes
$ srun --nodelist=esc8000a-0 --pty bash
# ----------------------------------------
# root@esc8000a-0:/run#
# fetch xxx.sqush
$ enroot import docker://nvidia/cuda:12.4.0-base-ubuntu20.04
# check the local xxx.sqush
$ ll # -> nvidia+cuda+12.4.0-base-ubuntu20.04.sqsh
# unzip to /root/.local/share/enroot/nvidia+cuda+12.4.0-base-ubuntu20.04
$ enroot create nvidia+cuda+12.4.0-base-ubuntu20.04.sqsh
# check the file system
$ ll ~/.local/share/enroot/
$ enroot start nvidia+cuda+12.4.0-base-ubuntu20.04 cat /etc/os-release
```
- ### image source
https://hub.docker.com/r/nvidia/cuda/tags?name=20.04&page=6
- [nvidia/cuda:12.2.0-base-ubuntu20.04](https://hub.docker.com/layers/nvidia/cuda/12.2.0-base-ubuntu20.04/images/sha256-0a42e6fffe9f41cbb0d15dcf3e178b86e99cba9a3c209a035a6fa155e9716873)
- ### `$ scontrol show nodes`
```
root@tj-slurm4-login-754cbbc8dd-hsg4f:~# scontrol show nodes
NodeName=esc8000a-0 Arch=x86_64 CoresPerSocket=32
CPUAlloc=0 CPUEfctv=126 CPUTot=128 CPULoad=4.57
AvailableFeatures=esc8000a
ActiveFeatures=esc8000a
Gres=(null)
NodeAddr=10.244.2.135 NodeHostName=esc8000a-0 Version=25.05.0
OS=Linux 5.15.0-142-generic #152-Ubuntu SMP Mon May 19 10:54:31 UTC 2025
RealMemory=245760 AllocMem=0 FreeMem=152811 Sockets=2 Boards=1
CoreSpecCount=1 CPUSpecList=126-127
State=IDLE+DYNAMIC_NORM ThreadsPerCore=2 TmpDisk=0 Weight=1 Owner=N/A MCS_label=N/A
Partitions=tn
BootTime=2025-06-21T21:40:26 SlurmdStartTime=2025-06-26T04:58:52
LastBusyTime=2025-06-26T04:58:52 ResumeAfterTime=None
CfgTRES=cpu=126,mem=240G,billing=126
AllocTRES=
CurrentWatts=0 AveWatts=0
```
- ### `$ enroot import docker://nvidia/cuda:12.4.0-base-ubuntu20.04`
```
root@esc8000a-0:/run# enroot import docker://nvidia/cuda:12.4.0-base-ubuntu20.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] Downloading 6 missing layers...
100% 6:0=6s ea310eb267ca1cab61b6b16f566cd28bfd59a741395a011f5e76716e15ba57c6
[INFO] Extracting image layers...
100% 5:0=0s 17d0386c2fff30a5b92652bbef2b84639dba9b9f17bdbb819c8d10badd827fdb
[INFO] Converting whiteouts...
100% 5:0=0s 17d0386c2fff30a5b92652bbef2b84639dba9b9f17bdbb819c8d10badd827fdb
[INFO] Creating squashfs filesystem...
Parallel mksquashfs: Using 2 processors
Creating 4.0 filesystem on /run/nvidia+cuda+12.4.0-base-ubuntu20.04.sqsh, block size 131072.
[===========================================================================================================================================================================\] 4543/4543 100%
Exportable Squashfs 4.0 filesystem, lzo compressed, data block size 131072
uncompressed data, compressed metadata, compressed fragments,
compressed xattrs, compressed ids
duplicates are removed
Filesystem size 218640.50 Kbytes (213.52 Mbytes)
90.98% of uncompressed filesystem size (240318.67 Kbytes)
Inode table size 54140 bytes (52.87 Kbytes)
34.86% of uncompressed inode table size (155304 bytes)
Directory table size 45911 bytes (44.83 Kbytes)
49.81% of uncompressed directory table size (92178 bytes)
Number of duplicate files found 182
Number of inodes 4208
Number of files 3010
Number of fragments 314
Number of symbolic links 536
Number of device nodes 0
Number of fifo nodes 0
Number of socket nodes 0
Number of directories 662
Number of hard-links 4
Number of ids (unique uids + gids) 1
Number of uids 1
root (0)
Number of gids 1
root (0)
```
- ### `$ ll`
```
root@esc8000a-0:/run# ll
total 432024
drwxrwxrwx 6 root root 4096 Jun 26 04:21 ./
drwxr-xr-x 1 root root 4096 Jun 25 09:39 ../
-rw-r--r-- 1 root root 223891456 Jun 26 04:21 nvidia+cuda+12.4.0-base-ubuntu20.04.sqsh
```
- ### `$ enroot create nvidia+cuda+12.4.0-base-ubuntu20.04.sqsh`
```
root@esc8000a-0:/run# enroot create nvidia+cuda+12.4.0-base-ubuntu20.04.sqsh
[INFO] Extracting squashfs filesystem...
Parallel unsquashfs: Using 2 processors
3550 inodes (4543 blocks) to write
[===========================================================================================================================================================================/] 8093/8093 100%
created 3010 files
created 662 directories
created 536 symlinks
created 0 devices
created 0 fifos
created 0 sockets
created 4 hardlinks
```
- ### `$ enroot start nvidia+cuda+12.4.0-base-ubuntu20.04 cat /etc/os-release`
<br>
<hr>
<br>
### srun & enroot start
```
root@tj-slurm4-login-754cbbc8dd-kqvlh:~# srun --nodelist=esc8000a-0 --pty bash
root@esc8000a-0:~# ls -ls /mnt/data/sqsh/llm-gemma3-trainer-0.2.1.sqsh
22946016 -rw-r--r-- 1 root root 23496712192 Jun 24 03:28 /mnt/data/sqsh/llm-gemma3-trainer-0.2.1.sqsh
root@esc8000a-0:~# enroot start --rw /mnt/data/sqsh/llm-gemma3-trainer-0.2.1.sqsh
nvidia-container-cli: mount error: failed to add device rules: unable to find any existing device filters attached to the cgroup: bpf_prog_query(BPF_CGROUP_DEVICE) failed: operation not permitted
[ERROR] /etc/enroot/hooks.d/98-nvidia.sh exited with return code 1
```
### `srun -N1 --container-image=/mnt/data/sqsh/llm-gemma3-trainer-0.2.1.sqsh --pty bash`
```
$ srun -N1 --container-image=/mnt/data/sqsh/llm-gemma3-trainer-0.2.1.sqsh --pty bash
[2025-06-24T02:19:09.927] error: pyxis: container start failed with error code: 1
[2025-06-24T02:19:09.927] error: pyxis: printing enroot log file:
[2025-06-24T02:19:09.927] error: pyxis: nvidia-container-cli: mount error: failed to add device rules: unable to find any existing device filters attached to the cgroup: bpf_prog_query(BPF_CGROUP_DEVICE) failed: operation not permitted
[2025-06-24T02:19:09.927] error: pyxis: [ERROR] /etc/enroot/hooks.d/98-nvidia.sh exited with return code 1
[2025-06-24T02:19:09.927] error: pyxis: couldn't start container
[2025-06-24T02:19:09.927] error: spank: required plugin spank_pyxis.so: task_init() failed with rc=-1
[2025-06-24T02:19:09.927] error: Failed to invoke spank plugin stack
srun: error: esc8000b-2-0: task 0: Exited with exit code 1
```
- `/etc/nvidia-container-runtime/config.toml`
---
### `pyxis --version`, `enroot version`, `nvidia-container-cli --version`
```
# pyxis --version
dpkg -l | grep pyxis
ii nvslurm-plugin-pyxis 0.20.0-1 amd64 Slurm plugin for launching containerized tasks
# enroot version
3.5.0
# nvidia-container-cli --version
cli-version: 1.17.7
lib-version: 1.17.7
build date: 2025-05-16T13:27+00:00
build revision: d26524ab5db96a55ae86033f53de50d3794fb547
build compiler: x86_64-linux-gnu-gcc-7 7.5.0
build platform: x86_64
build flags: -D_GNU_SOURCE -D_FORTIFY_SOURCE=2 -DNDEBUG -std=gnu11 -O2 -g -fdata-sections -ffunction-sections -fplan9-extensions -fstack-protector -fno-strict-aliasing -fvisibility=hidden -Wall -Wextra -Wcast-align -Wpointer-arith -Wmissing-prototypes -Wnonnull -Wwrite-strings -Wlogical-op -Wformat=2 -Wmissing-format-attribute -Winit-self -Wshadow -Wstrict-prototypes -Wunreachable-code -Wconversion -Wsign-conversion -Wno-unknown-warning-option -Wno-format-extra-args -Wno-gnu-alignof-expression -Wl,-zrelro -Wl,-znow -Wl,-zdefs -Wl,--gc-section
```
---
### `nvidia-ctk config view`
```
# nvidia-ctk config view
#accept-nvidia-visible-devices-as-volume-mounts = false
#accept-nvidia-visible-devices-envvar-when-unprivileged = true
disable-require = false
supported-driver-capabilities = "compat32,compute,display,graphics,ngx,utility,video"
#swarm-resource = "DOCKER_RESOURCE_GPU"
[nvidia-container-cli]
#debug = "/var/log/nvidia-container-toolkit.log"
environment = []
#ldcache = "/etc/ld.so.cache"
ldconfig = "@/sbin/ldconfig.real"
load-kmods = true
no-cgroups = true
#path = "/usr/bin/nvidia-container-cli"
#root = "/run/nvidia/driver"
#user = "root:video"
[nvidia-container-runtime]
#debug = "/var/log/nvidia-container-runtime.log"
log-level = "info"
mode = "auto"
runtimes = ["docker-runc", "runc", "crun"]
[nvidia-container-runtime.modes]
[nvidia-container-runtime.modes.cdi]
annotation-prefixes = ["cdi.k8s.io/"]
default-kind = "nvidia.com/gpu"
spec-dirs = ["/etc/cdi", "/var/run/cdi"]
[nvidia-container-runtime.modes.csv]
mount-spec-path = "/etc/nvidia-container-runtime/host-files-for-container.d"
[nvidia-container-runtime.modes.legacy]
cuda-compat-mode = "ldconfig"
[nvidia-container-runtime-hook]
path = "nvidia-container-runtime-hook"
skip-mode-detection = false
[nvidia-ctk]
path = "nvidia-ctk"
```
<br>
### [可能方向] 檢查 kernel.unprivileged_bpf_disabled 設定
```
# 查看設定值
sysctl kernel.unprivileged_bpf_disabled
```
- 如果沒有回應或者顯示 `kernel.unprivileged_bpf_disabled = 1`,代表非 root 用戶無法執行 BPF 程式。
- 若要暫時關閉限制(以 root 執行):
```bash
sysctl -w kernel.unprivileged_bpf_disabled=0
```
- 永久修改可編輯 `/etc/sysctl.conf` 加入:
```ini
kernel.unprivileged_bpf_disabled=0
```
<br>
<br>
<hr>
<br>
## securityContext
### 列出完整的 capabilities (所有能力)?
- gpt-4.1-mini
當你在 Kubernetes 或 Linux 容器中設定 `securityContext.capabilities.add`,可以選擇附加的 Linux capabilities(能力)有一整套,以下列出 Linux kernel 常見的 capabilities(參考 Linux kernel `capabilities(7)`):
---
## 常見 Linux Capabilities 列表
| Capability | 說明 |
| -------------------- | ---------------------------------- |
| `CHOWN` | 允許改變檔案擁有者和群組 |
| `DAC_OVERRIDE` | 繞過檔案讀取/寫入/執行的 DAC 權限判斷 |
| `DAC_READ_SEARCH` | 繞過目錄搜尋的 DAC 權限判斷 |
| `FOWNER` | 忽略檔案的擁有者限制 |
| `FSETID` | 忽略 set-user-ID 和 set-group-ID bits |
| `KILL` | 使用 `kill()` 向其他進程送信號 |
| `SETGID` | 設定群組識別(GID) |
| `SETUID` | 設定使用者識別(UID) |
| `SETPCAP` | 修改 process capabilities |
| `LINUX_IMMUTABLE` | 修改不可變(immutable)位元 |
| `NET_BIND_SERVICE` | 綁定 1024 以下埠口 |
| `NET_BROADCAST` | 傳送廣播訊號 |
| `NET_ADMIN` | 網路管理(例如設定網路介面) |
| `NET_RAW` | 使用 raw sockets |
| `IPC_LOCK` | 鎖定記憶體,避免被 swap |
| `IPC_OWNER` | IPC 物件權限 |
| `SYS_MODULE` | 插入/移除 kernel 模組 |
| `SYS_RAWIO` | 進行原始 IO 操作(如 iopl/io perm) |
| `SYS_CHROOT` | 變更 root 目錄 |
| `SYS_PTRACE` | 使用 ptrace 監控其他程序 |
| `SYS_PACCT` | 設定 process accounting |
| `SYS_ADMIN` | 幾乎所有管理型系統權限(危險且強大) |
| `SYS_BOOT` | 關機與重啟系統 |
| `SYS_NICE` | 調整程序優先權 |
| `SYS_RESOURCE` | 修改系統資源限制(如檔案數、記憶體限制) |
| `SYS_TIME` | 設定系統時間 |
| `SYS_TTY_CONFIG` | 設定 tty 相關參數 |
| `MKNOD` | 建立特殊檔案 |
| `LEASE` | 設定檔案 Lease |
| `AUDIT_WRITE` | 寫入 audit 記錄 |
| `AUDIT_CONTROL` | 控制 audit 系統 |
| `SETFCAP` | 設定檔案 capabilities |
| `MAC_OVERRIDE` | 繞過 MAC(如 SELinux)安全限制 |
| `MAC_ADMIN` | 管理 MAC 設定 |
| `SYSLOG` | 管理系統日誌 |
| `WAKE_ALARM` | 設定喚醒鬧鐘 |
| `BLOCK_SUSPEND` | 阻止系統掛起 |
| `AUDIT_READ` | 讀取 audit 日誌 |
| `PERFMON` | 使用性能監控 |
| `BPF` | 使用 BPF(Berkeley Packet Filter)程式 |
| `CHECKPOINT_RESTORE` | 進行 checkpoint 與 restore |
---
## Kubernetes `securityContext.capabilities.add` 常用示例
```yaml
securityContext:
privileged: false
capabilities:
add:
- SYS_ADMIN
- SYS_RESOURCE
- SYS_PTRACE
- NET_ADMIN
- DAC_OVERRIDE
```
---
## 說明
* `privileged: true` 等同於給容器「全部」 capabilities(幾乎無限制)
* 只加選特定 capability 時,必須視需求而定,因為每個 capability 涉及的權限範圍不同,過多會影響安全性
* 常用於需要系統層面管理權限的應用,如 GPU 裝置管理、系統時間設定、網路設定等
---
如果需要,我可以幫你針對你的應用情境,建議一組合適的 capabilities 名單!