下面以向运行中的 LXC 容器注入 /dev/vhost-net 为例讲解。
有两种思路:临时注入(容器重启后失效)和永久配置(写入配置)。有时无法重启 lxc 容器,希望配置生效,就可以用临时注入热载入,在写入配置,这样现在就可以用,下次重启后载入配置就不用热载入了。下面介绍方法:
临时注入
(容器运行中,立即生效)
步骤 1:在宿主机上确认设备号
ls -l /dev/vhost-net
# crw-rw-rw- 1 root kvm 10, 238 ... /dev/vhost-net
主设备号通常是 10,次设备号常见为 238(以你机器输出为准)。
如果没有该设备,先加载模块:
modprobe vhost_net
步骤 2:在容器的 devices cgroup 中放行该设备
cgroup v1:
lxc-cgroup -n <容器名> devices.allow "c 10:238 rwm"
cgroup v2(现代发行版默认)没有 devices.allow 文件,设备控制基于 eBPF,lxc-cgroup 一般无法这样动态修改。此时建议改用下面的”永久配置 + 重启”。
步骤 3:在容器内创建设备节点
lxc-attach -n <容器名> -- mknod -m 666 /dev/vhost-net c 10 238
或直接去容器里执行后面的命令即可。
注意:如果是非特权容器,容器内
mknod通常会被拒绝(用户命名空间中没有CAP_MKNOD),此时需要用 bind mount 方式或永久配置。
替代:直接 bind mount 设备文件(不需要 mknod)
# 找到容器的 rootfs 路径后,在宿主机上创建目标文件并 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。)
永久配置
编辑 /var/lib/lxc/<容器名>/config(或 ~/.local/share/lxc/...):
# 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
然后重启容器。