制作自定义的 archlinux initramfs 与 rootfs
本文最后更新于 2024年3月30日 晚上
最近想做一个自定义的 archlinux pxe 启动环境,由于 pxe 走的 tftp, 因此希望 initramfs 尽量小,官方 iso 里面的 initramfs 带了一些 glibc 的动态链接库,因此体积还是比较大的。我打算基于 busybox 去做一个 initramfs, 尽量只包含 busybox 以及网卡驱动,其他一概不加,都放在 rootfs 里面。
最后所有脚本放在 Github 仓库
制作 initramfs
我并不打算从头写 init 脚本,而是尽量抄 mkinitcpio 的代码。首先我们尝试通过自制的 initramfs 引导 archiso 带的 rootfs.
先新建一个文件夹,将 archiso 的 initramfs 复制进去解压
1 |
|
看一下目录结构
1 |
|
这几乎就是一个正常根目录的结构,其中 init
就是启动脚本,内核在解压 initramfs 后会执行 init
. hooks/
文件夹是 archiso 的各种 hook, 通过 config
配置,自己写的变更就可以放在 hook
里面。
主要的命令和库都放在 usr/bin
和 usr/lib
下面。我们先把这两个文件夹清空(因为我们尽量只用 busybox
嘛)。
同样的,那些 hook,
然后将 busybox
安装到 usr/bin
1 |
|
再把 busybox
本体复制过去。
1 |
|
然后我们由于我们打算通过 http 传输 rootfs, 所以得加上网卡驱动。把内核自带的网卡驱动都复制到 usr/lib/modules
下面.
注意,这些驱动一定要是 .ko
格式(而不是 .ko.zst
, 因为两次压缩没有必要)
同时由于我们要挂载 squashfs
形式的 rootfs 还要挂载 overlayfs
, 因此也需要 squashfs
与 overlayfs
这两个模块。
另外,由于原来的 initramfs 使用了一些 glibc 的库和命令,它们与 busybox
的不一致,我们需要对脚本做一些修改以兼容 busybox
的命令, 比如 busybox
的 mount
没有 --mkdir
,同时我们将 curl
更换为 wget
。
而 losetup
我不会配置参数以达到和原来一样的效果,因此这个就直接用glibc
的 losetup
而不是 busybox
的了。我们需要将它以及它所依赖的动态库都一起复制过去,具体可以通过 lddtree
命令查看。这里 /usr/lib/libsmartcols.so.1
是一个软链接,所以我直接把 /usr/lib/libsmartcols.so*
都复制过去了。
1 |
|
由于我们使用的 busybox
和 原装 initramfs 的 busybox
不一致(我们使用的 busybox
会优先使用 busybox
applet, 而不是 PATH
中的命令),因此,在使用两者都有的命令时,需要使用绝对路径(例如 /usr/bin/losetup
).
另外我们加了一个 addmod
的 hook, 并且在 config 中先于其他 hook 执行以加载网卡(原来是在 udev
中执行的,但是我们把 udev
拿掉了)。
打包
linux 内核其实支持两种引导的格式,initrd 与 initramfs, 两者的区别可以看参考资料。我们使用如下的命令创建 initramfs。 其中 xz -1
是压缩程序及压缩等级,也可以调整成 zstd -19
.
1 |
|
启动
命令行启动的启动命令(方便查看日志调试)
1 |
|
启动的同时我们要保证启动了一个 http 服务,并确保http://192.168.122.1/arch/x86_64/airootfs.sfs
这个路径有效,这样我们就能顺利启动了。
制作 rootfs
airootfs.sfs
可以自己制作. ${ROOTFS_DIR}
是一个与 initramfs 无关的文件夹, 同时我们将 root
密码设置成了 root
1 |
|
接着使用如下的命令打包 squashfs
, 打包出来的文件就是 airootfs.sfs
1 |
|
暂未解决的问题
目前 losetup
和 ipconfig
还是用的动态链接的,尤其 ipconfig
是从源码编译的,后续可以看看如何用 busybox
的内置命令实现这两个功能,这样我们就完全不需要 glibc
的库了。(另一种方法是将 busybox
也换成动态链接的版本)