惯性聚合 高效追踪和阅读你感兴趣的博客、新闻、科技资讯
阅读原文 在惯性聚合中打开

推荐订阅源

IT之家
IT之家
C
CXSECURITY Database RSS Feed - CXSecurity.com
V
Visual Studio Blog
D
Darknet – Hacking Tools, Hacker News & Cyber Security
小众软件
小众软件
L
LangChain Blog
Cyberwarzone
Cyberwarzone
美团技术团队
The Register - Security
The Register - Security
Threat Intelligence Blog | Flashpoint
Threat Intelligence Blog | Flashpoint
T
Tor Project blog
V
V2EX
Security Archives - TechRepublic
Security Archives - TechRepublic
Hacker News: Ask HN
Hacker News: Ask HN
L
LINUX DO - 最新话题
Recent Announcements
Recent Announcements
H
Hackread – Cybersecurity News, Data Breaches, AI and More
酷 壳 – CoolShell
酷 壳 – CoolShell
freeCodeCamp Programming Tutorials: Python, JavaScript, Git & More
aimingoo的专栏
aimingoo的专栏
人人都是产品经理
人人都是产品经理
F
Full Disclosure
V2EX - 技术
V2EX - 技术
The Cloudflare Blog
博客园 - 叶小钗
T
Threat Research - Cisco Blogs
阮一峰的网络日志
阮一峰的网络日志
G
GRAHAM CLULEY
OSCHINA 社区最新新闻
OSCHINA 社区最新新闻
Latest news
Latest news
S
Security @ Cisco Blogs
Spread Privacy
Spread Privacy
Project Zero
Project Zero
K
Kaspersky official blog
MyScale Blog
MyScale Blog
Attack and Defense Labs
Attack and Defense Labs
云风的 BLOG
云风的 BLOG
博客园 - 【当耐特】
Hacker News - Newest:
Hacker News - Newest: "LLM"
大猫的无限游戏
大猫的无限游戏
P
Privacy International News Feed
Google DeepMind News
Google DeepMind News
WordPress大学
WordPress大学
C
Cybersecurity and Infrastructure Security Agency CISA
Webroot Blog
Webroot Blog
罗磊的独立博客
Vercel News
Vercel News
N
News and Events Feed by Topic
A
Arctic Wolf
C
CERT Recently Published Vulnerability Notes

Kenvix's Blog

