Install Void Linux on Raspberry Pi
简介
Void Linux 是一款相对小众的 Linux 发行版
其主要的特点如下
- 独立构建, Void Linux 不基于已有的发行版修改, 有自己的一套包管理系统: xbps
- 滚动发行, 更新内容会持续推送到系统中, 没有需要重新安装的大版本更新
- 不使用 Systemd, 使用 runit 作为系统初始化与服务管理程序
- 支持多种 C 标准库:Void Linux 同时支持 glibc 和 musl 两种实现,可根据需要选择
选择的理由
在上一次的文章中, 我在 Rpi Zero 2W 中使用 Garage 替代 Minio, 同时用 Podman 替代了 Docker, 将系统的内存使用量从 300+ MiB, 缩减到了 100+ MiB
此时系统的另一大内存消耗的地方便落到了 Systemd 上, 我期望找到一个不使用 Systemd 的精简发行版, 同时希望它对于 Rpi 有良好的支持
比较后我发现,只有 Alpine Linux 和 Void Linux 满足需求,而 Void Linux 的安装过程对我而言更加简单
安装过程
设置分区
Void Linux 的 Arm Platform 下载页面提供了树莓派 aarch64 的两种下载包
- platform image 也就是系统镜像, 包含了磁盘分区内容
- rootfs tarball 只包含了系统文件, 可以自定义分区与文件系统
我选择的是 rootfs tarball, 采用与 Arch Linux Arm 相同的分区方案
分区 | 大小 | 文件系统 | 说明 |
---|---|---|---|
/dev/mmcblk0p1 | 512MiB | vfat | 挂载 boot 分区 |
/dev/mmcblk0p2 | 剩余磁盘空间 | ext4 | 挂载 / 分区 |
而后使用 bsdtar
将下载的压缩包解压到 sd 卡中
修改启动内容
而后修改启动内容, 共有两处
在 /boot/config.txt
底部增加配置
...
[all]
dtoverlay=dwc2
gpu_mem=16
修改 /boot/cmdline.txt
的启动命令
root=/dev/mmcblk0p2 rw rootwait modules-load=dwc2,g_ether,ip_tables,iptable_nat g_ether.host_addr=ca:9d:fb:09:5a:62 g_ether.dev_addr=d6:b1:ca:33:f0:2d cgroup_enable=cpuset cgroup_enable=memory cgroup_memory=1 console=serial0,115200 console=tty1 fsck.repair=yes dwc_otg.lpm_enable=0 elevator=noop
之后就可以插入树莓派并启动, 使用 root
用户名和 voidlinux
作为密码登陆
系统基本配置
增加普通用户
在 Void Linux 中, 默认只有 root 用户, 我们要添加一个普通用户作为我们日常使用的账户
# 添加名为 xxl 的组,GID 为 1000
groupadd -g 1000 xxl
# 添加名为 xxl 的用户,UID 为 1000,主组为 xxl,创建主目录,shell 为 /bin/bash
useradd -u 1000 -g 1000 -m -s /bin/bash xxl
# 设置密码
passwd xxl
# 将 xxl 增加至 wheel 组, 而后修改 /etc/sudoers, 让 wheel 组可以执行 sudo 指令
usermod -aG wheel xxl
设置时区
sudo ln -sf /usr/share/zoneinfo/Asia/Shanghai /etc/localtime
更换镜像源与系统更新
根据清华源的帮助文档
执行以下步骤
mkdir -p /etc/xbps.d
cp /usr/share/xbps.d/*-repository-*.conf /etc/xbps.d/
sed -i 's|https://repo-default.voidlinux.org|https://mirrors.tuna.tsinghua.edu.cn/voidlinux|g' /etc/xbps.d/*-repository-*.conf
使用 xbps-install -Syu
更新系统
安装系统日志
Void Linux 默认安装后不会带有 syslog 组件, 需要自行安装
# 安装 socklog-void 作为 syslog 的实现
xbps-install socklog-void
# 设置为开机启动
ln -s /etc/sv/socklog-unix /var/service/
ln -s /etc/sv/nanoklogd /var/service/
安装 Podman
使用 xbps-install podman podman-compose
安装软件包
并修改 /etc/subuid
和 /etc/subgid
的内容, 两个文件内容相同
xxl:100000:65536
启动 Podman 后可能遇到以下问题
WARN[0000] "/" is not a shared mount, this could cause issues or missing mounts with rootless containers
这表明根文件系统 / 不是一个 "shared mount",非 root 用户使用容器时可能会出现 volume 不可见、bind mount 不生效等奇怪的问题。
需要修改 /etc/rc.local
, 将以下内容添加到文件末尾
mount --make-rshared /
可以通过 findmnt -o TARGET,PROPAGATION /
检查是否生效
runit 设置
添加用户级别运行服务
完成上述配置后, Podman 就已经可以使用了, 但还需要让 Podman 在系统重启时, 自动启动相关的 rootless 容器
在有 Systemd 的系统中, 可以使用以下的命令, 启动一个用户级的 Podman 重启服务
systemctl --user enable podman-restart.service
在 runit 中, 我们也需要实现类似的逻辑
按照官方文档中的示例, 我们可以创建 /etc/sv/runsvdir-xxl
目录
在其中添加 run
文件, 并写入以下内容
#!/bin/sh
export USER="xxl"
export HOME="/home/xxl"
groups="$(id -Gn "$USER" | tr ' ' ':')"
svdir="$HOME/.service"
# 此条命令用于检测 chronyc 是否同步
# 为防止出现时间显示错误, 仅在同步完成后才执行后续逻辑
# 也可酌情去掉, 不影响服务启动
chronyc tracking | grep -q "Leap status *: Normal" || exit 1
exec chpst -u "$USER:$groups" runsvdir "$svdir"
我们声明了一个系统级服务, 用于启动用户级别的服务
runit 原生没有启动顺序的配置, 如果需要一个服务在另一个服务后运行, 只能在服务启动时自行判断, 如果依赖服务未启动, 则 exit 1
退出, 这样 runit 会自动重试
随后我们创建 ~/.service
和 ~/.sv
两个文件夹
其中, ~/.service
是软链接运行目录, 而 ~/.sv
是服务仓库
添加 podman-restart
在 ~/.sv
添加 podman-restart
文件夹, 并添加 run
脚本
#!/bin/sh
exec 2>&1
[ -r ./conf ] && . ./conf
podman ${LOGGING} start --all --filter restart-policy=always || exit 1
exec chpst -b podman-restart pause
其中 exec
命令是待执行的 Daemon 进程, 由于重启为一次性任务, 实际执行 pause 命令,该命令会使进程无限阻塞,从而保持服务状态不退出, 并将其名字改为 podman-restart
, 否则进程退出后, runit 还会反复重试, 造成不必要的资源浪费
conf
文件内容
LOGGING="--log-level=info"
随后增加 log
文件夹, 并加入 run
脚本, 用于记录该进程的日志
#!/bin/sh
exec svlogd -tt ./main
完整的服务文件夹结构
.sv/podman-restart/
├── conf
├── log
│ └── run
└── run
最后启动 podman-restart
服务和 runsvdir-xxl
服务
# 为 run 脚本增加执行权限
sudo chmod +x /etc/sv/runsvdir-xxl/run
chmod +x ~/.sv/podman-restart/{run,log/run}
cd ~/.service
ln -s ../.sv/podman-restart .
sudo ln -s /etc/sv/runsvdir-xxl /var/service/
最终效果
在安装 Void Linux 系统后, 系统启动后无而外服务情况下, 内存消耗仅 60+ MiB, 增加 Garage 服务后, 也仅消耗 90+ MiB 内存