LXC 热载入设备文件
内容提要
LXC容器热载入设备文件时,先查宿主机设备号(如/dev/vhost-net为10:238)。临时注入可用lxc-cgroup放行设备,再在容器内mknod创建节点;非特权容器可能被拒,可改用bind mount。cgroup v2不支持动态放行,建议永久配置:在容器config中写入devices.allow和mount.entry,重启生效。
延伸解读
临时注入与永久配置的取舍
文章指出,临时注入适合无法重启容器的场景,能立即生效,但容器重启后失效。永久配置写入容器 config 文件后,重启容器即可自动生效。两者可结合:先临时注入让当前容器可用,再写入配置,下次重启后便无需手动操作。
cgroup v2 下的限制与应对
在 cgroup v2 环境中,设备控制基于 eBPF,没有 devices.allow 文件,lxc-cgroup 无法动态放行设备。文章建议此时放弃临时注入,改用永久配置并重启容器。若必须热载入,可考虑 bind mount 设备文件,但仍需 cgroup 放行,否则容器内访问会报 Operation not permitted。
非特权容器的 mknod 风险
非特权容器内执行 mknod 通常会被拒绝,因为用户命名空间中缺少 CAP_MKNOD 能力。文章给出的替代方案是 bind mount 设备文件,或直接使用永久配置。操作前需确认容器是否为特权模式,避免因权限不足导致注入失败。
Q&A
如何在运行中的LXC容器里临时添加一个设备文件?
以添加/dev/vhost-net为例:先在宿主机用ls -l /dev/vhost-net确认设备号(如10:238),然后使用lxc-cgroup -n <容器名> devices.allow "c 10:238 rwm"放行设备(仅cgroup v1支持),最后在容器内用lxc-attach -n <容器名> -- mknod -m 666 /dev/vhost-net c 10 238创建设备节点。
非特权LXC容器中mknod创建设备节点失败怎么办?
非特权容器中mknod通常会被拒绝,因为用户命名空间中没有CAP_MKNOD。此时可以改用bind mount方式:在宿主机上创建目标文件并挂载,例如touch /var/lib/lxc/<容器名>/rootfs/dev/vhost-net,然后mount --bind /dev/vhost-net /var/lib/lxc/<容器名>/rootfs/dev/vhost-net。同时还需要cgroup放行设备,否则容器内访问会得到Operation not permitted。
cgroup v2下如何为LXC容器动态放行设备?
cgroup v2不支持通过lxc-cgroup动态修改devices.allow,因为设备控制基于eBPF。建议改用永久配置:在容器config中写入lxc.cgroup2.devices.allow = c 10:238 rwm和lxc.mount.entry = /dev/vhost-net dev/vhost-net none bind,create=file 0 0,然后重启容器。
如何永久配置LXC容器使其自动加载设备文件?
编辑容器的配置文件(如/var/lib/lxc/<容器名>/config),添加设备放行和挂载条目:对于cgroup v1,添加lxc.cgroup.devices.allow = c 10:238 rwm;对于cgroup v2,添加lxc.cgroup2.devices.allow = c 10:238 rwm;同时添加lxc.mount.entry = /dev/vhost-net dev/vhost-net none bind,create=file 0 0。保存后重启容器即可生效。
LXC容器热载入设备文件时,如何确认设备的主次设备号?
在宿主机上使用ls -l /dev/vhost-net查看,输出中会显示主设备号和次设备号,例如10, 238。如果设备不存在,需要先加载内核模块,如modprobe vhost_net。
临时注入和永久配置LXC设备文件各有什么优缺点?
临时注入(使用lxc-cgroup和mknod)立即生效,但容器重启后失效,且仅适用于cgroup v1。永久配置(写入config文件)需要重启容器才能生效,但重启后自动加载,且支持cgroup v2。有时无法重启容器,可先临时注入再写入配置,这样当前可用,下次重启后配置生效。