手动保留常用端口,解决 Windows 端口被 Hyper-V / WinNAT 占用的问题 免Telent/TTL屏蔽运营商新版光猫的远控、TR069和RMS,获取动态随机超级管理员密码并固化权限 | Kenvix's Blog 利用Windows卷影副本(Volume Shadow)找回被覆盖和删除的数据 | Kenvix's Blog 在Windows下实现WireGuard动态DNS解析(DDNS)的正确方法:避免无意义的开销 | Kenvix's Blog OpenWRT/DNSMasq 配置DHCP静态路由主动推送 实现流量直达和旁路由流量零代价分载 | Kenvix's Blog 解决 Windows 打开视频/图片文件夹很慢的问题 | Kenvix's Blog AltA2DP - 向支持Sony LDAC协议的耳机提供Windows下蓝牙LDAC音频编码器支持 | Kenvix's Blog (2024更新)修复黑群晖 DSM7.0 + Btrfs 存储空间/磁盘损毁/堪用 的问题 校园网白嫖思路分享:局域网中转-不花钱、不认证、高速上网 | Kenvix's Blog 在 Windows 上配置网卡多个 VLAN、多个虚拟网卡、实现单线多拨网速叠加(无需驱动支持) | Kenvix's Blog 解决视频彩铃、语音通话自动转视频通话导致打电话自动挂断的问题 | Kenvix's Blog 超低成本廉价考研教程:如何用小于¥500甚至¥300的开销考个研 | Kenvix's Blog 在 Ubuntu 21.10 上启用蓝牙 LDAC/AAC/AptX 高质量音频编码支持 在 VMware Workstation 桥接模式的网卡上让虚拟机使用 VLAN 的正确方法 在 Windows 上设置 NAT 或网络共享的正确方法——避免Wi-Fi热点无法使用 自编译 红米 AC2100 OpenWRT R21.7.26 Linux 内核结构和子系统简介 | Kenvix's Blog Java 快速读取文本 (算法竞赛适用) | Kenvix's Blog 利用 ThreadLocal + Lambda,实现有状态变量的单例模式 | Kenvix's Blog 状态压缩的动态规划问题:骨牌完全覆盖棋盘问题 | Kenvix's Blog 我的 Windows 10 2004 新增 Bug 解决办法记录 解决 Android Studio 及 IDEA 中 Gradle 错误信息乱码的问题 Kotlin 的那些骚操作 | Kenvix's Blog 在普通的 Gradle Java/Kotlin 项目中使用 BuildConfig 修复国行 MIUI 打开 Google Play 始终提示 DF-DFERH-01 的问题 解决 VSCode 持续调用 WMIC 导致一个 CPU 核心完全被占满的问题 扔鸡蛋问题 | Kenvix's Blog 计算机幻觉从入门到入土 | Kenvix's Blog Java 注解预处理 Annotation Processing & 代码生成 Ubuntu 上通过以太网分享网络连接(NAT) | Kenvix's Blog Windows 选择指定的网卡来开承载网络型热点 | Kenvix's Blog 修复升级 Windows10 版本后所有内置应用闪退+第三方应用参数错误的问题 | Kenvix's Blog 配置用于 Gradle6.x + MySQL 8 的 jOOQ 3.14 代码自动生成 (已更新) 修复 Windows 环境下的程序访问 WSL 中的 MySQL 提示 Access Denied 的问题 修复 WSL 下 PHP+FastCGI 卡死的问题 使用任意磁盘或路径保存 Windows 文件历史记录 | Kenvix's Blog [1.12.2+Mod] MoeCraft :: 自由开放的科技向公益 Mod 服务器 Kenvix's Blog 禁用使用Intel核显的Windows笔记本自动调节亮度功能 | Kenvix's Blog 真正实现Minecraft高级登录(外置登录)的几种方案 | Kenvix's Blog 谈谈神舟的两艘贼船,Z7M-KP7S1 / Z7M-KP7SC USBCopyer: 插上U盘自动按需复制文件 | Kenvix's Blog USBCopyer 回调功能详细说明 | Kenvix's Blog C# 实现自定义"应用程序设置"的配置文件(user.config)存储路径 | Kenvix's Blog Win10 资源管理器为所有格式激活“编辑”按钮并修改文本文件“编辑”按钮的编辑器 | Kenvix's Blog 留言板 | Kenvix's Blog 又一次 Hello world | Kenvix's Blog Java 学习笔记 (仍在更新) | Kenvix's Blog 在Win10 Pro下挂载NFS(网络文件系统) | Kenvix's Blog Nginx 反向代理 Aria2 JSONRPC | Kenvix's Blog (Android6.0~9.0) 清除锁屏密码 | Kenvix's Blog WordPress 更换站点地址后批量修改文章/评论中的旧地址 | Kenvix's Blog 修复一加3/3T因固件过老导致刷入ROM时提示错误7的问题 | Kenvix's Blog 修复Android DM-Verity 警告 | Kenvix's Blog 贴吧云签到 资源索引(下载|文档|插件) | Kenvix's Blog 继续监控!使用树莓派+Motion实现实时视频监控并通过浏览器查看 | Kenvix's Blog 自动获取Pixiv每日排行榜第一张图片(600x600 | 可用于博客背景图) | Kenvix's Blog 使用树莓派实现定时拍照监控并发送邮件到邮箱 | Kenvix's Blog 好压 V2.7 Beta1 绿色版——功能强大,良心的压缩软件 | Kenvix's Blog 任意语言实现读取压缩包注释 | Kenvix's Blog 自己实现QQ群自定义分享(管理员开启了群交易?) | Kenvix's Blog MoeCDN - 加速Gravatar/GoogleAPIs等无法在国内访问的资源 | Kenvix's Blog [Minecraft] WebLogin-连接到你的服务器来检查玩家是否可以登录 | Kenvix's Blog Android卡刷包提示This package is for device: ... this device is ...的解决方案 Kenvix's Blog 给EMLOG评论框加上复选框[√]防止垃圾评论 | Kenvix's Blog 欢迎使用emlog | Kenvix's Blog
实现带有Nvidia GPU+Rootless Podman+Docker+Systemd+自动驱动注入支持的systemd nspawn容器 | Kenvix's Blog
2026-02-02 · via Kenvix's Blog

