外观
在容器里使用核显(转码场景)
Plex、Jellyfin、Immich 这类服务用核显做硬件转码时,容器比虚拟机更划算——不需要把整块显卡从宿主机剥离,多个容器还能共享同一块核显。这篇讲怎么把核显的设备节点映射进容器。
为什么需要它,以及它和 PCI 直通的区别
硬件直通讲的是把一个 PCI 设备整个从宿主机剥离,交给一台虚拟机独占——LXC 容器不支持 PCI 直通,这是容器和虚拟机在隔离机制上的根本差异(见容器还是虚拟机)。
核显转码不需要整卡直通。核显在 Linux 下表现为 /dev/dri/ 目录下的几个设备节点(renderD128、card0 等),只要把这几个设备节点映射进容器,容器内的进程就能像访问普通设备一样使用核显,宿主机仍然完整持有这块显卡,可以给多个容器同时用。
开始之前
- 宿主机上核显驱动已经装好,
/dev/dri/下能看到设备节点:
sh
# 在宿主机 shell 执行
ls -l /dev/dri/正常应该能看到类似 card0、renderD128 这样的条目,以及它们的属组和 GID:
text
crw-rw---- 1 root video 226, 0 ... card0
crw-rw---- 1 root render 226, 128 ... renderD128- 明确只需要转码的话,通常只需要
renderD128(render 节点),不一定需要card0。 - 核显的硬件转码能力和并发路数受具体型号限制,这个不在 PVE 的控制范围内,规划前查你的核显型号支持多少路硬件转码。
操作步骤
第一步:确认宿主机侧的设备节点和 GID
sh
# 在宿主机 shell 执行
ls -l /dev/dri/记下 renderD128(和需要的话 card0)所属的组名和 GID。
第二步:用 dev[n] 选项映射进容器(推荐做法)
PVE 提供了 dev[n] 这个配置项专门做设备直通,同时处理好 cgroup 权限和挂载,不需要手动写底层 cgroup 规则:
sh
# 在宿主机 shell 执行
pct set <ctid> -dev0 /dev/dri/renderD128,gid=<容器内 render 组的 GID>Web UI 等效路径:容器 → Resources → Add → Device Passthrough。
dev[n] 支持的参数:
| 参数 | 作用 |
|---|---|
path | 要映射的设备路径 |
gid | 设备节点在容器内的属组 GID |
uid | 设备节点在容器内的属主 UID |
mode | 设备节点的访问权限(八进制) |
deny-write | 禁止容器写入这个设备 |
gid 该填哪边的数字
官方 pct.conf 文档只说明 gid 是"赋给设备节点的组 ID",没有明确这个数字是宿主机侧还是容器侧的视角。实践中更常见的做法是填容器内 render 组的 GID(进容器用 getent group render 查),而不是宿主机上的 GID。如果按容器内 GID 填了权限还是不对,两个数值都试一下,以你的版本实测为准。
先查容器内的 render 组 GID:
sh
# 在容器内部执行(如果容器内还没有 render 组,先跳过,装转码相关软件包时通常会自动创建)
getent group render第三步:需要完整设备节点时追加 card0
某些应用除了 render 节点还需要 card0:
sh
# 在宿主机 shell 执行
pct set <ctid> -dev1 /dev/dri/card0,gid=<容器内 video 组的 GID>第四步:重启容器
sh
# 在宿主机 shell 执行
pct restart <ctid>特权与非特权容器的差异
dev[n] 这套机制非特权容器和特权容器都能用,这也是它比早期手动方案更友好的地方——早期做法需要手动写 lxc.cgroup2.devices.allow 规则并配合 lxc.mount.entry 做 bind mount,在非特权容器下还要处理 UID/GID 映射,配置门槛高很多。
遇到权限问题不要改成特权容器
核显权限映射不对是常见现象,正确的排查方向是核对 gid/uid/mode 这几个参数是否匹配容器内实际的组和权限,而不是把容器整个改成特权容器来"绕开"权限检查。特权容器是完全不同量级的风险(见特权与非特权容器),核显转码这个场景不构成使用它的理由。
检查结果
- 容器内能看到设备节点:
sh
# 在容器内部执行
ls -l /dev/dri/- 装了
vainfo(VA-API 测试工具)的话,确认能查询到转码能力:
sh
# 在容器内部执行
apt install -y vainfo
vainfo能列出编解码 profile,说明容器内的应用已经能通过 VA-API 使用这块核显。
- 在实际应用(Jellyfin/Plex 等)里跑一次真实的转码任务,确认 CPU 占用明显低于纯软件转码,同时能在系统监控里看到核显有负载——这是最终验收标准,前两步只能确认设备可见,不能确认应用真的用上了硬件加速。
常见问题
容器内 /dev/dri 是空的。 检查宿主机侧驱动是否正常(ls -l /dev/dri/ 在宿主机上应该已经有输出),再检查 pct config <ctid> 里是否有对应的 dev0/dev1 行,改完配置记得重启容器。
设备节点看得到,但应用报权限不足。 大概率是 gid/mode 没对上容器内应用实际运行时所在的组,回到「第二步」重新核对容器内 render/video 组的 GID。
多个容器同时转码,效果变差或失败。 核显的硬件编解码单元数量有限,具体能撑几路并发和型号强相关,PVE 这一层不负责这个限制,遇到瓶颈需要评估是否要专门给某个容器提高优先级,或者改用独立显卡直通给虚拟机。
我用的是独立显卡(比如 NVIDIA),不是核显。 独显的驱动模型和权限方式与核显不同,通常需要专门的驱动和不同的挂载方式,且如果这块显卡同时要给虚拟机做 PCI 直通,就不能再共享给容器用。这不在本文范围内,独显走虚拟机直通见硬件直通。