如何从零构建 ARM64 系统:Umbrel OS 用 debootstrap+QEMU 完成跨架构引导的完整指南
【免费下载链接】umbrel-osumbrelOS development has moved to https://github.com/getumbrel/umbrel项目地址: https://gitcode.com/gh_mirrors/um/umbrel-os
Umbrel OS 是一个面向树莓派的开源个人云操作系统,本仓库正是它官方镜像的构建脚本集合。本文拆解其核心机制:如何在 x86 构建机上用 debootstrap 与 QEMU,从零完成一个 ARM64 系统的跨架构引导——即使是新手,也能在 10 分钟内看懂整条流水线。
一、为什么必须跨架构:x86 上的 ARM64 困境
先理解一个问题:🤔 构建服务器通常是 x86 架构的 CI 机器,而目标设备是 ARM64 架构的树莓派 4——架构不同,怎么"造"出目标系统的镜像?
两条常见路线:
- 交叉编译工具链:专业但繁琐,要处理链接、头文件、依赖地狱
- 直接运行 ARM 二进制:用 QEMU 用户态模拟,让 ARM 程序在 x86 上"假装是原生"
本项目选择后者,思路非常干净。看依赖清单depends就能发现核心只有两件武器:
debootstrap:引导生成最小 Debian 系统qemu-aarch64-static(即 qemu-user-static):用户态模拟 ARM64 指令
全程不需要交叉编译器。更妙的是,最终镜像在 QEMU 虚拟机里也能直接启动,方便调试——这一点后文还会揭晓。
二、项目结构速览:用目录理解"三阶段"
整个构建过程被拆成清晰的阶段目录,每个目录只干一件事:
| 阶段 | 目录 | 职责 |
|---|---|---|
| Stage0 | stage0/ | debootstrap 生成最小 Debian 系统、配置 APT、装树莓派固件 |
| Stage1 | stage1/ | 写入启动文件、调整系统与网络 |
| Stage2 | stage2/ | 安装 Umbrel 应用、设置版本、准备导出 |
| 导出 | export-image/ | 把 rootfs 打包成可刷写的 .img 镜像 |
| 发布 | export-noobs/ | 官方刷机流程所需的 os.json、partitions.json 与引导页素材 |
💡 提示:本仓库是构建脚本的归档版本,主线开发已迁移至官方组织的仓库,但整套构建思路至今仍是学习"如何用脚本造一个 OS"的绝佳样本。
想动手看源码的话:
git clone https://gitcode.com/gh_mirrors/um/umbrel-os三、debootstrap 一键引导:最小系统如何"长"出来
一切的起点在stage0/prerun.sh,核心就一句话:对bootstrap函数发起调用,把 Debian buster 引导进一个空目录。真正的聪明之处在scripts/common里的bootstrap函数——它会自动判断宿主机架构:
if [ "$(dpkg --print-architecture)" != "arm64" ]; then BOOTSTRAP_CMD=qemu-debootstrap fi- 宿主机就是 ARM64?→ 直接用
debootstrap原生引导,快 - 宿主机是 x86?→ 换成
qemu-debootstrap,跨架构引导
debootstrap的作用,等价于在一个空目录里"裸装"一个可以登录的最小 Debian 系统:装好 apt、base 基础包,完成 dpkg 数据库初始化。随后 Stage0 继续打地基:
stage0/00-configure-apt/00-run.sh:写入sources.list,追加树莓派官方源raspi.list,并注册armhf多架构(为兼容 32 位树莓派软件包)stage0/01-locale/00-packages:安装 locales,配好中文等语言环境stage0/02-firmware/01-packages:安装raspberrypi-bootloader与raspberrypi-kernel两个固件包——这是系统能上电启动的"灵魂"
整个阶段所有"进系统内执行"的操作,都靠scripts/common中的on_chroot辅助函数完成:先挂载proc、dev、sys,再 chroot 进入目标系统执行命令,保证环境干净可控。
四、QEMU 用户态模拟:ARM 二进制在 x86 上直接跑
qemu-debootstrap到底做了什么?🧩
- 在目标 rootfs 里预装
qemu-aarch64-static静态 QEMU 二进制 - 向内核注册 binfmt_misc 规则
- 之后 chroot 内每次执行 ARM64 ELF 程序,内核自动把控制权交给 QEMU 模拟执行
于是,apt-get install、编译器、shell 脚本……所有 ARM 程序都在 x86 构建机上"透明运行",不需要任何交叉工具链。代价是执行速度较慢,但对"装几百个软件包"这种场景完全够用。
还有一个容易被忽略的细节——成品镜像也刻意对 QEMU 友好。stage2/00-sys-tweaks/files/90-qemu.rules用 udev 规则把虚拟机里的磁盘名映射成真实硬件名:
KERNEL=="sda", SYMLINK+="mmcblk0" KERNEL=="sda2", SYMLINK+="root"在树莓派上,系统盘是mmcblk0;在 QEMU 里则是sda。这一小段规则让同一张镜像既能上真实硬件,也能进 KVM 虚拟机,测试成本直接降为零。
五、三个阶段详解:从最小系统到完整 Umbrel OS
Stage1:让系统能启动
stage1/00-boot-files/把两个关键启动文件写入/boot:
cmdline.txt:内核启动参数(root 分区、ext4 文件系统、串口控制台)config.txt:树莓派引导配置,其中arm_64bit=1强制 64 位启动,dtoverlay=vc4-fkms-v3d启用图形栈
再配合stage1/01-sys-tweaks/files/fstab挂载表和网络调整,系统骨架就绪。
Stage2:装进"灵魂"
stage2/03-install-umbrel/00-packages安装 git、python3、rsync 等核心依赖并部署 Umbrel 主体;stage2/04-set-umbrel-os-version/写入版本号。而镜像的名字、主机名umbrel、首个用户、SSH 开关等信息,统一由根目录的config定义。
分层组装的精髓
每个阶段的prerun.sh都会先执行copy_previous:用 rsync 复制上一阶段的 rootfs(排除 apt 缓存),再执行本阶段的变更。像搭积木一样逐层叠加,每一步都可单独重跑、独立验证。
六、打包导出:从目录到可刷写的 .img
最后一步在export-image/prerun.sh,把整个 rootfs 目录"凝固"成一张磁盘镜像,流程干净利落:
- 算尺寸:boot 分区固定 256MB FAT32;root 分区 = rootfs 实际大小 + 20% 余量 + 200MB,并对齐到 4K
- 建分区:
truncate创建空文件,parted写 msdos 分区表并切出两个主分区 - 做文件系统:
losetup把分区挂成环回设备,mkdosfs/mkfs.ext4初始化 - 灌数据:rsync 把 rootfs 与 boot 文件写入分区
export-noobs/则面向发布:写入官方刷机工具识别的os.json、partitions.json,以及首屏展示的引导页素材(slides_vga/目录)——也就是文章开头那张欢迎画面。
七、要点清单:把这套经验带走 🎯
- debootstrap负责"零 → 最小系统",一行调用生成可登录的 rootfs
- qemu-user-static(经 qemu-debootstrap)负责跨架构"透明执行",告别交叉工具链
- 分阶段增量组装:Stage0 打地基 → Stage1 能启动 → Stage2 装应用,每层只负责一件事
- 一张镜像双环境:90-qemu.rules 让物理树莓派与 QEMU 虚拟机都能直接引导
- 关键文件索引:
scripts/common、stage0/prerun.sh、stage1/00-boot-files/、stage2/00-sys-tweaks/files/90-qemu.rules、export-image/prerun.sh
看懂了这条流水线,你就掌握了"用脚本从零造一个操作系统镜像"的完整方法论——换掉发行版与固件包,同样的套路可以复刻给任何 ARM 设备。
【免费下载链接】umbrel-osumbrelOS development has moved to https://github.com/getumbrel/umbrel项目地址: https://gitcode.com/gh_mirrors/um/umbrel-os
创作声明:本文部分内容由AI辅助生成(AIGC),仅供参考