絮絮叨叨一筐废话

在用了几年 archlinux 后,我开始觉得有些厌倦。可能是年纪变大了。我开始觉得,每天花不少时间滚动更新系统,就像是绝症患者定时吃药续命一样,一定是哪里出了什么问题。

诚然,arch 是个令人舒适的发行版,可惜和我的理念有些不和了。

Arch 更像是发行版的发行版,一堆预制原料,你需要自己组装成自己需要的发行版。做一个属于自己的发行版,听起来很浪漫,但这也意味着你需要自己打磨自己的操作系统。

有时,一些软件包组合可能相性不符。举例来说,我曾经遇到过在更新 kernal 的时候磁盘爆满的问题。这并不是因为我没有打开 pacman 的 CheckSpace 功能,而是因为很不巧,我的文件系统是开了定时快照的 btrfs ,pacman 检查磁盘返回的不是真实的磁盘余量。总之,在桌面卡住前我完全没有意识到发生了什么。最后只好搞了个 LiveCD 挂上磁盘修复依赖和引导。

有时,一些软件包更新得过于激进。举例来说,最近的一次更新用 wireplumber 替代了 pipewire-media-session ,结果导致 PulseAudio 和单用 ALSA 的用户的音频坏了(链接)。毕竟软件包组合千千万万,手动测试也不可能面面俱到。这样的问题修复很快,但是更新完后那一段时间里会很糟心。

此外,在设计哲学上,我觉得像显示软件包特殊变更新闻这样的功能细节应该属于包管理器的一部分。不一定要写到包管理器中,但要有可选项,譬如以可选依赖包的方式提供。但在 arch ,这也是需要你自己打磨的部分。你可以订阅新闻源手动查看;或者是写脚本去自动订阅;亦或是再包装甚至实现一个新的前端。总之,你需要自己打磨。他们做到了软件开发的 KISS ,没有做到人机交互的 KISS 。但是如果你把 arch 当作发行版的发行版,这么做的逻辑是可以理解的。只是我,一个精疲力竭的打工仔,现在只想用一个别人打磨好的系统。

抱着对滚动发行版的执念,在收购了一台新的松下洋垃圾后,我尝试了一下 openSUSE Tumbleweed (喜提轴心国全家桶套餐)

尝试 openSUSE Tumbleweed 是因为它是一个滚动更新的发行版(或者说发布周期以天计算的类传统发行版?);同时它的包管理器能够处理跨版本升级的依赖问题,可以心安理得个把月不滚系统;还有一套开箱即用支持从 grub 回滚的 btrfs 快照机制;再有至少它有个 openQA 系统不是?以及我真的好喜欢 KDE 。

然而使用几个月后,我对 Tumbleweed 的使用体验并不完全满意。Tumbleweed 的软件包数量和部分部分软件包质量有些令人扫兴。譬如没有一些我常用的软件包;部分软件包存在但过旧并缺乏维护;更新经常会遇到默认移除一些软件的情况,如移除了 FreeCAD;奇怪的依赖问题,如 fcitx5 竟然能一路依赖到 fcitx 然后提示文件冲突;默认编译选项问题导致库里的 cross-xxx-gcc 交叉编译出来的内容不符合预期……

我一开始选择的解决方法是使用官方的 OBS 实例来自己打包,编写 SPEC 文件后,缺失或者有细微问题的软件包可以通过公共的 Open Build Service 服务器打包并放入独立的源中,真是帅呆了。就这样用了一段时间后,我发觉我的 RSS 订阅从 arch recent news 变成了各软件的更新新闻源,(觉得好像上当了) 就像是从一个坑跳进了另一个坑。

于是我意识到,滚动发行版必然存在这样的弊病——维护者的精力会被频繁的更新所稀释,让系统整体上看起来并不精致,露出些小毛病来。

所以我到底想要什么?我期望系统足够稳定的同时软件包既新又丰富。这在现实中必然会有冲突,很多时候只能在这两者间妥协。

想要在保证系统稳定可控的同时享有丰富而紧跟上游的软件?快用 Windows 或 macOS

幸运的是,我们有 Linux 容器可以用。

缝合手法介绍

这个方案大致的思路就是通过拉取所需系统的镜像建立一个特别的容器,然后使它与主机互通网络、设备、图形接口、home 目录等等。这样,在容器内安装的软件可以在主机无缝使用,同时又不搞乱主机系统文件。

建立这样一个特别的容器需要好多操作,幸运的是已经有人把指令包装好了。这里将介绍的是 distrobox 方案。

首先,一切的一切,你需要一个容器运行时。可选的有 Docker 社区版和 Podman 。我这里选择的是 Podman ,因为我不想开机就有 docker 守护进程在后台跳舞。对于大多数发行版,直接安装即可:

# apt install podman
# pacman -S podman
# zypper in podman
# dnf install podman
...

这样就能用了。如果是 arch 用户,安装完之后只有 root 能运行容器,你还需要按照 wiki 说明配置为 rootless 模式。

之后安装 distrobox 。目前只有 openSUSE 、Debian Sid 、Fedora 打了包 (哦哦,还有 AUR) 。这里以 openSUSE 为例:

# zypper in distrobox

如果你使用的发行版没有打包,那么需要按照 readme 里的说明手动安装。这里是个示例:

$ curl -s https://raw.githubusercontent.com/89luca89/distrobox/main/install | sudo sh

完成后,就能直接创建我们想要的发行版容器了。我这里选择了 archlinux ,因为作为一个社区驱动的发行版,我就没见过不能在 arch 上跑的软件。

$ distrobox create --name arch --image archlinux

执行这一步操作,distrobox 会从 docker hub 上拉取 archlinux:latest 镜像,然后创建对应的容器,并命名为 arch 。执行成功后会输出下一步操作的指令:

$ distrobox enter arch

这一步完成后对应的终端就会显示容器里的命令行输出了。不过事情通常不会那么简单…… distrobox enter 的操作会自动执行系统更新的命令,而镜像内默认的软件源很可能在地球的另一端之类,这一步将会进行得相当缓慢。最简单的处理方法是 泡杯茶硬等 挂代理,如果手上没有趁手的互联网直通车的话你可以提前进入容器内修改软件源列表。

$ podman start arch
$ podman exec -it arch bash

这里的 arch 是别名,也可以用执行 distrobox list 后列出来的那个 ID 。进入容器后还有另一个问题,这类镜像通常极为精简,所以压根就没有编辑器供你使用。所以你可能得把软件源列表文件删了然后用 echo 大法:

sudo echo "Server = https://mirrors.tuna.tsinghua.edu.cn/archlinux/\$repo/os/\$arch" >> /etc/pacman.d/mirrorlist

或者 sed 替换大法之类……总之想办法更新软件源列表,然后再执行 distrobox stop archdistrobox enter arch

顺利的话,你已经进入一个可以为所欲为的容器了。你可以装任何你想装的软件,然后直接从命令行唤出,就像这本来就是主机系统一样。你也可以直接导出各种启动方式到主机,譬如导出到 desktop 文件:

$ distrobox-export --app software_name

然后在桌面启动器里就能看到启动图标了。要注意,导出命令是在容器内执行的。

日常维护

好了,这下我们兜兜转转又跑起了 arch ,这不是又回到了天天滚系统的日子?

其实并不需要。首先,容器里的软件包不会太多,系统依赖关系更简单,不容易挂。其次,我们想要的只是打包好的软件包而已,所以并不需要担心系统滚挂的问题。就算挂了又如何,删了重建就是了。我们只需要导出软件列表:

$ pacman -Qqe > pkglist.txt

当然还有 AUR 等外部来源的软件包列表:

$ pacman -Qqem > foreignpkglist.txt

如果真滚出麻烦,照着列表再装一遍就是。

此外,容器可以不止一个。你完全可以把特殊的软件隔离开,只是多占点磁盘空间罢了。用 Linux 这些年,没少装奇奇怪怪的软件,经常把系统搞到脏兮兮的。放到容器里装,就像垫上一张餐桌布一样。不过需要注意的是,默认情况下,你的 home 目录也是暴露给容器内的。

