第四章:Jail文件系统

如果你还没有注意到,文件系统管理是jail的重要组成部分。当我们讨论jail时,我们将深入探讨各种文件系统技巧和细节。不过,在我们走得太远之前,您需要了解文件系统的一些细节。其中许多不是针对jail的,但并不常用。

本章主要介绍从主机管理文件系统。第8章深入探讨了如何管理jail内的文件系统。

第四章:Jail文件系统mount(8)umount(8) 文件系统可见性启动时挂载文件系统挂载特定文件系统标准Jails和附加挂载Iocage和附加挂载设备文件系统和 Jails配置 devfs(5)标准Jails和DevfsIocage 和 DevfsIocage磁盘使用

mount(8)umount(8)

您已经使用了 mount(8)umount(8) 。您已装载磁盘和磁盘映像。您在意外安装了错误的东西并破坏了系统的稳定性后重新启动了系统。如果您担任系统管理员的时间足够长,那么在工资单运行时,您意外卸载了 /bin 磁盘包。关于 mount(8) 还有什么需要了解的?一堆。有时,当你有几分钟的空闲时间时,重读 mount(8) 。尝试一些选项。重温你认为自己知道的命令是提高技能的好方法。我们将在这里介绍我认为对jail管理有用的选项。

单独运行 mount(8) 会显示所有类型的已挂载文件系统。但有时您只想查看某种类型的文件系统。要只显示一个文件系统,请使用 -t 标志和文件系统名称。这里我显示了这个主机上挂载的每个设备文件系统:

如果你在寻找陌生感,你可能会发现将其添加到列 -t 很有用。

虽然 mount 可以读取 /etc/fstab ,但它也可以写入该格式的文件。添加 -p 标志以这种样式显示结果:

当我手动调整文件系统并想要生成fstab条目时,我发现这很有用。您可能需要调整最后两个字段,即 dump(8) 级别和挂载顺序,但这至少是一个很好的开始。

最后,mountumount 可以读取带有 -F 标志的 /etc/fstab 以外的fstab文件。您可以创建一个 per-jail fstab ,并且只能在启动jail时挂载它。jail 系统在 mount.fstab 参数后面隐藏了这一点,但你需要知道这种魔法是如何发生的。如果你不小心炸毁了一个jail,而它的自定义文件系统仍然被挂载,请卸载其fstab中的所有内容。

一旦你开始对基础jail进行破坏性测试(第6章讨论),这将为你节省大量的烦恼。

文件系统可见性

登录你的一个jail,运行 mount(8) 。您得到的内容取决于底层文件系统。被jail的用户可以看到他们jail的文件在主机上的挂载位置,但看不到jail上的其他挂载点。运行在ZFS上的jail可以查看其jail所在的数据集。在这里,jail www1被锁定在目录 /iocage/jails/www1/root 中:

UFS上的jail会看到其根文件系统挂载的设备。jail loghost被锁定在 /jail/loghost 中,但这是UFS文件系统 /jail 上的一个目录:

/jails 文件系统位于设备 /dev/gpt/ufs1 上,所以这就是jail看到的。

不过,UFS和ZFS上的jail拥有比单个根目录更多的文件系统。每个jail都有 /dev ,除非你故意关闭它。iocage jails默认挂载 fdescfs(5) 。每个都应该显示在已挂载的文件系统列表中,不是吗?

不是的。jail故意限制被jail程序可以看到的文件系统。默认情况下,被jail的进程只能看到它们的根目录及其挂载的设备。使用参数 enforce_statfs 调整此行为。默认值 2 是最高设置,对文件系统可见性的限制最为严格。其他挂载点仍然存在,被jail的进程可以在权限允许的情况下访问它们。然而,jail不能将它们视为单独的挂载点。

通过将 enforce_statfs 设置为 1 来放宽限制,jail可以感知监狱内挂载的文件系统。

如果您希望被jail的进程能够在jail中挂载新的文件系统,那么该进程必须能够感知挂载点。任何类型的允许装载都需要将 enforce_statfs 设置为 1 或更低。如本章其他部分所述,jail必须具有额外的权限来定义可以挂载哪些类型的文件系统,但内核不会单方面阻止与挂载相关的系统调用。

enforce_statfs 设置为 0 会删除jail可以看到的所有限制。jail可以看到主机上的所有挂载点和文件系统,如果授予权限,可以挂载它们。如果主机有一个单独的 /var 分区,则jail无法读取内容,但知道该分区存在。如果你认为jail需要这个,你可能错了。

大多数文件系统要求都可以通过在启动jail时让主机挂载适当的文件系统来解决。

启动时挂载文件系统

如果jail需要访问其根目录之外的设备或文件系统,您可以在创建jail时自动挂载该文件系统。这可以是jail之间共享的空间、只读数据存储、 /procfdescfs(5) 等特殊文件系统或其他任何东西。

请记住,共享读写磁盘空间并不能控制不同jail如何写入该空间。如果多个jail安装了MariaDB,并且您将它们配置为共享同一个数据目录,那么您的数据就会发生错误——就像不同的数据库服务器通过NFS、SMB或任何其他文件共享协议访问该数据目录一样。不同的jail看不到其他jail的进程。在选择分享时要非常小心。

话虽如此,在多个jail之间共享目录是有意义的。您需要 /usr/ports/usr/src 的多少个副本?在主机之间共享这样的基础设施目录可能是非常有意义的。为了获得最大的安全性,请以只读方式挂载此类目录。

jails系统有几种方法可以在启动时在jail中安装额外的文件系统。

挂载特定文件系统

一些专用文件系统不需要配置。它们要么存在,要么不存在。示例包括 procfs(5)fdescf(5)devfs(5) 。每个jail都有一个参数。

几乎每个jail都需要 /devmount.devfs 参数为jail挂载一个标准设备文件系统。您可以自定义jail可以访问的设备节点,如本章后面的“自定义/dev”中所述。

只有使用Bash shell等外来软件时,才需要文件描述符文件系统。使用 mount.fdescfs 参数启用它(iocage中的 mount_fdescfs )。

FreeBSD开发人员讨厌进程文件系统 /proc 。如果你的软件需要 /proc ,最好启用 mount.procfs (iocage中的 mount_procfs )并在jail中运行它,而不是将主机暴露给它。此外,还可以获得更好的软件。

在jail内挂载其他文件系统稍微复杂一些。

标准Jails和附加挂载

如果一个jail只需要一个特殊的挂载,我们可能会使用 mount 参数。它需要一个参数,一个格式化的 fstab 行。jail系统在创建jail时挂载此文件系统,并在关闭jail时卸载它。

假设我的标准jail loghost 需要非常快速的暂存空间,我决定为 /tmp 分配一个 tmpfs(5) 内存文件系统。jail的根文件系统是 /jail/loghost ,所以我需要将这个 tmpfs 挂载在 /jail/loghost/tmp 。在启动jail之前,我需要 jail(8) 来挂载这个文件系统。我可以通过以下 jail.conf 代码段来实现这一点:

这几乎直接来自 fstab(5) ;我唯一更改的是挂载内存文件系统的目录。

一次性(one-off)解决方案的问题在于,它们从来不是一次性的。一旦你意识到你可以在jail里挂载额外的文件系统,你会发现它们的用途越来越多。此外,这些 fstab 条目会让你整洁的 jail.conf 变得一团糟。jail系统可以在创建jail时挂载额外的 fstab ,并在关闭jail时自动卸载这些文件系统。在 mount.fstab 参数中给出此fstab文件的完整路径。

我通常会为 fstab 文件创建一个目录,并将单个文件命名为 jail 。这让你可以做一些愚蠢的事情,比如将 mount.fstab 设置为默认值,这在你有很多标准基础jails时很有用(第6章)。

每个jail的附加文件系统都包含在一个单独的文件中,您可以轻松挂载和卸载该jail的文件系统,而无需激活jail本身。

虽然挂载和重新挂载额外的文件系统是基础jail不可或缺的一部分,但它们为更常规的jail增加了急需的灵活性。

Iocage和附加挂载

iocage提供了几种编辑 fstab 文件的方法,全部通过 iocage fstab 命令。新创建的iocage jail(不是克隆jail或基础jail)没有 fstab 条目,所以我们将从添加一些开始。

使用 -a 选项向 fstab 添加一行。该命令的格式为:

此命令与为标准jail创建 fstab不同。您没有提供到目标装载点的完整路径。iocage根据需要在数据集之间移动jail,因此您不需要指定当前装载位置的完整路径:相反,您可以在jail内给出您希望新挂载结束的挂载点。在这里,我给jail www4一个tmpfs /tmp

如果你想把源目录 nullfs 挂载在jail的同一位置,比如把主机的 /usr/src 挂载到jail的 /usr/src 上,你可以把这个命令缩短为:

在我的环境中,我将所有自定义脚本放在 /usr/local/scripts 中。我想让主机上的这个目录在所有jail内都可用。我不需要所有主机上的所有这些脚本,所以我可以使用 nullfs(5)使此目录在多个挂载点上可用:

iocage拒绝创建目录,因为jail www1 没有 /usr/local/scripts 目录可供挂载。命令行工具提供了一些健全性检查,这是手动编辑 fstab 无法获得的。一旦我创建了目录,命令就会生效,iopage会立即执行挂载。

过了一段时间,你会忘记你在每个jail的 fstab 中添加了什么。要查看当前的 fstab ,请使用 iocage fstab -l 。默认情况下,它会打印出一个格式化的表,但您可以使用 -h 删除所有内容并获取信息。

我想我曾经把 /usr/src 添加到这个jail里。每个条目都有一个索引号,显示在最左侧。我的 /usr/local/scripts 挂载是索引 0 ,而 /usr/src 是索引 1

要删除 fstab 条目,请获取该条目的索引号,然后使用 iocage fstab -r 命令。将jail名称和 fstab 表条目的索引号作为参数。这个jail不再需要 /usr/src ,所以我要删除它。 /usr/src 挂载的索引是 1 ,所以我运行:

请注意,删除 fstab 条目会更改索引号。删除条目下方的所有内容都向上移动一个。不要一个接一个地删除索引 012 ,因为每次删除后,它们都会指向不同的条目。

你可以用 iocage fstab -R 替换条目。最终,我意识到我不想让我的主机的所有脚本都在jail上可用。清除模板和执行其他jail管理任务的脚本不应该在jail本身;他们向潜在的入侵者泄露了我草率的系统管理员习惯的信息。我需要在主机上创建一个删除的脚本目录 /usr/local/hair-scripts ,并将其挂载到jail上。 /usr/local/scripts 挂载在索引 0 处,所以我运行了:

如果所有这些程序化的东西感觉工作量太大,而您更愿意直接编辑jail的fstab,请使用 iocage fstab -e 和jail名称。这将在默认编辑器中打开jail的fstab:

当您直接编辑jail的 fstab 时,iocage不会执行健全性检查,也不会为您挂载任何文件系统。如果你创建了一个虚假的 fstab 条目,iocage不会告诉你,直到你尝试重新启动jail。如果您担心正常运行时间,请让iocage为您编辑文件系统表。

设备文件系统和 Jails

每个jail都有一个精简的(stripped-down)设备文件系统。典型的jail需要访问允许用户登录、在程序之间传输数据、生成数字和丢弃数据的设备。他们不需要磁盘设备、物理控制台、声卡等。

除非他们这样做。

最终,你需要授予jail访问不同设备的权限。也许你在jail里运行备份软件,或者从备份库中翻录CD,或者使用网络摄像头,或者谁知道呢?这意味着在jail中暴露一个设备,这意味着为该jail配置一个特殊的设备文件系统。

配置 devfs(5)

设备文件系统的深入配置确实超出了本书的范围,但我会给你一个非常简单的例子,因为我是个好人,而不是一个十足的怪物。配置设备文件系统意味着创建隐藏和显示设备节点的规则集。在 /etc/devfs.rules 中配置devfs规则集。使用 devfs(5) 时最常见的错误可能是将规则放在 /etc/devfs.conf 中。不要这样做。

每个规则都有一个编号。FreeBSD在 /etc/defaults/devfs.rules 中包含了一些规则集。这些旨在作为进一步规则集的基石,主要是jail。每个规则集都有一个唯一的名称和编号。规则集4是专门针对jail的。

初始括号用于分隔规则集名称(devfsrules_jail )和规则集编号(4)。

以下行按名称包括其他规则集。标准规则集具有反映其目的的名称: devfsrules_hide_all 隐藏所有设备,devfsrules_unhide_basic 取消隐藏 /dev/random/dev/stdin 等基本设备,devfsrules_unhide_login 取消隐藏登录所需的虚拟终端设备。

在这个基本模型的基础上,jail的规则集还需要两个特殊的设备节点。第四条规则显示 /dev/fuse ,第五条规则显示 /dev/zfs 。这允许在jail 内使用 mount_fusefs(8)zfs(8) 。在jail中公开这些信息意味着您可以通过jail参数控制对它们的访问,而无需为jail分配一组新的 devfs 规则。如果你在UFS上运行jail,并且不允许使用FUSE,你可以删除这些规则。

