iT邦幫忙

0

Container in Container with GPU

  • 分享至 

  • xImage

日前遇到需求是要在 GCP 的 GKE 上建置 nested container 且最內層的 Container 要可以連接到 GPU。

目前實測不考慮 GPU 下, 利用 Podman 或 docker in docker 或 crun + cgroup 都可以順利完成,但總是無法在最內層的容器抓到 GPU, 想詢問各位先進,有沒有相關經驗可以提供我作為 debug 的方向。

非常感謝!

圖片
  熱門推薦
圖片
{{ item.channelVendor }} | {{ item.webinarstarted }} |
{{ formatDate(item.duration) }}
直播中

1 個回答

0
海綿寶寶
iT邦大神 1 級 ‧ 2025-05-17 18:10:56

Grok回答如下

在 GCP 的 GKE 上建置嵌套容器(nested container)並讓最內層容器連接到 GPU 是一個複雜的挑戰,涉及容器運行時、權限、cgroup 設定、GPU 驅動程式以及 GKE 的特定限制。以下是針對你的問題的一些分析和 debug 方向,結合現有的技術背景和可能遇到的問題:

---

### 問題分析

1. **GKE 的 GPU 支援**:
   - GKE 支援 NVIDIA GPU,但需要特定的節點設定(例如,啟用 GPU 節點池並安裝 NVIDIA 驅動程式)。
   - 在 GKE 中,GPU 是通過 Kubernetes 資源(`nvidia.com/gpu`)分配給 Pod 的,且需要 NVIDIA 容器工具包(NVIDIA Container Toolkit)來將 GPU 暴露給容器。
   - 嵌套容器環境增加了複雜性,因為最內層容器需要正確繼承 GPU 設備和相關的驅動程式庫。

2. **嵌套容器的挑戰**:
   - 嵌套容器(例如 Docker-in-Docker 或 Podman)需要特定的權限(通常是 `--privileged` 或特定的 capability)來訪問底層設備(如 `/dev/nvidia*`)。
   - 在 GKE 上,預設的安全設定(例如 Pod 安全性策略或 seccomp)可能限制嵌套容器的設備訪問。
   - cgroups(尤其是 cgroup v2)可能導致嵌套容器無法正確管理資源或設備,這在你的描述中已經提到。

3. **GPU 訪問問題**:
   - 最內層容器無法看到 GPU,可能是因為:
     - GPU 設備未正確傳遞到內層容器(例如,缺少 `--device` 或 CDI 設定)。
     - NVIDIA 驅動程式庫未正確掛載到內層容器(例如,`/usr/lib/nvidia` 或 `/usr/local/nvidia`)。
     - 嵌套容器運行時(Podman、Docker 或 crun)未正確配置 NVIDIA Container Toolkit。
     - GKE 的安全限制(例如,SELinux、AppArmor 或 seccomp)阻止了設備訪問。

4. **Podman/Docker-in-Docker/crun 的行為**:
   - **Podman**:作為無守護進程的容器工具,Podman 支援 rootless 和 privileged 模式,但在嵌套場景下,cgroup v2 和設備傳遞可能需要額外配置。
   - **Docker-in-Docker (DinD)**:DinD 需要掛載 Docker socket 或以特權模式運行,這可能與 GPU 設備傳遞衝突。
   - **crun**:作為輕量級 OCI 運行時,crun 支援 cgroup v2,但在嵌套容器中可能遇到 cgroup 路徑或權限問題。

---

### Debug 方向與建議

以下是一些具體的 debug 方向和解決方案,針對你在 GKE 上建置嵌套容器並讓內層容器訪問 GPU 的需求:

#### 1. 確認 GKE 節點的 GPU 設定
   - **檢查 GPU 是否可用**:
     確保你的 GKE 節點池已正確配置 GPU(例如,A100、V100 或 T4)。運行以下命令檢查:
     ```bash
     kubectl describe node <node-name> | grep nvidia.com/gpu
     ```
     確認 `nvidia.com/gpu` 資源存在且分配正確。
   - **檢查 NVIDIA 驅動程式**:
     GKE 使用 NVIDIA GPU 驅動程式 DaemonSet 自動安裝驅動程式。確保 DaemonSet 已正確運行:
     ```bash
     kubectl get daemonset -n kube-system | grep nvidia
     ```
     如果未看到 `nvidia-driver-installer` 或類似 DaemonSet,請按照 [GKE 文檔](https://cloud.google.com/kubernetes-engine/docs/how-to/gpus) 手動啟用 GPU 支援。
   - **驗證 NVIDIA Container Toolkit**:
     確保節點已安裝 NVIDIA Container Toolkit(`nvidia-container-toolkit`)。你可以進入節點並檢查:
     ```bash
     nvidia-container-cli --version
     ```
     如果未安裝,可能需要手動配置。

#### 2. 配置嵌套容器環境
   - **使用特權模式**:
     在嵌套容器場景中,外部容器通常需要以特權模式運行以訪問 GPU 設備。確保你的 Pod 配置文件包含:
     ```yaml
     spec:
       containers:
       - name: outer-container
         securityContext:
           privileged: true
         resources:
           limits:
             nvidia.com/gpu: 1
     ```
     這確保外部 Pod 可以訪問 GPU 並將其傳遞給內層容器。
   - **掛載 GPU 設備**:
     確保外部容器正確掛載了 GPU 相關的設備和庫。例如,在 Docker 或 Podman 中運行外部容器時,添加以下參數:
     ```bash
     podman run --privileged --device=/dev/nvidia0:/dev/nvidia0 --device=/dev/nvidia-ctl:/dev/nvidia-ctl --device=/dev/nvidia-uvm:/dev/nvidia-uvm -v /usr/lib/nvidia:/usr/lib/nvidia ...
     ```
     對於嵌套容器,內層容器也需要類似的設備傳遞。
   - **檢查 CDI 支援**:
     NVIDIA Container Toolkit 支援容器設備介面(CDI),這是將 GPU 暴露給容器的現代方式。確保你的 Podman 或 Docker 配置使用了 CDI:
     ```bash
     podman run --device nvidia.com/gpu=all ...
     ```
     如果 CDI 未生效,檢查 `/etc/cdi` 是否包含 NVIDIA 相關的 CDI 配置文件(例如,`nvidia.yaml`)。

#### 3. 解決 cgroup 相關問題
   - **檢查 cgroup 版本**:
     GKE 預設使用 cgroup v2(尤其在較新的版本中)。確認節點的 cgroup 版本     ```bash
     stat -fc %T /sys/fs/cgroup/
     ```
     如果節點使用 cgroup v2,確保你的嵌套容器運行時(Podman、Docker 或 crun)支援 cgroup v2。根據你的描述,cgroup v2 可能導致嵌套容器無法正確訪問設備。
   - **解決 cgroup 路徑問題**:
     在嵌套容器中,內層容器可能無法訪問正確的 cgroup 路徑(例如,`/sys/fs/cgroup/devices/libpod_parent`)。嘗試以下解決方案:
     - 啟用嵌套 cgroup 支援(僅適用於 cgroup v2):
       ```bash
       mkdir -p /sys/fs/cgroup/init
       xargs -rn1 < /sys/fs/cgroup/cgroup.procs > /sys/fs/cgroup/init/cgroup.procs || :
       sed -e 's/ / +/g' -e 's/^/+/' < /sys/fs/cgroup/cgroup.controllers > /sys/fs/cgroup/cgroup.subtree_control
       ```
       這確保內層容器可以在獨立的 cgroup 中運行。[](https://stackoverflow.com/questions/70872355/how-to-resolve-cgroup-error-when-running-docker-container-inside-a-docker-contai)
     - 如果問題持續,考慮在外部容器中運行 systemd 以管理 cgroup:
       ```bash
       podman run --privileged --systemd=always ...
       ```
   - **檢查權限**:
     確保內層容器的 cgroup 路徑(例如,`/sys/fs/cgroup/devices`)對運行用戶是可寫的。如果使用 rootless Podman,檢查 `XDG_RUNTIME_DIR` 是否正確設置並可寫。[](https://github.com/containers/podman/blob/main/troubleshooting.md)

#### 4. 驗證內層容器的 GPU 訪問
   - **運行 nvidia-smi**:
     在內層容器中運行以下命令檢查 GPU 是否可見:
     ```bash
     nvidia-smi
     ```
     如果失敗,檢查以下內容:
     - 確保內層容器正確繼承了外部容器的設備和庫。
     - 檢查是否有安全限制(例如,SELinux 或 AppArmor)阻止了訪問。
   - **檢查日誌**:
     查看內層容器的日誌,尋找與 GPU 相關的錯誤(例如,`nvidia-container-cli: mount error` 或 `no such device`)。這些錯誤可能指向設備掛載或權限問題。[](https://lists.podman.io/archives/list/podman%40lists.podman.io/thread/VOF6W7LQ5Q3464F5EO2YN2ZTJWE27H5E/)
   - **測試簡單用例**:
     使用一個簡單的 CUDA 容器(例如,`nvidia/cuda:11.0.3-base-ubuntu20.04`)作為內層容器,確保問題不是由應用程式本身引起:
     ```bash
     podman run --rm --device nvidia.com/gpu=all nvidia/cuda:11.0.3-base-ubuntu20.04 nvidia-smi
     ```

#### 5. 檢查 GKE 特定的限制
   - **Pod 安全性策略**:
     GKE 可能應用了 Pod 安全性策略(PodSecurityPolicy 或 Gatekeeper),限制了特權模式或設備訪問。檢查集群的安全策略:
     ```bash
     kubectl get psp
     ```
     如果需要,創建一個允許特權容器和設備訪問的策略。
   - **網絡和 DNS 配置**:
     確保內層容器的網絡配置正確,特別是如果 GPU 相關的操作需要訪問外部服務(例如,NVIDIA 驅動程式下載)。檢查 DNS 設置:
     ```bash
     podman run --rm nvidia/cuda:11.0.3-base-ubuntu20.04 cat /etc/resolv.conf
     ```
     如果 DNS 配置無效,添加 `--dns` 參數。[](https://docs.podman.io/en/latest/markdown/podman-run.1.html)
   - **GKE 版本兼容性**:
     確保你的 GKE 集群版本支援嵌套容器和 GPU。較舊的版本可能有已知的 cgroup 或設備傳遞問題。考慮升級到最新的穩定版本(例如,1.27 或更高)。

#### 6. 替代方案
   如果嵌套容器無法穩定訪問 GPU,考慮以下替代方案:
   - **直接在 Pod 中運行 GPU 工作負載**:
     避免嵌套容器,直接在 GKE Pod 中運行 GPU 工作負載。這需要調整你的應用程式架構,但可以減少複雜性。
   - **使用 Kubernetes Job 或 DaemonSet**:
     將內層容器的任務封裝為 Kubernetes Job 或 DaemonSet,直接分配 GPU 資源。
   - **使用 GKE 的 Autopilot 模式**:
     GKE Autopilot 自動管理節點配置,可能簡化 GPU 和容器運行時的設定。
   - **測試其他運行時**:
     如果 crun 持續失敗,嘗試使用 runc 或其他 OCI 運行時,並確保它們與 NVIDIA Container Toolkit 兼容。

---

### Debug 步驟總結

1. 確認 GKE 節點的 GPU 資源和 NVIDIA 驅動程式是否正確配置。
2. 確保外部容器以特權模式運行並正確掛載 GPU 設備和庫。
3. 檢查 cgroup v2 配置,啟用嵌套支援或使用 systemd 管理 cgroup。
4. 在內層容器中運行 `nvidia-smi` 並檢查日誌以診斷 GPU 訪問問題。
5. 檢查 GKE 的安全策略、網絡配置和集群版本是否限制了嵌套容器。
6. 如果問題持續,簡化架構或測試替代運行時。

---

### 常見問題與解決方案

- **問題**:內層容器報錯 `nvidia-container-cli: mount error: permission denied`。
  - **解決方案**:確保外部容器以特權模式運行,並檢查 SELinux/AppArmor 設定。嘗試禁用安全限制(僅用於測試):
    ```bash
    podman run --security-opt label=disable ...
    ```
   [](https://lists.podman.io/archives/list/podman%40lists.podman.io/thread/VOF6W7LQ5Q3464F5EO2YN2ZTJWE27H5E/)

- **問題**:cgroup 相關錯誤(例如,`cannot enter cgroupv2` 或 `pids.max: no such file`)。
  - **解決方案**:啟用嵌套 cgroup 支援或在外部容器中運行 systemd。確保 `XDG_RUNTIME_DIR` 可寫。[](https://stackoverflow.com/questions/70872355/how-to-resolve-cgroup-error-when-running-docker-container-inside-a-docker-contai)[](https://access.redhat.com/solutions/5913671)

- **問題**:內層容器無法解析 NVIDIA 相關的域名。
  - **解決方案**:添加 `--dns` 參數或檢查 `/etc/resolv.conf` 是否正確。[](https://docs.podman.io/en/latest/markdown/podman-run.1.html)

---

### 後續步驟

如果你已經嘗試了上述步驟但問題仍未解決,請提供以下信息以進一步診斷:
1. 你的 GKE 集群版本和節點作業系統(例如,COS 或 Ubuntu)。
2. 外部和內層容器的具體運行命令(包括所有參數)。
3. 內層容器運行 `nvidia-smi` 時的完整錯誤訊息。
4. 外部容器的 cgroup 配置(例如,`cat /sys/fs/cgroup/cgroup.controllers`)。
5. 是否使用了特定的安全策略或網絡配置。

這些信息可以幫助我提供更精確的建議。如果你有其他問題或需要更詳細的配置範例,請隨時告訴我!

我要發表回答

立即登入回答