rootfs
定义
rootfs(root filesystem,根文件系统)是进程把 /
解析到的那棵目录树。对容器而言,它通常由镜像的只读层加上一层可写目录构成;对 MicroVM
而言,它是客户机内核挂载的根设备或根目录。无论哪一种,入口进程执行
open("/etc/os-release") 时,看到的都是这份
rootfs,而不是宿主的 /。
问题背景
进程不能在「没有文件系统」的情况下运行:动态链接器要找
libc,程序要读配置,日志要写到某个路径。若直接共用宿主根目录,则依赖宿主已安装的软件包,隔离与可复现同时失败。把一份自包含的根文件系统交给工作负载,等于把运行环境从宿主安装状态中剥离出来。
机制说明
从层到可启动根
产品运行时把镜像层按顺序叠加后,得到一棵完整的目录树。这一步需要正确处理:
- 白出(删除)与覆盖;
- 符号链接与硬链接;
- 权限、所有者、时间戳与扩展属性;
- 目标文件系统无法无损表示的文件名(必须失败,而不是改名后继续)。
叠加结果可以以目录形式存在,也可以写入磁盘镜像(例如 ext4 raw
镜像)。Box 在 macOS MicroVM 路径上采用后一种:将校验过的 OCI
层组装到已验证的 ext4 基座,并为每个 box 发布私有 raw 磁盘,见
docs/guest-native-rootfs-design.md。
只读层与可写层
运行期写入默认落在可写层。容器删除后,可写层通常一并删除。这解释了两个常见现象:
- 在容器里
apk add安装的软件,容器一删就消失; - 同一镜像启动的两个容器,不会看见对方写入的文件。
需要跨生命周期保留的数据,应使用命名卷或 bind mount,而不是依赖可写层。
rootfs 与 bundle
在 OCI 模型中,rootfs 是 bundle
的一部分,通常位于 bundle 目录下的
rootfs/。config.json
描述进程如何使用它(工作目录、只读根、额外挂载)。底层运行时不应再去
registry 拉层;它只校验并使用已经发布的 rootfs。
在 Box 中的位置
- 层展开与 rootfs 准备位于
src/runtime/src/oci/rootfs.rs、src/runtime/src/rootfs/,以及local_execution/prepared_rootfs.rs、oci_portable_rootfs.rs。 - MicroVM 客户机内的 PID 1(
src/guest/init/)负责挂载/proc、/sys、/dev、virtio-fs 与 tmpfs,使客户机内核看到完整的运行根。 - macOS 上的字节保真 ext4 写入器是独立 crate
src/third_party/mkext4/,由发布流程拥有。
验证命令
a3s-box run --rm alpine:3.20 -- cat /etc/os-release |
输出应显示 Alpine 的发行信息,而不是宿主发行版。这说明进程的
/ 已经指向准备好的 rootfs。
相关与易混
- 相关:镜像与层、卷与挂载、OCI 标准与 bundle
- 易混:rootfs 不是镜像。镜像是可分发的只读输入;rootfs
是某一次执行已经物化出的根。rootfs 也不是卷:卷是额外挂载点,根是
/本身。