在AI计算集群等场景中,系统级容器的稳定部署、GPU资源高效透传及多容器运行时兼容是核心需求,传统容器方案要么无法良好支持systemd服务管理,要么GPU透传配置复杂、需在容器内重复安装驱动,且难以兼顾Rootless Podman与Docker的二级容器运行需求。本文针对这一现状,详细阐述一套集成Nvidia GPU透传、自动驱动注入、systemd-nspawn容器管理及多二级容器运行时的完整方案,该方案已在某高校AI计算集群中稳定运行数月,可有效降低集群容器化部署的复杂度,提升资源利用率。

针对传统容器部署存在GPU透传配置繁琐、需在容器内额外安装驱动导致环境冗余、systemd支持不足、二级容器运行时兼容性差及Rootless模式适配困难等痛点,本方案核心优势在于无需在容器内安装GPU驱动,可动态扫描并挂载NVIDIA库和工具,完美支持GPU透传与CDI驱动注入,兼容Docker与Rootless Podman两种二级容器运行时,同时通过脚本实现systemd-nspawn容器的自动监控与管理,简化集群部署与运维成本。

功能特性:

  • 多级容器的 NVIDIA GPU 透传支持,支持 DinD/PinD 模式
  • ✅ 动态扫描 NVIDIA 库和工具,不需要在容器内安装 GPU 驱动,容器驱动自动跟随宿主机更新
  • ✅ 真正的系统级容器,完美支持 systemd 服务管理,同时无Docker一级容器方案的存储冗余、可靠性差等诸多弊端。
  • ✅ 支持 Docker 和 Podman 二级容器运行时,容器内可以再运行容器,支持 CDI 方式的 NVIDIA GPU 驱动注入
  • ✅ 多节点集群支持,自动配置跨节点路由,支持宿主集群NFS。
  • ✅ 支持 Rootless Podman 容器运行时,安全性风险低。
  • ✅ 自动监控和管理 systemd-nspawn 容器。

宿主环境准备

宿主机需要安装好 NVIDIA GPU 驱动和 NVIDIA Container Toolkit,具体请参考,对于 Ubuntu 22.04,安装步骤如下:

apt update
apt install systemd-container debootstrap tmux
apt install nvidia-container-toolkit nvidia-container-toolkit-base libnvidia-container-tools
systemd-nspawn --version
machinectl --version

由于 Nspawn 的 NAT 存在诸多 Bug,不推荐使用,因此我们还需要宿主机存在一个网络提供者给一级容器使用,这里我直接借用了宿主机的 Docker 网络,为此也需要在宿主机上安装 Docker,后续的脚本会自动创建 Docker network :

sudo apt update
sudo apt install docker-ce docker-ce-cli containerd.io docker-buildx-plugin docker-compose-plugin

由于 Nspawn 的端口转发(-p 参数)也存在诸多 Bug,我们使用 rinetd 提供端口转发功能,因此还需要安装 rinetd :

sudo apt install rinetd

本文后续的宿主和容器配置均基于 Ubuntu 22.04 操作系统。其他发行版请参考对应的官方文档进行安装,也欢迎在评论区进行补充。

一级容器 systemd-nspawn 容器支持配置

首先安装一级容器的操作系统,我这里安装到了 /var/lib/machines/inais

sudo mkdir -p /var/lib/machines/inais
sudo debootstrap \
  --include=systemd,dbus \
  jammy \
  /var/lib/machines/ubuntu22 \
  http://archive.ubuntu.com/ubuntu

mkdir -p /var/lib/machines/_Scripts
cd /var/lib/machines/_Scripts

请将我附件提供的 Shell 脚本(点击下载) 上传到 /var/lib/machines/_Scripts 目录下,脚本用于管理基于 systemd-nspawn 的 INAIS 容器环境,支持多节点存储绑定、NVIDIA GPU 透传、自动网络配置和端口转发。

使用方法:

./run.sh daemon

以守护进程模式运行,自动监控和管理容器。

脚本会自动加载同目录下的配置文件 config-{脚本名}.sh,例如 run.sh 会加载 config-run.sh