可能出现的问题及解决方法

1.添加 archlinuxcn 源后导入 GPG keyring 报错。

执行以下操作:

sudo rm -rf /etc/pacman.d/gnupg
sudo pacman-key --init
sudo pacman-key --populate

然后安装 keyring:

sudo pacman -Sy archlinuxcn-keyring

2.使用 AUR helper (yay, paru …) 时显示 ==> ERROR: Cannot find the strip binary required for object file stripping.

安装 binutils 即可:

sudo pacman -S binutils

以此为原型的发行版

发散一下思维,能不能让所有软件都安装在容器里?

当然可以。甚至还能更进一步,让主机系统的绝大部分变成只读,让系统变得绝对稳定可靠,可以各版本间自由来回滚动。

现在较为知名的桌面方案是 Fedora Silverblue 以及 openSUSE MicroOS ,还有 Fedora IoT 作为 Official Edition 推出。

在任意 Linux 发行版安装 ROS

这是额外的独立章节,介绍在任意发行版上安装对发行版有特殊限定的软件包/软件集。以机器人操作系统为例,提供给有需要的人。毕竟咱曾经用 ROS 骗过大创经费

方案一

首先使用包管理器安装 Podman 和 distrobox 。若没有提供 distrobox ,按照此链接说明安装。

完成后,开始创建安装 ROS 所需的容器。我这里选择 Ubuntu 22.04 LTS (ROS 官方品质之选,毕竟支持时间长)以及 ROS2 Humble Hawksbill 。

首先拉取 Ubuntu 22.04 LTS 镜像,并创建容器:

$ distrobox -n ros2.humble -i ubuntu:22.04

完成后进入容器命令行环境:

$ distrobox enter ros2.humble

第一次进入需要一些时间,但通常不会很慢。默认使用官方的源大概有 CDN ,金钱的力量 你可以通过 podman logs -f ros2.humble 查看具体输出。

进入后第一步,先顺手再更新一下系统:

$ sudo apt update
$ sudo apt upgrade

然后按照 ROS 官方文档添加软件源。因为语言环境通常默认是 UTF-8,universe 储存库默认也已添加,我们就跳过这两步。首先下载添加 ROS 官方的 GPG key :

$ sudo apt install curl gnupg gnupg2 lsb-release
$ sudo curl -sSL https://raw.githubusercontent.com/ros/rosdistro/master/ros.key -o /usr/share/keyrings/ros-archive-keyring.gpg

然后添加官方软件源列表:

$ echo "deb [arch=$(dpkg --print-architecture) signed-by=/usr/share/keyrings/ros-archive-keyring.gpg] http://packages.ros.org/ros2/ub
untu $(source /etc/os-release && echo $UBUNTU_CODENAME) main" | sudo tee /etc/apt/sources.list.d/ros2.list > /dev/null

我这里使用的是 tuna 的镜像源:

$ echo "deb [arch=$(dpkg --print-architecture) signed-by=/usr/share/keyrings/ros-archive-keyring.gpg] https://mirrors.tuna.tsinghua.e
du.cn/ros2/ubuntu jammy main" | sudo tee /etc/apt/sources.list.d/ros2.list > /dev/null

然后就可以开始安装 ROS 的软件包了。先更新本地源:

$ sudo apt update

然后直接安装 ROS 完整桌面软件集:

$ sudo apt install ros-humble-desktop

Apt 会自动处理依赖。你需要准备 3~4G 的磁盘空间,然后等待安装完毕。

完成后,配置一下环境,就可以使用了。

方案二

实际上 docker hub 上有现成的 ROS 镜像可供使用,由 OSRF 直接维护。你直接拉取下来就行:

$ podman pull osrf/ros:humble-desktop-full-jammy

冒号后的标签你可以自由选择。

方案三

有没有可以远程的方案?

有的。请看这个。你可以通过浏览器远程访问容器内的桌面,然后像处理虚拟机一样处理容器实例,但磁盘占用和性能损失比虚拟机方案小很多。