rootfs 详解与裁剪优化记录(以busybox为例)
rootfs(Root File System,根文件系统)是 Linux 内核启动后挂载的第一个文件系统(挂载点为 /),是整个用户空间的运行根基。内核完成硬件初始化后,会挂载 rootfs 并执行其中的 init 进程,正式进入用户态。它包含了系统运行必需的初始化程序、命令工具、动态库、配置文件、设备节点等所有核心组件。
一、rootfs 核心基础
1.1 核心组成
- init 进程:系统第一个用户进程(PID=1),负责系统初始化与服务管理
- 基础命令集:shell、文件操作、系统管理等工具(如 ls、mount、sh)
- 动态链接库:libc、libm 等运行时依赖库
- 系统配置 :
/etc目录下的主机名、挂载表、用户权限、启动脚本等 - 设备节点 :
/dev下的硬件访问接口 - 虚拟文件系统挂载点 :
/proc、/sys、/tmp等
1.2 常见类型与适用场景
| 类型 | 特点 | 适用场景 |
|---|---|---|
| initramfs/initrd | 内存文件系统,内核启动时加载到 RAM | 过渡启动、极小系统、ram 运行场景 |
| ext4 | 通用读写文件系统,稳定性好 | eMMC、SD 卡等块设备 |
| squashfs | 只读高压缩文件系统,体积极小 | 嵌入式固件、只读系统分区 |
| ubifs/yaffs2 | 专为 NAND Flash 设计,支持磨损均衡 | 嵌入式 Flash 存储 |
| NFS rootfs | 网络挂载 | 开发调试阶段 |
1.3 主流构建方案对比
| 方案 | 上手难度 | 体积控制 | 包管理 | 适用场景 |
|---|---|---|---|---|
| BusyBox 手动构建 | 中等 | 极致裁剪 | 无 | 原理学习、极小系统、深度定制 |
| Buildroot | 简单 | 优秀 | 有限 | 嵌入式中小项目、快速量产 |
| Yocto/Poky | 困难 | 优秀 | 完整 | 工业级项目、复杂系统定制 |
| Debootstrap | 简单 | 一般 | apt | Debian/Ubuntu 衍生系统 |
二、从零构建最小 rootfs(BusyBox 分步实操)
本步骤以 ARM 架构交叉编译为例,x86_64 平台可直接使用本地 gcc,流程完全一致。
2.1 准备环境与源码
- 安装基础依赖
bash
sudo apt install build-essential gcc-arm-linux-gnueabihf bzip2 xz-utils squashfs-tools
- 下载并解压 BusyBox 源码
bash
wget https://busybox.net/downloads/busybox-1.36.1.tar.bz2
tar xf busybox-1.36.1.tar.bz2 && cd busybox-1.36.1
2.2 编译 BusyBox
推荐优先使用静态编译,减少动态库依赖问题;追求极致体积可选动态编译。
方式一:静态编译(推荐新手)
- 进入配置界面
bash
make ARCH=arm CROSS_COMPILE=arm-linux-gnueabihf- menuconfig
- 核心配置
Settings -> Build static binary (no shared libs)勾选Settings -> Cross compiler prefix填写工具链前缀:arm-linux-gnueabihf-- (可选裁剪)在
Applets分类中关闭不需要的命令
- 编译安装
bash
make ARCH=arm CROSS_COMPILE=arm-linux-gnueabihf- install
编译完成后,产物会生成在 _install 目录中。
方式二:动态编译(体积更小)
步骤与静态一致,仅不勾选「Build static binary」,后续需补充依赖库。
2.3 搭建根目录结构
创建 rootfs 工作目录并复制 BusyBox 产物:
bash
mkdir -p ~/minirootfs
cp -r _install/* ~/minirootfs/
cd ~/minirootfs
补充 FHS 标准必要目录:
bash
mkdir -p etc/init.d dev proc sys tmp var/log var/run root home lib usr/lib
2.4 配置核心系统文件
/etc 目录的配置是系统正常启动的关键,逐个创建以下文件:
-
/etc/inittab(init 进程配置)::sysinit:/etc/init.d/rcS
::askfirst:-/bin/sh
::restart:/sbin/init
::ctrlaltdel:/sbin/reboot
::shutdown:/bin/umount -a -r -
/etc/init.d/rcS(系统初始化脚本)
bash
#!/bin/sh
mount -t proc proc /proc
mount -t sysfs sysfs /sys
mount -t devtmpfs devtmpfs /dev
hostname -F /etc/hostname
mount -a
添加执行权限:
bash
chmod +x etc/init.d/rcS
-
/etc/fstab(文件系统挂载表)proc /proc proc defaults 0 0
sysfs /sys sysfs defaults 0 0
devtmpfs /dev devtmpfs defaults 0 0
tmpfs /tmp tmpfs defaults 0 0 -
/etc/hostnameminirootfs
-
/etc/passwd(用户配置)root:x:0:0:root:/root:/bin/sh
-
/etc/group(用户组配置)root:x:0:
2.5 补齐动态库依赖(仅动态编译需要)
静态编译可跳过此步。
- 查看 BusyBox 的库依赖
bash
arm-linux-gnueabihf-ldd bin/busybox
- 将依赖的库文件复制到 rootfs 的
lib目录,例如:
bash
cp /usr/arm-linux-gnueabihf/lib/ld-linux-armhf.so.3 lib/
cp /usr/arm-linux-gnueabihf/lib/libc.so.6 lib/
cp /usr/arm-linux-gnueabihf/lib/libm.so.6 lib/
2.6 打包生成镜像
根据使用场景选择对应格式:
场景1:制作 initramfs 镜像(内核启动用)
bash
find . | cpio -o -H newc | gzip -9 > ../rootfs.cpio.gz
场景2:制作 squashfs 只读压缩镜像(量产推荐)
bash
mksquashfs ~/minirootfs rootfs.squashfs -comp xz -b 128K
场景3:制作 ext4 读写镜像
bash
dd if=/dev/zero of=rootfs.ext4 bs=1M count=128
mkfs.ext4 rootfs.ext4
mkdir -p /mnt/rootfs && mount rootfs.ext4 /mnt/rootfs
cp -r ~/minirootfs/* /mnt/rootfs/
umount /mnt/rootfs
三、rootfs 裁剪核心步骤(逐层瘦身)
裁剪遵循「先功能模块 → 再二进制库 → 再文件系统 → 最后启动流程」的优先级,从大体积项入手收益最高。
3.1 第一层:功能模块裁剪(体积减少 50%+)
核心原则:只保留系统必需功能,移除所有非必要组件。
- BusyBox 命令集深度裁剪
BusyBox 默认包含上百个命令,绝大多数场景无需使用。进入make menuconfig按需关闭:
- 无网络需求:关闭
Networking Utilities全部分类(ping、ifconfig、wget 等) - 无文件高级操作:关闭 diff、patch、cpio、tar 等
- 无进程高级管理:关闭 top、strace、ps 高级选项
- 无模块加载需求:关闭
Linux Module Utilities - 无打印、多媒体、蓝牙相关功能:全部关闭
极致裁剪后,仅保留 init、sh、mount、ls、cp、rm 等核心命令,静态编译体积可压缩到 200KB 以内。
- 移除冗余系统服务
- 日志服务:不需要日志可关闭 syslogd、klogd
- 定时任务:不需要 cron 则直接移除
- 网络服务:sshd、ftp、telnetd 等按需保留
- 登录认证:嵌入式场景可去掉 login、passwd,直接 root 自动登录
- C 库选型优化(底层体积关键)
glibc:功能最全但体积最大,完整动态库约 8MBmusl libc:轻量级 POSIX 兼容库,完整动态库仅几百 KB,静态编译优势极大uClibc-ng:面向嵌入式,兼容性好,体积略大于 musl
嵌入式裁剪首选 musl libc,同等功能下体积比 glibc 小 70% 以上。
3.2 第二层:二进制与库文件裁剪(体积减少 20%~40%)
- strip 剥离符号信息
编译生成的二进制、动态库包含大量调试符号与符号表,占用显著体积,使用 strip 工具剥离:
bash
# 剥离二进制所有符号(量产必做)
arm-linux-gnueabihf-strip --strip-all bin/* sbin/* usr/bin/* usr/sbin/*
# 剥离库文件冗余符号(保留动态链接必需信息)
arm-linux-gnueabihf-strip --strip-unneeded lib/*.so* usr/lib/*.so*
通常 strip 后体积可减少 30% 左右,缺点是无法进行源码级调试。
- 清理冗余库文件
- 只保留程序实际依赖的
.so库,不复制完整 lib 目录 - 删除所有静态库文件(
.a后缀),运行时系统完全不需要 - 移除库的调试版本、冗余版本号软链接
- 编译选项优化
所有组件编译时添加大小优化参数:
- CFLAGS 添加
-Os:编译器优先优化代码大小 - 添加
-g0:不生成调试符号 - C++ 程序添加
-fno-exceptions -fno-rtti:关闭异常与运行时类型信息
3.3 第三层:文件系统级裁剪(体积减少 50%+)
- 选择高压缩只读文件系统
固件系统分区优先使用 squashfs,支持多种压缩算法:
xz:压缩率最高,比 ext4 小 60%~80%,适合体积优先场景zstd:压缩解压速度快,平衡性能与体积
极致压缩命令示例:
bash
mksquashfs rootfs rootfs.squashfs -comp xz -Xdict-size 128K -b 128K -no-exports -no-xattrs
如需可写配置,推荐「squashfs 只读系统 + overlayfs 可写叠加」方案,兼顾体积与配置持久化。
- 清理非运行必需文件
逐项删除无用内容:
- 文档手册:
/usr/share/man、/usr/share/doc、README、LICENSE - 多语言文件:
/usr/share/locale,仅保留需要的语言 - 头文件:
/usr/include,运行时完全不需要 - 示例程序、测试脚本、图标主题
- 缓存与日志:
/var/cache、/var/log/*
3.4 第四层:启动流程精简
-
替换重型 init 系统
用 BusyBox init 替代 systemd、SysVinit,体积从几 MB 降到几十 KB;极简场景甚至可用自定义脚本直接作为 init 进程。
-
精简初始化脚本
rcS 脚本只保留必需操作:
- 仅挂载核心虚拟文件系统
- 移除不必要的硬件检测、模块加载
- 去掉启动欢迎信息、冗余日志打印
- 不启动多余后台服务
- 简化登录流程
嵌入式场景无需登录验证时,修改 inittab 将askfirst改为respawn:/bin/sh,启动后直接进入 shell。
四、rootfs 性能优化(启动速度 + 运行效率)
4.1 启动速度优化
- 精简 initramfs:无需 initramfs 的场景直接从 Flash 挂载 rootfs,省去内存拷贝与解压开销
- 并行启动服务:无依赖的服务后台并行启动,避免串行等待
- 驱动内置化:将必需驱动编译进内核(builtin),减少模块加载开销,移除 rootfs 中无用内核模块
- 临时目录内存化 :
/tmp、/var/run、/var/log挂载 tmpfs,大幅提升 IO 速度
4.2 运行时性能优化
- 挂载参数优化 :添加
noatime、nodiratime,禁止更新文件访问时间,减少 Flash 写入 - 动态库预链接 :使用
prelink提前完成动态链接重定位,缩短程序启动时间 - 日志降频写入:减少日志写入频率,或先写入 tmpfs 定期落盘,降低 Flash 磨损
- 内存优化:精简后台进程,关闭无用内核功能,减少内存占用与碎片
五、Buildroot 下的 rootfs 裁剪实战
实际项目中 Buildroot 是最主流的构建工具,以下是核心优化步骤:
5.1 基础配置优化
执行 make menuconfig 进入配置:
-
Build options
- 勾选
strip target binaries gcc optimization level选择Optimize for size (-Os)- 关闭
compile packages with debugging symbols
- 勾选
-
Toolchain
- C library 选择
musl - 关闭
Thread library debugging support - 关闭
Locale support、C++ support(不需要则关闭)
- C library 选择
-
System configuration
- Init system 选择
BusyBox - 关闭不必要的登录、getty 功能
- 自定义精简初始化脚本
- Init system 选择
5.2 包与 BusyBox 裁剪
Target packages中仅勾选必需软件包,默认多余包全部关闭- 执行
make busybox-menuconfig,按前文方法深度裁剪 BusyBox 命令集
5.3 文件系统镜像优化
进入 Filesystem images:
- 仅保留需要的镜像格式(如 squashfs)
- squashfs 压缩算法选择
xz - 关闭 ext4、tar 等其他镜像格式
配置完成后执行 make,即可生成裁剪优化后的固件镜像。
六、裁剪验证与问题排查
6.1 体积分析方法
bash
# 查看总大小
du -sh rootfs/
# 逐层定位大目录
du -h --max-depth=1 rootfs/
# 找出最大的10个文件
find rootfs/ -type f -exec du -h {} \; | sort -rh | head -10
6.2 功能验证方式
- QEMU 模拟启动:快速验证系统可用性,无需硬件
- NFS 网络挂载:开发板通过网络挂载 rootfs,方便调试修改
- 逐项功能测试:验证保留的命令、服务是否正常工作
6.3 常见问题定位
- Kernel panic: No init found :检查
/sbin/init是否存在、动态库是否完整、内核是否支持对应文件系统 - 命令执行报错 not found:动态库缺失,用 ldd 检查依赖;或交叉编译架构与目标不一致
- 裁剪后功能异常:遵循少量多次原则,逐步回退裁剪项,定位误删的命令或库