在有一段时间里我因为不同发行版环境问题而头疼,无论是开发、还是日常使用。编译时遇到 glibc、各种各样库版本不同等问题,那个发行版有二进制包呀这个发行版没有的。
尝试过 chroot (觉得不太得劲),又去研究 bwrap (据说 flatpak 也在用的方案) 跑了 debian 和 Arch 容器, https://blog.glumi.cn/bwrap-debian ,https://blog.glumi.cn/bwrap-arch 。但因为工具又太过于轻量,用起来比较麻烦。最近又尝试了另一种陌生的方案,也就是 systemd-nspawn
那这又是个什么东西呢,可以简单理解为同时兼顾 chroot 的易用性又有 bwrap 的灵活性且与 systemd 深度集成的容器工具。
它既可以作为轻量级的隔离环境快速启动,满足临时测试需求;又能支撑起完整的系统容器,跑起一整套带服务的发行版环境,甚至可以在上面运行 GUI 程序,且带硬件加速,还几乎没有明显的性能损失。(硬件直通,共享宿主机的图形接口资源实现显示输出)
在开始前,以 Debian 系为例。需要安装 systemd-container 包获得相关工具。
sudo apt install systemd-container
接下来准备一个 rootfs ,(Arch 的话可以使用 pacstrap,这里我就不展开了) 这里以 Debian 为示例,可以使用 debootstrap
来下载一个 debian rootfs
sudo debootstrap --arch amd64 sid /path/to/debian/ https://deb.debian.org/debian
其中 sid 为 unstable,也可以换成 bookworm 等版本代号。amd64 就是相当于 x86_64,可以是其他架构。
systemd-nspawn 可以像 chroot 一样简单
其中 -D 代表 --directory 参数简写。
sudo systemd-nspawn -D rootfs
它默认会做一些基础的配置,能够直接使用宿主网络,且以 root 用户为起始。
如果你需要从普通用户启动,你需要提前在容器内做好 useradd 相关操作。
sudo systemd-nspawn -D rootfs --user=用户名或UID
容器内使用 sudo 提权也是没问题的,也仅限于容器内的提权,不会涉及到外部权限。
回到本文标题,让我们跑 GUi 之前。我们可以再挂载以下内容。
参数较多,接下来为了排版直观,我编写一个 run.sh
文件为示例。
#!/bin/bash
container_path=./debian_bookworm
XAUTH=/tmp/container_xauth
DISPLAY=":1"
uid=1000
sudo systemd-nspawn \
--directory="$container_path" \
-E XAUTHORITY="$XAUTH" \
-E DISPLAY="$DISPLAY" \
-E XDG_RUNTIME_DIR="/run/user/$uid" \
-E LANG="zh_CN.UTF-8" \
-E PULSE_SERVER="unix:/run/user/$uid/pulse/native" \
--hostname="Debian12" \
--bind="$XAUTH" \
--bind="/dev/dri" \
--bind="/tmp/.X11-unix" \
--bind="/dev/input" \
--bind="/run/user/$uid/pulse" \
--bind="/run/user/$uid/bus" \
--user="$uid"
这里面涉及到很多内容,其中 --bind
为挂载的意思,为了跑起 GUi,我们需要告诉容器需要用到哪个显示器(DISPLAY) 使用 -E DISPLAY="$DISPLAY"
其中 -E
就是传递变量的意思,根据个人情况来写,我这里是 :1
然后挂载 --bind="/tmp/.X11-unix"
让容器与宿主 X11 通信,而一般情况下 x 有个机制默认不允许非本机与 x 进行通信,而容器其实就相当于另一个主机。为了让它们建立连接,需要使用 xhost
去开放权限如:xhost +Debian12
其中 Debian12
为主机名 +
为添加白名单 -
为移除。但是一般不推荐这么做。我使用了另一种方法。也就是增加一个 XAUTHORITY
变量指向 /tmp/container_xauth
。
--hostname="Debian12"
:的意思很明了,就是给容器设置一个主机名
--bind="/dev/dri"
:将宿主 dri 挂载到容器以实现 GPU 加速
如果你需要音频,那必须得加入以下参数和 PulseAudio 进行通信:
--bind="/run/user/$uid/pulse"
-E PULSE_SERVER="unix:/run/user/$uid/pulse/native"
准备完后,使用 chmod +x run.sh
给以执行权限,就可以跑了。以下为测试效果。
资源占用还不错(测试硬件 Ai9 365 )
关于更详细教程推荐阅读: