ZFS 启动环境详解
发布时间:2025/11/25
作者:𝚟𝚎𝚛𝚖𝚊𝚍𝚎𝚗
这篇文章不会尝试给出 ZFS 的通用解释——我们只会专注于 ZFS 启动环境。关于它们存在许多误解和误会——有些人不知道 ZFS 启动环境里面有什么、ZFS 启动环境里面没有什么——但更糟的是——有些人完全不懂。
我假设读者确实了解什么是 ZFS 文件系统的概念和特性 —— 比如 ZFS 池或 ZFS 数据集之类的东西对读者来说是已知的……并且读者能够解释 ZFS 和 LVM 之间的区别。
ZFS 启动环境里有什么
这是首先经常被误解的主题……大概是因为没有理解 canmount=off 这个 ZFS 属性 —— 你可以在 man zfsprops(7) 中获得更多相关内容。
如果该属性被设置为
off,则文件系统无法被挂载,并且会被zfs mount -a忽略。将该属性设置为off类似于将mountpoint属性设置为none,但数据集仍然具有正常的mountpoint属性,该属性可以被继承。将此属性设置为off允许数据集仅作为继承属性的机制使用。设置canmount=off的一个例子是创建两个具有相同挂载点的数据集,这样两个数据集的子数据集会显示在同一目录中,但可能具有不同的继承特性。当设置为
noauto时,数据集只能显式地挂载和卸载。数据集在创建或导入时不会自动挂载,也不会被zfs mount -a命令挂载,或被zfs unmount -a命令卸载。该属性不可继承。——整理者加
这是我以前关于 “ZFS 启动环境” 的演讲中的幻灯片 —— 可以在链接 https://is.gd/BECTL 获得 —— 那是在 2018 NLUUG 会议上做的……颜色并不是随便选的……它们是特地准备成那样,以致敬 NLUUG 会议举办的国家 —— 荷兰。

对 /var 和 /usr 使用 canmount=off 背后的想法是这样的:
/var 和 /usr 这些 ZFS 数据集的内容确实位于 ZFS 启动环境中 —— 位于安装程序创建的 zroot/ROOT/default 这个 ZFS 启动环境中 —— 而其余像下面这些这样的内容:
这些内容 被排除在这个 ZFS 启动环境之外。
因此,在默认情况下,一切都包含在 ZFS 启动环境中 —— 如果你想从 /usr 或 /var 中排除某些部分 —— 你就为这些需要排除的路径添加相应的 ZFS 数据集。
下面是你在 bsdinstall(8) 安装程序中选择 Auto(ZFS) 选项后,FreeBSD 默认的 ZFS 布局。
关键点在于,zroot/usr 和 zroot/var 这两个 ZFS 数据集都具有 canmount=off 这个 ZFS 属性。这意味着 /usr 文件系统 并不存放在 zroot/usr 这个 ZFS 数据集中……它是存放在 zroot/ROOT/default 这个 ZFS 启动环境里的。
你可以用传统的 df(1) 命令进行验证如下。
如你所见,/usr 和 /var 都只是 zroot/ROOT/default 这个 ZFS 数据集中的目录。数据并 不 保存在 zroot/usr 或 zroot/var 这些 ZFS 数据集中……再次强调,这是因为它们具有 canmount=off 这个 ZFS 属性。
现在,这个 FreeBSD 默认设置的主要理念 / 概念是:所有内容都保存在 zroot/ROOT/default 这个 ZFS 数据集中,而所有其他 ZFS 数据集都是从它中 排除(exclude) 出去的。比如 zroot/var/audit 具有 canmount=on 这个 ZFS 属性……其他所有的也都是完全相同的情况。
说实话,为了让事情变得傻瓜式地简单,我会把 zroot/usr 和 zroot/var 这两个 ZFS 数据集换成一个能准确说明用途的名称 —— zroot/exclude,因为在它下面的所有 ZFS 数据集,本质上都是被排除在 ZFS 启动环境 之外的。
现在更容易理解了吗?我希望是的……即使在上面进行了所有这些重命名,ZFS 的挂载点也 没有任何变化,因为 mountpoint 是个独立的 ZFS 属性——所以即使我们对 ZFS 数据集的命名逻辑进行了重新组织,只要没有从上层继承,这个 ZFS mountpoint 属性在逻辑重组后依然保持不变。
之前使用 df(1) 的测试结果与之前完全相同。
/usr 和 /var 的数据都保存在 default ZFS 启动环境内。
我们甚至可以移除 /usr 和 /var 的挂载点,这样会更加清晰。
够清楚了吗?
新建 ZFS 启动环境时会发生什么
另一个经常被误解的谜题……或者说没有被清楚理解的部分。
通常,ZFS 启动环境 是由某个时间点创建的 ZFS 快照 克隆出来的可写 ZFS clone。
让我用我最喜欢的 Enterprise Architect ASCII Edition 软件来可视化一下。
关于上面的 ASCII 图,beadm(8) 命令的输出将显示类似的信息。
现在……有趣的部分来了——你可以创建任意数量的额外 ZFS 启动环境,或者使用 ZFS 的 send|recv 功能。
下面是这种设置的示例。
……并且你可以从每一个这些 ZFS dataset 创建额外的 ZFS 启动环境。
在系统之间传输 ZFS 启动环境
……而且这些系统可以是 任意 系统。你可以在笔记本之间传输 ZFS 启动环境,或者从笔记本传到服务器……甚至从 Bhyve VM 传到服务器……随你喜欢。
下面你将看到一些示例,展示如何将现有的 ZFS 启动环境通过网络从一个 FreeBSD UNIX 系统复制到另一个系统。
这里的 mbuffer(1) 并非关键——它只是通过确保随时有数据可发送来加快传输过程。
上面演示的是将我在 ThinkPad W520 上的 14.3 ZFS 启动环境发送到 ThinkPad T14 系统——这也是为什么我想在另一端将其命名为 14.3.w520,以确保我记得它的来源。
你也可以像我在文章 Other FreeBSD Version in ZFS Boot Environment 中描述的那样,从零创建新的 ZFS 启动环境。
总结
我希望现在 ZFS 启动环境 的主要原理更加清晰了。
……如果还有不明白的地方,欢迎提出你的疑问。
最后更新于
这有帮助吗?