配置项说明

必需配置项

变量名 类型 说明 示例值
INAIS_HOST_ACCOUNT string 主机账户名,用于构建存储路径 "Kenvix"
NODE_ID integer 当前节点ID(1~MAX_NODE_ID) 15
CONTAINER_NAME string 容器名称,用于 machinectl 管理 "inais"
CONTAINER_ROOT string 容器根文件系统路径 "/var/lib/machines/inais"
CONTAINER_INDEX integer 容器索引,用于计算容器IP地址 0
INAIS_NETWORK_MODE string 网络模式:"docker""veth" "docker"
USE_RINETD_PORT_FORWARDING boolean 端口转发方式:true=rinetd, false=systemd-nspawn内置 false

可选配置项

变量名 类型 默认值 说明
MAX_NODE_ID integer 21 最大节点ID,决定节点范围 1~N
DISABLE_LOCAL_STORAGE_BINDINGS boolean false 设为 true 禁用本地存储挂载(当前节点的 /data/inXX
DISABLE_NVIDIA_BINDINGS boolean false 设为 true 禁用所有 NVIDIA 设备和库文件挂载
LOCAL_DATA_PREFIX string /data 本地数据目录前缀
NFS_STORAGE_PREFIX string /storagenfs/nfs NFS 存储路径前缀(不含节点编号)
PORT_FORWARD_HOST_START integer 30600 主机端起始端口号
PORT_FORWARD_CONTAINER_START integer 30000 容器端起始端口号
PORT_FORWARD_COUNT integer 20 端口映射数量

配置详解

网络模式 (INAIS_NETWORK_MODE)

docker 模式
  • 使用 Docker 创建的桥接网络 inais0
  • 容器 IP 格式:253.{NODE_ID}.{CONTAINER_INDEX/256+1}.{CONTAINER_INDEX%256}
  • 子网:253.{NODE_ID}.0.0/16
  • 网关:253.{NODE_ID}.0.1

我这里使用了 IPv4 Class-E 类IP这种比较邪门的地址,以避免和现有网络冲突。也可以修改脚本使用其他私有地址段,例如 10.{NODE_ID}.0.0/16 。需注意 Windows 只对 E 类地址提供有限支持,即可以连接但无法监听;Linux 则完整支持 E 类地址作为单播地址。

veth 模式
  • 使用 veth pair 直连
  • 主机端 IP:253.{NODE_ID}.{CONTAINER_INDEX}.1/24
  • 容器端 IP:253.{NODE_ID}.{CONTAINER_INDEX}.2/24
  • 自动配置 NAT MASQUERADE

端口映射配置

端口映射范围由三个变量控制:

主机端口范围: PORT_FORWARD_HOST_START ~ (PORT_FORWARD_HOST_START + PORT_FORWARD_COUNT - 1)

容器端口范围: PORT_FORWARD_CONTAINER_START ~ (PORT_FORWARD_CONTAINER_START + PORT_FORWARD_COUNT - 1)

默认配置30600-3061930000-30019(共 20 个端口)

端口转发方式

  • USE_RINETD_PORT_FORWARDING=false:使用 systemd-nspawn 内置的 --port 参数
  • USE_RINETD_PORT_FORWARDING=true:使用外部 rinetd 工具,支持 TCP 和 UDP

存储绑定

脚本支持多个节点组成集群,组成集群时,编号必须是连续的整数,从 1 开始,到 MAX_NODE_ID 结束。

存储绑定是可选的,可以通过上面的选项禁用。

存储路径前缀

注意:为了提高效率,容器和脚本本身并不直接操作 NFS 存储,而是通过宿主机的 NFS 挂载路径进行绑定。因此请确保宿主机已经正确挂载了 NFS。

可通过以下变量自定义存储路径:

变量名 默认值 说明
LOCAL_DATA_PREFIX /data 本地数据目录前缀
NFS_STORAGE_PREFIX /storagenfs/nfs NFS 存储路径前缀(不含节点编号)
节点存储

脚本会自动为所有节点(1 到 MAX_NODE_ID)创建存储绑定:

节点类型 主机路径 容器路径
当前节点 {LOCAL_DATA_PREFIX}/{INAIS_HOST_ACCOUNT} /data/in{NODE_ID:02d}
远程节点 {NFS_STORAGE_PREFIX}{XX}/{INAIS_HOST_ACCOUNT} /data/in{XX}
静态绑定路径
主机路径 容器路径 说明
{LOCAL_DATA_PREFIX}/{INAIS_HOST_ACCOUNT}/home /home 用户主目录
{LOCAL_DATA_PREFIX}/{INAIS_HOST_ACCOUNT} /data/this 当前节点数据(别名)
/var/lib/machines/_Data/inais /ssd 本地 SSD 存储

NVIDIA GPU 支持

DISABLE_NVIDIA_BINDINGS=false(默认)时,脚本会自动挂载:

设备文件(读写)
  • /dev/nvidia0 ~ /dev/nvidia7
  • /dev/nvidiactl
  • /dev/nvidia-modeset
  • /dev/nvidia-uvm
  • /dev/nvidia-uvm-tools
  • /dev/nvidia-caps
  • /dev/nvidia-nvswitchctl
  • /dev/dri

因为几乎不存在大于8卡的情况,因此这里我写死了最多支持 8 块 GPU(/dev/nvidia0 ~ /dev/nvidia7),如果需要更多,请自行修改脚本。如果少于8卡,则多余的设备文件不会被挂载,不必修改。

系统路径(只读)
  • /proc/driver/nvidia
  • /sys/devices/pci0000:00
  • /sys/class/drm
  • /sys/module/nvidia*
动态扫描的文件

脚本会自动扫描并挂载以下文件:

  • /usr/bin/nvidia-* - NVIDIA 可执行文件
  • /usr/bin/nvcc* - CUDA 编译器
  • /usr/bin/nsight* - NVIDIA 分析工具
  • /usr/lib/x86_64-linux-gnu/libnvidia* - NVIDIA 库文件
  • /usr/lib/x86_64-linux-gnu/libcuda* - CUDA 库文件

虽然会挂载宿主的 CUDA 工具包和库文件,但容器内最好还是另外安装一套 CUDA。驱动是前向兼容 CUDA 的,因此容器内的 CUDA 版本可以低于宿主机的驱动版本,按照个人需求决定CUDA版本即可1。

派生配置(自动计算)

以下变量由脚本自动计算,无需手动配置:

变量名 计算方式 示例值
NODE_ID_STR printf '%02d' $NODE_ID "15"
INAIS_HOSTNAME "IN$NODE_ID_STR" "IN15"
RINETD_CONFIG /var/run/rinetd.conf.$CONTAINER_NAME /var/run/rinetd.conf.inais
RINETD_PID /var/run/rinetd.pid.$CONTAINER_NAME /var/run/rinetd.pid.inais

配置文件示例

#!/bin/bash

# === 必需配置 ===
export INAIS_HOST_ACCOUNT="Kenvix"
export NODE_ID=15
export CONTAINER_NAME="inais"
export CONTAINER_ROOT="/var/lib/machines/$CONTAINER_NAME"
export CONTAINER_INDEX=0
export INAIS_NETWORK_MODE="docker"  # docker 或 veth
export USE_RINETD_PORT_FORWARDING=false

# === 可选配置 ===
# 节点范围配置
export MAX_NODE_ID=21

# 禁用本地存储挂载
export DISABLE_LOCAL_STORAGE_BINDINGS=false

# 禁用 NVIDIA 挂载(无 GPU 环境设为 true)
#export DISABLE_NVIDIA_BINDINGS=true

# 存储路径前缀配置
export LOCAL_DATA_PREFIX="/data"              # 本地数据目录前缀
export NFS_STORAGE_PREFIX="/storagenfs/nfs"   # NFS 存储路径前缀

# 端口映射配置
export PORT_FORWARD_HOST_START=30600
export PORT_FORWARD_CONTAINER_START=30000
export PORT_FORWARD_COUNT=20

脚本信号支持

信号 行为
SIGHUP 立即重新执行监控检查。脚本会作为一个 Daemon 监控容器的状态。
SIGTERM SIGINT 优雅退出(停止容器后退出)

ℹ️ 注意:该脚本是为多服务器集群设计的,因此假设你有很多服务器需要配置相同的环境。如果你只是单机使用,可以忽略脚本中的集群相关配置,或者直接设置数量为1。

ℹ️ 提示:虽然已经稳定运行一段时间,但此脚本的 Vibe coding 成分较高,请自行进行代码审查,如果存在漏洞请告知我。

赋予可执行权限:

chmod +x run.sh
chmod +x config-run.sh

通过下面的命令,测试启动一级容器:

./run.sh daemon
sleep 2s
tmux attach -t inais
nvidia-smi

如果看到 GPU 信息,说明一级容器的 NVIDIA GPU 透传配置成功。此时可以创建一个 systemd 服务,实现在系统启动时自动启动一级容器:

[Unit]
Description=Run Kenvix Dev Containe at boot
Documentation=Kenvix Dev Container monitoring and management daemon
After=network.target docker.service systemd-machined.service systemd-resolved.service modprobe@tun.service modprobe@loop.service modprobe@dm-mod.service
Wants=network.target systemd-machined.service
Requires=docker.service systemd-machined.service

[Service]
Type=simple
ExecStart=/var/lib/machines/_Scripts/run.sh daemon
ExecReload=/bin/kill -HUP $MAINPID
ExecStop=/bin/kill -TERM $MAINPID
Restart=on-failure
RestartSec=50
StartLimitInterval=100

[Install]
WantedBy=multi-user.target

保存为 /etc/systemd/system/kenvix-container.service ,然后启用并启动:

sudo systemctl daemon-reload
sudo systemctl enable --now kenvix-container.service

通过下面的命令进入一级容器 Shell:

machinectl shell inais

此时可以在容器内配置 SSH 等常用服务。

二级容器环境配置

二级容器指的是在 systemd-nspawn 容器内运行的 Docker 或 Podman 容器。类似于 DinD(Docker in Docker)或 PinD(Podman in Docker/Podman in Podman),只不过我们这里的一级容器是 systemd-nspawn 容器。

同样的,对于二级容器,切勿使用带有 GPU 驱动的镜像,也不要在容器内安装 GPU 驱动!容器内只应该安装 CUDA 工具包和相关库,GPU 驱动由一级容器通过 CDI 注入。

二级容器 Docker 支持配置

通过 Docker 官方安装最新版本的 Docker-CE 引擎(具体可参见官方文档)。不要使用从 Ubuntu 官方源安装的 docker,否则缺少 CDI 支持将无法使用 GPU:

sudo apt update
sudo apt install ca-certificates curl
sudo install -m 0755 -d /etc/apt/keyrings
sudo curl -fsSL https://download.docker.com/linux/ubuntu/gpg -o /etc/apt/keyrings/docker.asc
sudo chmod a+r /etc/apt/keyrings/docker.asc

# Add the repository to Apt sources:
sudo tee /etc/apt/sources.list.d/docker.sources <<EOF
Types: deb
URIs: https://download.docker.com/linux/ubuntu
Suites: $(. /etc/os-release && echo "${UBUNTU_CODENAME:-$VERSION_CODENAME}")
Components: stable
Signed-By: /etc/apt/keyrings/docker.asc
EOF

sudo apt update
sudo apt install docker-ce docker-ce-cli containerd.io docker-buildx-plugin docker-compose-plugin

使用 Docker 时,只支持 CDI(Container Device Interface) 方式的GPU驱动注入,因此不能用 Docker 旧版的 --gpus all 参数,需改参数为 --device nvidia.com/gpu=all 即可。

# 例如原命令为
docker run --rm -it --gpus all nvidia/cuda:12.3.1-base-ubuntu22.04 bash
# 则须改为
docker run --rm -it --device nvidia.com/gpu=all nvidia/cuda:12.3.1-base-ubuntu22.04 bash

然后,在二级容器内使用 nvidia-smi 查看 GPU 信息。

二级容器 Podman 支持配置

对于 Ubuntu 22.04,官方源的 Podman 版本非常陈旧,Podman 3 不支持 CDI 方式的GPU驱动注入,文件系统支持也有问题,需要从 OpenSUSE 源安装较新版本的 Podman 4+(或自行编译最新版本):

ubuntu_version='22.04'
key_url="https://download.opensuse.org/repositories/devel:/kubic:/libcontainers:/unstable/xUbuntu_${ubuntu_version}/Release.key"
sources_url="https://download.opensuse.org/repositories/devel:/kubic:/libcontainers:/unstable/xUbuntu_${ubuntu_version}"

echo "deb $sources_url/ /" | tee /etc/apt/sources.list.d/devel:kubic:libcontainers:unstable.list
curl -fsSL $key_url | gpg --dearmor | tee /etc/apt/trusted.gpg.d/devel_kubic_libcontainers_unstable.gpg > /dev/null
apt update
apt install podman
nvidia-ctk cdi generate --output=/etc/cdi/nvidia.yaml

安装后,需配置使用 cgroupfs,编辑 /etc/containers/containers.conf

[containers]
cgroup_manager = "cgroupfs"
[engine]
cgroup_manager = "cgroupfs"

编辑 /etc/subuid/etc/subgid ,为需要运行 Podman 的用户分配子 UID/GID 范围,例如:

kenvix:100000:65536

然后,切换到此用户,通过以下命令测试:

# 注意:不能使用 Root 用户运行 Podman GPU 容器!请先切换到非 Root 普通用户
podman run --rm -it --device nvidia.com/gpu=all nvidia/cuda:12.3.1-base-ubuntu22.04 bash

然后,在二级容器内使用 nvidia-smi 查看 GPU 信息。

常见问题

强烈建议也阅读完本章节!在实际使用中几乎必然遇到下面的问题

宿主机 GPU 驱动更新后,一级容器正常但二级容器无法启动

这是由于 CDI 描述文件未更新所致。请运行下面的脚本,自动在 systemd 的开机早期阶段生成 NVIDIA CDI 描述文件。

sudo tee /etc/systemd/system/nvidia-cdi-generate.service >/dev/null <<'EOF'
[Unit]
Description=Generate NVIDIA CDI specification early
Documentation=https://docs.nvidia.com/datacenter/cloud-native/container-toolkit/
DefaultDependencies=no
Before=docker.service podman.service containerd.service crio.service
After=local-fs.target systemd-udev-settle.service
ConditionPathExists=/proc/driver/nvidia/version

[Service]
Type=oneshot
ExecStartPre=/usr/bin/mkdir -p /etc/cdi
ExecStart=/usr/bin/nvidia-ctk cdi generate --output=/etc/cdi/nvidia.yaml
RemainAfterExit=yes

[Install]
WantedBy=sysinit.target
EOF
sudo systemctl daemon-reload
sudo systemctl enable --now nvidia-cdi-generate.service

此脚本在一级容器运行。

Root 用户无法使用 Podman GPU 容器

此问题尚未解决,目前的解决方案是:

  • Root 用户一律使用 Docker 运行 GPU 容器。
  • 使用非 Root 用户运行 Podman 容器。

为何一级容器选择冷门的 systemd-nspawn 而不是更流行的其他虚拟化?

  • Docker/Podman:不支持 systemd,而且 Docker 是应用级别的容器,而非系统级别容器!Docker 设计用来运行单个应用服务,不适合用作完整的操作系统环境。强行使用 Docker 会遇到相当多麻烦事和效率问题。虽然运行 NVIDIA GPU 是简单了,但失去了系统级容器的优势。
  • LXC/LXD:LXC/LXD 一样对 GPU 支持不佳,不支持 CDI 方式的驱动注入。而且不支持 systemd。

为何一级容器使用 Ubuntu 24.04 时,二级容器无法使用?

这是一个已知问题,Ubuntu 24.04 作为一级容器操作系统时,Cgroup 存在兼容性问题,导致无法正确创建 Docker 所需的命名空间。目前解决方案仍在探索中,建议暂时使用 Ubuntu 22.04 作为一级容器操作系统。

为何二级容器试图加载不存在的旧显卡驱动?

  • 如果之前在一级容器安装过驱动,确保一级容器已经完全卸载了任何显卡驱动。可以临时设置一级容器的启动参数禁用显卡驱动绑定来卸载驱动。(启用绑定时,无法卸载驱动,会导致 apt 直接出错)
  • 确保二级容器使用的镜像也不包含任何显卡驱动
  • 确保二级容器使用的是 CDI 文件已更新(命令见上方)

有没有你直接配好的镜像?

有的,你可以在评论区催一下我发布