BusyBox 搭建 mini rootfs 完全指南 / 第 12 章:最佳实践
第 12 章:最佳实践
12.1 安全加固
12.1.1 最小权限原则
# 1. 不以 root 运行应用
# /etc/passwd
appuser:x:1000:1000:Application User:/home/appuser:/bin/sh
# 2. 使用 su-exec 或 gosu 切换用户
$ su-exec appuser /usr/bin/myapp
# 3. 设置文件权限
$ chmod 700 /usr/local/bin/myapp
$ chown appuser:appuser /usr/local/bin/myapp
# 4. 移除不需要的 Applet
# 编译时禁用危险工具
# make menuconfig → 禁用:
# - su (不需要时)
# - mount (不需要时)
# - reboot/halt/poweroff
# - telnetd
12.1.2 文件系统安全
# 1. 只读 rootfs
# /etc/fstab
/dev/mmcblk0p2 / ext4 ro,noatime 0 1
tmpfs /tmp tmpfs defaults 0 0
tmpfs /var tmpfs defaults 0 0
# 2. 使用 squashfs(压缩只读)
$ mksquashfs rootfs rootfs.sqsh -comp xz
# 3. 使用 read-only overlay
mount -t overlay overlay \
-o lowerdir=/ro-rootfs,upperdir=/tmp/overlay,workdir=/tmp/work \
/mnt/rootfs
# 4. 禁用不需要的挂载点
# 从 inittab 中移除不需要的挂载
12.1.3 网络安全
# 1. 使用 iptables 限制访问
# 允许 SSH
iptables -A INPUT -p tcp --dport 22 -j ACCEPT
# 允许已建立连接
iptables -A INPUT -m state --state ESTABLISHED,RELATED -j ACCEPT
# 拒绝其他
iptables -A INPUT -j DROP
# 2. 使用 dropbear 替代 telnet
# Dropbear 是轻量级 SSH 服务器
$ dropbear -R -w -s # 禁止 root 登录
# 3. 禁用不需要的网络服务
# 从 inittab 中移除:
# - telnetd(不安全)
# - ftpd(不安全)
12.1.4 用户管理
# 1. 设置强密码
$ passwd root
$ echo 'root:$6$rounds=100000$salt$hash' > /etc/shadow
# 2. 禁用不必要的账户
$ sed -i 's/^nobody:.*/nobody:!:0:0:99999:7:::/' /etc/shadow
# 3. 使用 /etc/securetty 限制登录终端
# /etc/securetty
console
ttyS0
# 4. 禁用空密码
$ sed -i 's/root::/root:*:/' /etc/shadow
12.1.5 安全加固清单
| 项目 | 操作 | 优先级 |
|---|
| 禁用不需要的 Applet | menuconfig | 高 |
| 只读 rootfs | fstab/mount | 高 |
| 非 root 运行应用 | su-exec | 高 |
| SSH 替代 Telnet | dropbear | 高 |
| 防火墙规则 | iptables | 中 |
| 禁用空密码 | shadow | 中 |
| 移除调试工具 | menuconfig | 低 |
| 定期更新 BusyBox | 源码更新 | 中 |
12.2 体积优化
12.2.1 BusyBox 编译优化
# 1. 只启用需要的 Applet
$ make menuconfig
# 禁用所有不需要的功能
# 2. 静态编译 + musl(更小)
$ make CC=musl-gcc
# 3. 优化级别
# Settings → (-Os) Additional CFLAGS
# -Os = 体积优化
# -Oz = 最大体积优化(GCC 8+)
# 4. Strip 符号表
$ strip busybox
# 5. UPX 压缩(可选)
$ sudo apt install upx
$ upx --best busybox
12.2.2 体积对比
| 配置 | x86_64 大小 |
|---|
| 默认配置 (glibc, 动态) | ~2.1MB |
| 默认配置 (glibc, 静态) | ~2.8MB |
| 默认配置 (musl, 静态) | ~960KB |
| 默认配置 (musl, 静态, strip) | ~847KB |
| 默认配置 (musl, 静态, strip, -Os) | ~780KB |
| 最小 Applet 集 (musl) | ~200KB |
| 全部 Applet (musl) | ~3.5MB |
| UPX 压缩后 | ~400KB |
12.2.3 rootfs 体积优化
# 1. 使用 squashfs 压缩
$ mksquashfs rootfs rootfs.sqsh -comp xz -b 256K
# 典型压缩比: 3-5x
# 2. 移除不需要的文件
$ rm -rf rootfs/usr/share/doc
$ rm -rf rootfs/usr/share/man
$ rm -rf rootfs/usr/share/info
# 3. 使用 musl 替代 glibc
# musl libc 约 600KB,glibc 约 2MB
# 4. 合并符号链接目录
# 将 /bin, /sbin, /usr/bin, /usr/sbin 合并
$ ln -s bin rootfs/usr/bin
$ ln -s bin rootfs/usr/sbin
$ ln -s bin rootfs/sbin
12.2.4 内核体积优化
# 使用最小内核配置
$ make tinyconfig
# 然后只启用需要的功能
# 压缩内核
# 支持的压缩算法:
# gzip - 压缩率一般,速度快
# bzip2 - 压缩率好
# lzma - 压缩率好,速度慢
# xz - 压缩率最好
# lzo - 压缩率一般,速度最快
# lz4 - 压缩率一般,速度极快
12.3 嵌入式应用
12.3.1 典型嵌入式架构
┌─────────────────────────────────────────┐
│ 用户应用 │
│ (Web UI, MQTT, 数据采集等) │
├─────────────────────────────────────────┤
│ 运行时环境 │
│ (libcurl, OpenSSL, SQLite 等) │
├─────────────────────────────────────────┤
│ BusyBox │
│ (Shell, 系统工具, init) │
├─────────────────────────────────────────┤
│ Linux 内核 │
│ (设备驱动, 文件系统, 网络栈) │
├─────────────────────────────────────────┤
│ 硬件平台 │
│ (ARM SoC, Flash, RAM, 外设) │
└─────────────────────────────────────────┘
12.3.2 系统启动脚本
#!/bin/sh
# /etc/init.d/rcS - 嵌入式系统启动脚本
# 挂载文件系统
mount -t proc proc /proc
mount -t sysfs sysfs /sys
mount -t tmpfs -o size=16M tmpfs /tmp
mount -t devtmpfs devtmpfs /dev
# 设备初始化
echo /sbin/mdev > /proc/sys/kernel/hotplug
mdev -s
# 设置网络
ifconfig lo 127.0.0.1 up
udhcpc -i eth0 -b -q
# 启动看门狗(如果存在)
[ -c /dev/watchdog ] && watchdog -t 30 /dev/watchdog &
# 启动应用
/usr/bin/myapp &
echo "System ready."
12.3.3 看门狗集成
# /etc/init.d/watchdog
#!/bin/sh
DAEMON="/usr/bin/myapp"
WATCHDOG_DEV="/dev/watchdog"
HEALTH_FILE="/tmp/health"
# 启动看门狗
start_watchdog() {
if [ -c "$WATCHDOG_DEV" ]; then
watchdog -t 60 "$WATCHDOG_DEV"
fi
}
# 喂狗
feed_watchdog() {
if [ -c "$WATCHDOG_DEV" ]; then
echo -n 'V' > "$WATCHDOG_DEV"
fi
}
# 健康检查
check_health() {
if [ -f "$HEALTH_FILE" ]; then
return 0
fi
return 1
}
# 主循环
start_watchdog
while true; do
if check_health; then
feed_watchdog
else
echo "Health check failed!"
fi
sleep 30
done
12.3.4 OTA 升级方案
#!/bin/sh
# /usr/bin/ota-update
UPDATE_URL="https://server/update/rootfs.sqsh"
UPDATE_FILE="/tmp/rootfs.sqsh"
# 下载更新
echo "Downloading update..."
wget -O "$UPDATE_FILE" "$UPDATE_URL"
# 校验
echo "Verifying..."
sha256sum -c /tmp/update.sha256 || exit 1
# 写入备用分区
echo "Installing..."
dd if="$UPDATE_FILE" of=/dev/mmcblk0p3 bs=4M
# 切换启动分区
echo "b" > /proc/sys/kernel/reboot_param
# 重启
reboot
12.3.5 电源管理
#!/bin/sh
# /usr/bin/power-manager
# 低功耗模式
low_power_mode() {
echo 0 > /sys/class/leds/status/brightness
echo mem > /sys/power/state
}
# 正常模式
normal_mode() {
echo 1 > /sys/class/leds/status/brightness
}
# 优雅关机
graceful_shutdown() {
echo "Shutting down..."
sync
umount -a
poweroff
}
# 信号处理
trap 'graceful_shutdown' TERM
trap 'low_power_mode' USR1
trap 'normal_mode' USR2
12.4 调试技巧
12.4.1 系统调试
# 1. 开启内核调试
# 内核参数:
loglevel=7 initcall_debug
# 2. 使用 strace
$ strace -f -o trace.log /bin/myapp
$ strace -e trace=open,read,write /bin/myapp
# 3. 使用 ltrace(如果编译了)
$ ltrace /bin/myapp
# 4. 查看系统调用
$ cat /proc/[pid]/syscall
# 5. 查看打开的文件
$ ls -la /proc/[pid]/fd/
# 6. 查看内存映射
$ cat /proc/[pid]/maps
12.4.2 网络调试
# 1. 网络连通性
$ ping -c 3 8.8.8.8
$ traceroute 8.8.8.8
# 2. DNS 查询
$ nslookup example.com
# 3. 端口扫描
$ nc -zv 192.168.1.1 80
# 4. 网络统计
$ netstat -tlnp
$ cat /proc/net/tcp
# 5. ARP 表
$ arp -a
12.4.3 应用调试
# 1. 核心转储
$ ulimit -c unlimited
# 运行程序...
# core 文件生成后使用 gdb 分析
# 2. 日志记录
# /etc/init.d/rcS
exec > /var/log/rcS.log 2>&1
set -x # 打印每条命令
# 3. 远程调试
# 使用 dropbear SSH
$ scp -r /tmp/debug user@remote:/tmp/
# 4. 内存分析
$ cat /proc/[pid]/status | grep -i vm
VmPeak: 12340 kB
VmSize: 12340 kB
VmRSS: 8192 kB
# 5. CPU 分析
$ top -p [pid]
12.4.4 常见问题排查
| 问题 | 排查方法 |
|---|
| Kernel panic | 检查 init 路径、rootfs、驱动 |
| 网络不通 | ifconfig、route、ping、DNS |
| 启动慢 | bootchartd、dmesg、init 日志 |
| 内存不足 | /proc/meminfo、ps、OOM killer |
| 磁盘满 | df、du、日志轮转 |
| 应用崩溃 | strace、核心转储、日志 |
12.5 性能优化
12.5.1 启动优化
# 1. 减少 init 脚本
# 只保留必要的 sysinit 操作
# 2. 使用 readahead
# 预读常用文件到内存
# 3. 延迟初始化
# 将非关键服务移到后台
/usr/bin/non-critical-service &
# 4. 内核参数优化
# 减少内核日志
echo 1 > /proc/sys/kernel/printk
# 5. 使用压缩内核
# lz4 压缩,启动时解压更快
12.5.2 运行时优化
# 1. 内存管理
echo 1 > /proc/sys/vm/drop_caches # 清理缓存
echo 50 > /proc/sys/vm/swappiness # 减少 swap 使用
# 2. I/O 调度
echo noop > /sys/block/mmcblk0/queue/scheduler # Flash 设备
# 3. CPU 频率
echo performance > /sys/devices/system/cpu/cpu0/cpufreq/scaling_governor
# 4. 网络优化
echo 1 > /proc/sys/net/ipv4/tcp_tw_reuse
echo 5 > /proc/sys/net/ipv4/tcp_fin_timeout
12.6 生产部署检查清单
12.6.1 发布前检查
| 检查项 | 操作 | 状态 |
|---|
| 静态编译 | file busybox 确认 | □ |
| strip 符号 | strip busybox | □ |
| 只读 rootfs | fstab 配置 | □ |
| 非 root 应用 | 用户配置 | □ |
| 防火墙规则 | iptables 配置 | □ |
| SSH 访问 | dropbear 配置 | □ |
| 看门狗 | watchdog 脚本 | □ |
| 日志配置 | syslogd 配置 | □ |
| 时间同步 | ntpd 配置 | □ |
| OTA 升级 | 测试升级流程 | □ |
12.6.2 部署脚本
#!/bin/sh
# deploy.sh - 生产部署脚本
set -e
IMAGE="$1"
DEVICE="${2:-/dev/mmcblk0}"
if [ -z "$IMAGE" ]; then
echo "Usage: $0 <image> [device]"
exit 1
fi
echo "=== Production Deployment ==="
echo "Image: $IMAGE"
echo "Device: $DEVICE"
echo ""
# 1. 验证镜像
echo "[1/5] Verifying image..."
sha256sum -c "${IMAGE}.sha256"
# 2. 备份当前系统
echo "[2/5] Creating backup..."
dd if="${DEVICE}p2" of="/tmp/backup-$(date +%Y%m%d).img" bs=4M
# 3. 写入新镜像
echo "[3/5] Writing image..."
dd if="$IMAGE" of="${DEVICE}p2" bs=4M status=progress
sync
# 4. 验证写入
echo "[4/5] Verifying write..."
dd if="${DEVICE}p2" bs=4M count=$(stat -c%s "$IMAGE" | awk '{print int($1/4194304)+1}') | sha256sum
# 5. 完成
echo "[5/5] Deployment complete!"
echo "Please reboot to apply changes."
12.7 持续集成
12.7.1 自动化构建
# .github/workflows/build.yml
name: Build BusyBox
on:
push:
branches: [ main ]
pull_request:
branches: [ main ]
jobs:
build:
runs-on: ubuntu-latest
steps:
- uses: actions/checkout@v3
- name: Install dependencies
run: |
sudo apt-get update
sudo apt-get install -y build-essential gcc make
- name: Build BusyBox
run: |
make defconfig
sed -i 's/# CONFIG_STATIC is not set/CONFIG_STATIC=y/' .config
make -j$(nproc)
- name: Test
run: |
./busybox --list | wc -l
./busybox ls -la
- name: Upload artifact
uses: actions/upload-artifact@v3
with:
name: busybox
path: busybox
12.8 总结与展望
12.8.1 本教程回顾
| 章节 | 内容 |
|---|
| 1-3 | BusyBox 基础概念、编译和使用 |
| 4-5 | rootfs 构建和 Init 系统 |
| 6-9 | 网络、Shell、工具和系统管理 |
| 10-11 | Buildroot 和 Docker 集成 |
| 12 | 最佳实践和生产部署 |
12.8.2 进阶学习路径
初级 ──→ 中级 ──→ 高级
│ │ │
├─ BusyBox 基础 ├─ Buildroot 定制 ├─ 内核裁剪
├─ rootfs 构建 ├─ 驱动开发 ├─ Yocto 项目
├─ Shell 脚本 ├─ OTA 升级 ├─ 安全加固
└─ 基本调试 └─ 性能优化 └─ 商用部署
12.8.3 推荐资源
扩展阅读
上一章: 第 11 章 — Docker 中使用
返回: 目录