创建新规则集就像选择一个规则号一样简单,包括一个要构建的规则集,并添加所需的新规则。假设你想让一个特定的jail访问CD阅读器 /dev/cd0 。(您无法从jail中读取CD文件系统,但可能您在其中有一个ZFS池或其他文件系统。)我将复制jail规则集 devfsrules_jail 并添加一个新的 unhide 语句。

此规则集的名称为 devfsrules_jail_cd ,规则集编号为 1000 。这给了我很大的空间让FreeBSD添加更多的规则集。它包括大多数 devfsrules_jail 规则集,并添加了一个规则来取消隐藏 cd0 设备。

运行 service devfs restart 命令,使devd重新读取其规则,并验证新规则集是否显示在 devfs规则集中。一旦它在devd中可用,就将规则集分配给jail。

标准Jails和Devfs

参数 devfs_ruleset 告诉 jail(8) 将哪个规则集分配给jail。默认值是规则集 4 ,也称为 devfsrules_jail 。在这里,我想为我的自定义 devfsrules_jail_cd 规则集(也称为规则集1000)分配一个特定的jail:

重新启动jail,您的设备将可用。 使用 jls(8) 查看分配给jail的所有devfs规则集。

或者,你可以登录jail并验证 /dev/cd0 是否存在,而 /dev/acpi 不存在……但这有什么乐趣呢?

Iocage 和 Devfs

使用 devfs_ruleset 参数控制iocage jail的设备文件系统规则。某种程度上。

iocage有一个硬编码的初始 devfs 规则集。在我写这篇文章的时候,默认的iocage规则集与基础系统用于jail的标准 devfs.rules 规则集 4 相同。如果你在jail上启用DHCP,它会添加 /dev/bpf 。当你启动jail时,iocage会构建一套全新的 devfs 规则并将其分配给jail。如果 devfs_ruleset 设置为 4 ,这是jail的常见默认值,iocage每次启动jail时都会创建这个新的规则集。当你停止jail时,它会删除jail的规则集。

为什么iocage会这样做? devfs 的一个鲜为人知的特性是,您可以使用 devfs(8) 命令在命令行上编辑其规则。我不知道有谁真的这样做,但我确信那些这样做的人有充分的理由。每个iocage jail在启动时都会被分配一个唯一的规则集,这样你就可以在不影响任何其他jail的情况下操纵这个jail。每当您启动一个jail时,iocage告诉您它为该jail创建的 devfs 规则集的数量。查询 jls(8) ,其中 devfs 规则集应用于哪些jail。

当您将特定的 devd 规则集分配给jail时,iocage不会将此规则集复制到新的规则集。它认为,如果你将规则集1000分配给一个jail,你的本意是好的。如果你将一个特定的规则集分配给几个jails,然后实时操纵该规则集,那么这些更改将适用于使用该规则集的所有jails。 devfs_ruleset 的更改只有在重新启动jail后才会生效。

因此,为了让jail wdb2通过规则集1000访问CD驱动器,我将其添加到 /etc/devfs.rules 中,我将运行:

这个jail现在可以看到 /dev/cd0 了。

Iocage磁盘使用

iocage为每个jail创建至少两个数据集。随着我们进入更复杂的iocage使用并利用ZFS功能,很快就会发现,弄清楚一个jail使用了多少磁盘空间并不像在jail内运行 df(1) 那么容易。随着ZFS克隆的分化,您将看到池利用率逐渐上升,需要弄清楚所有磁盘空间的去向。

iocage提供了 df 命令来精确地统计每个jail使用了多少磁盘空间:

第一列给出了jail的名称或UUID。 CRT列显示了jail的ZFS压缩比。 RES列显示了jail的任何ZFS预订,而QTA显示了ZFS配额。 USE显示了jail实际使用了多少空间。 使用 -s 标志按特定列从最小到最大进行排序。下面,我按jail的压缩程度排序:

如果你想找到五个最大的jails,按USE排序,并将输出传输到 tail(1)-h 标志去掉了所有花哨的表格格式,留下原始数据:

或者,您可以搜索 zfs(8) 命令并找出磁盘空间使用情况。任何能让你的鱼浮起来的东西。