前言:
Linux系统启动时使用initramfs(intram file system)在启动初期提供一个用户态环境,用来完成一些内核在启动阶段不容易做或者不必要做的事情,如加载模块,定制化启动过程,执行/init进程等;initramfs制作时通常使用gzip或xz将数据压缩,再通过cpio进行归档。
裁剪过程
前面说过,initramfs通常进行压缩后归档,而启动的时候解压的步骤由内核完成,因此原始initrootfs的大小决定了解压的速度,当然,xz在实现了高压缩比的情况下解压速度是比较慢的,我们讨论的前提是同一压缩方式,本次我们使用的是gzip。未优化前解压initramfs的日志如下:
[ 0.598371] Trying to unpack rootfs image as initramfs...
[ 1.706403] Freeing initrd memory: 76116K
可以看到解压花费了1.1s左右的时间,initramfs大小为76116k。
系统启动后,可以在/boot目录查看initrd,具体的内容可以通过lsinitrd命令查看:
Image: initramfs.x86_64.img: 75M
========================================================================
Early CPIO image
========================================================================
drwxr-xr-x 3 root root 0 Jan 1 1970 .
-rw-r--r-- 1 root root 2 Jan 1 1970 early_cpio
drwxr-xr-x 3 root root 0 Jan 1 1970 kernel
drwxr-xr-x 3 root root 0 Jan 1 1970 kernel/x86
drwxr-xr-x 2 root root 0 Jan 1 1970 kernel/x86/microcode
-rw-r--r-- 1 root root 30546 Jan 1 1970 kernel/x86/microcode/AuthenticAMD.bin
-rw-r--r-- 1 root root 4898816 Jan 1 1970 kernel/x86/microcode/GenuineIntel.bin
========================================================================
Version: dracut-055-4.oe2203
可以使用initrd --unpack对initrd进行解压,解压之后查找大文件:
# du -sh *
4.0K tmp
172M usr
8.0K var
...
# du -sh usr/lib/* | sort
0 usr/lib/os-release
16K usr/lib/tmpfiles.d
20M usr/lib/modules
220K usr/lib/dracut
232K usr/lib/udev
24K usr/lib/ostree
28K usr/lib/net-lib.sh
28K usr/lib/sysctl.d
32K usr/lib/dracut-lib.sh
4.0K usr/lib/cifs-lib.sh
4.0K usr/lib/dracut-dev-lib.sh
4.0K usr/lib/initrd-release
44K usr/lib/ignition
4.6M usr/lib/kbd
53M usr/lib/firmware
...
发现firmware占用了大量的空间,我们知道firmware是某些driver加载的时候需要传递给device的数据,而启动的时候仅需要加载少数驱动,大多数的驱动可以在启动之后从磁盘进行加载,因此firmware是可以去掉的;
使用lsinitrd -m可以查看initrd中内置了哪些dracut模块:
# lsinitrd -m initramfs.x86_64.img
Image: initramfs.x86_64.img: 75M
========================================================================
Early CPIO image
========================================================================
drwxr-xr-x 3 root root 0 Jan 1 1970 .
-rw-r--r-- 1 root root 2 Jan 1 1970 early_cpio
drwxr-xr-x 3 root root 0 Jan 1 1970 kernel
drwxr-xr-x 3 root root 0 Jan 1 1970 kernel/x86
drwxr-xr-x 2 root root 0 Jan 1 1970 kernel/x86/microcode
-rw-r--r-- 1 root root 30546 Jan 1 1970 kernel/x86/microcode/AuthenticAMD.bin
-rw-r--r-- 1 root root 4898816 Jan 1 1970 kernel/x86/microcode/GenuineIntel.bin
========================================================================
Version: dracut-055-4.oe2203
dracut modules:
systemd
scsi-rules
systemd-initrd
modsign
i18n
afterburn
ignition
network-legacy
network
ifcfg
url-lib
ignition-conf-fcos
rdcore
btrfs
btrfs
crypt
dm
kernel-modules
kernel-modules-extra
kernel-network-modules
mdraid
multipath
nvdimm
qemu
qemu-net
cifs
lunmask
resume
rootfs-block
terminfo
udev-rules
walinuxagent
dracut-systemd
usrmount
base
emergency-timeout
fs-lib
journal-conf
shutdown
可以选择性的将一些module去掉,这里我们去掉了llvm,issci,nfs等,dracut追加–omit="llvm iscsi nfs"参数;
dracut可以使用–strip参数,去掉制作文件的debug信息;还可以使用–hostonly选项,生成一个最小化的initramfs,使用此选项生成的initrd对硬件兼容性稍差。
经过一顿折腾,最终生成的initramfs大小为34M,内核启动时解压信息如下:
[ 0.262957] Trying to unpack rootfs image as initramfs...
[ 0.633050] Freeing initrd memory: 34368K
解压时间从1.1s减少到0.4s。