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.rssrc/runtime/src/rootfs/,以及 local_execution/prepared_rootfs.rsoci_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 也不是卷:卷是额外挂载点,根是 / 本身。