第21章 其他文件系统
附录 D. OpenPGP 密钥
15.5.更新多个 Jail
对多个 Jail 的管理可能会成为问题,因为每座 Jail 在升级时都必须从头开始重建。如果创建并手动更新了许多 Jail,这可能会非常耗时且无聊。
本节演示一种解决此问题的方法,方法是使用只读 mount_nullfs(8) 挂载在 jail 之间安全地共享尽可能多的内容,以便更新更简单。这使得将单个服务(如HTTP,DNS和SMTP)放入单独的 Jail 更具吸引力。此外,它还提供了一种添加、删除和升级 jail 的简单方法。
存在更简单的解决方案,例如 ezjail,它提供了一种更简单的 FreeBSD jail 管理方法,但其通用性不如此设置。ezjail 在《用 ezjail 管理 Jail》中有更详细的介绍。
本节中描述的设置的目标是:
  • 创建一个简单易懂的 jail 结构,不需要在每个 jail 上运行完整的安装世界。
  • 轻松添加新的 Jail 或删除现有的 Jail。
  • 轻松更新或升级现有 Jail。
  • 使运行定制的 FreeBSD 分支成为可能。
  • 对安全性保持偏执,尽可能减少妥协的可能性。
  • 尽可能节省空间和 inode。
此设计依赖于一个只读主模板,该模板安装在每个 jail 中,每个 jail 都有一个读写设备。设备可以是单独的物理光盘、分区或 vnode 支持的内存设备。此示例使用读写空值挂载。
文件系统布局如下:
  • jail 位于 /home 分区下。
  • 每个 jail 都将挂载在 /home/j 目录下。
  • 每个 jail 的模板和所有 jail 的只读分区是 /home/j/mroot。
  • 将为 /home/j 目录下的每个 jail 创建一个空白目录。
  • 每个 jail 都有一个 /s 目录,该目录将链接到系统的读写部分。
  • 每个Jail都有自己的读写系统,该系统基于/home/j/skel。
  • 每个 jail 的读写部分将在 /home/js 中创建。

15.5.1. 创建模板

本节介绍创建主模板所需的步骤。
建议首先使用“从源代码更新 FreeBSD”中的说明将主机 FreeBSD 系统更新到最新的 -RELEASE 分支。此外,此模板使用 sysutils/cpdup 包或端口,portsnap 将用于下载 FreeBSD Ports Collection。
  1. 1.
    首先,为只读文件系统创建一个目录结构, 它将包含 Jail 的 FreeBSD 二进制文件。然后,将目录更改为 FreeBSD 源代码树,并将只读文件系统安装到 jail 模板中:
1
# mkdir /home/j /home/j/mroot
2
# cd /usr/src
3
# make installworld DESTDIR=/home/j/mroot
Copied!
  1. 1.
    接下来,为 jail 准备一个 FreeBSD Ports 以及一个 FreeBSD 源代码树,这是 mergemaster 所必需的:
1
# cd /home/j/mroot
2
# mkdir usr/ports
3
# portsnap -p /home/j/mroot/usr/ports fetch extract
4
# cpdup /usr/src /home/j/mroot/usr/src
Copied!
  1. 1.
    为系统的读写部分创建框架:
1
# mkdir /home/j/skel /home/j/skel/home /home/j/skel/usr-X11R6 /home/j/skel/distfiles
2
# mv etc /home/j/skel
3
# mv usr/local /home/j/skel/usr-local
4
# mv tmp /home/j/skel
5
# mv var /home/j/skel
6
# mv root /home/j/skel
Copied!
  1. 1.
    使用 mergemaster 安装缺少的配置文件。然后,删除 mergemaster 创建的额外目录:
1
# mergemaster -t /home/j/skel/var/tmp/temproot -D /home/j/skel -i
2
# cd /home/j/skel
3
# rm -R bin boot lib libexec mnt proc rescue sbin sys usr dev
Copied!
  1. 1.
    现在,将读写文件系统符号链接到只读文件系统。确保在正确的 s/ 位置创建符号链接,因为在错误的位置创建目录将导致安装失败。
1
# cd /home/j/mroot
2
# mkdir s
3
# ln -s s/etc etc
4
# ln -s s/home home
5
# ln -s s/root root
6
# ln -s ../s/usr-local usr/local
7
# ln -s ../s/usr-X11R6 usr/X11R6
8
# ln -s ../../s/distfiles usr/ports/distfiles
9
# ln -s s/tmp tmp
10
# ln -s s/var var
Copied!
  1. 1.
    作为最后一步,创建一个包含以下行的通用 /home/j/skel/etc/make.conf
1
WRKDIRPREFIX?= /s/portbuild
Copied!
这使得在每个 jail 中编译 FreeBSD ports 成为可能。请记住,ports 目录是只读系统的一部分。WRKDIRPREFIX的自定义路径允许在每个 jail 的读写部分完成生成。

15.5.2. 创建 Jail

jail 模板现在可用于在 /etc/rc.conf 中设置和配置 jail。此示例演示如何创建 3 个 jail:NSMAILWWW
  1. 1.
    将以下行添加到 /etc/fstab,以便 jail 的只读模板和读写空间在各自的 jail 中可用:
1
/home/j/mroot/home/j/ns nullfs ro 00
2
/home/j/mroot/home/j/mailnullfs ro 00
3
/home/j/mroot/home/j/www nullfs ro 00
4
/home/js/ns /home/j/ns/snullfs rw 00
5
/home/js/mail/home/j/mail/s nullfs rw 00
6
/home/js/www /home/j/www/s nullfs rw 00
Copied!
为了防止 fsck 在引导期间检查 nullfs 挂载,并防止转储备份 jail 的只读 nullfs 挂载,最后两列都设置为 0
  1. 1.
    在 /etc/rc.conf 中配置 jail:
1
jail_enable="YES"
2
jail_set_hostname_allow="NO"
3
jail_list="ns mail www"
4
jail_ns_hostname="ns.example.org"
5
jail_ns_ip="192.168.3.17"
6
jail_ns_rootdir="/usr/home/j/ns"
7
jail_ns_devfs_enable="YES"
8
jail_mail_hostname="mail.example.org"
9
jail_mail_ip="192.168.3.18"
10
jail_mail_rootdir="/usr/home/j/mail"
11
jail_mail_devfs_enable="YES"
12
jail_www_hostname="www.example.org"
13
jail_www_ip="62.123.43.14"
14
jail_www_rootdir="/usr/home/j/www"
15
jail_www_devfs_enable="YES"
Copied!
jailnamerootdir 变量被设置为 /usr/home 而不是 /home,因为在默认的 FreeBSD 安装中,/home 的物理路径是 /usr/homejailnamerootdir变量不能被设置为包含符号链接的路径,否则Jail将拒绝启动。
  1. 1.
    为每个 jail 的只读文件系统创建所需的挂载点:
1
# mkdir /home/j/ns /home/j/mail /home/j/www
Copied!
  1. 1.
    使用 sysutils/cpdup 将读写模板安装到每个 jail 中:
1
# mkdir /home/js
2
# cpdup /home/j/skel /home/js/ns
3
# cpdup /home/j/skel /home/js/mail
4
# cpdup /home/j/skel /home/js/www
Copied!
  1. 1.
    在这个阶段,Jail 已经建成并准备运行。首先,为每个 jail 挂载所需的文件系统,然后启动它们:
1
# mount -a
2
# service jail start
Copied!
Jail 现在应该运行。要检查它们是否已正确启动,请使用 jls 。其输出应类似于以下内容:
1
# jls
2
JID IP AddressHostname Path
3
3 192.168.3.17 ns.example.org /home/j/ns
4
2 192.168.3.18 mail.example.org /home/j/mail
5
1 62.123.43.14 www.example.org/home/j/www
Copied!
daemons。JID 列表示每个运行中的 jail 的标识号。使用下面的命令来执行JID 为 3 的 jail 的管理任务。
1
# jexec 3 tcsh
Copied!

15.5.3. 升级

此设置的设计提供了一种简单的方法来升级现有的 jail,同时最大限度地减少其停机时间。此外,它还提供了一种在出现问题时回滚到旧版本的方法。
  1. 1.
    第一步是升级主机系统。然后,在 /home/j/mroot2 中创建新的临时只读模板。
1
# mkdir /home/j/mroot2
2
# cd /usr/src
3
# make installworld DESTDIR=/home/j/mroot2
4
# cd /home/j/mroot2
5
# cpdup /usr/src usr/src
6
# mkdir s
Copied!
installworld 将创建一些不必要的目录,应将其删除:
1
# chflags -R 0 var
2
# rm -R etc var root usr/local tmp
Copied!
  1. 1.
    为主文件系统重新创建读写符号链接:
1
# ln -s s/etc etc
2
# ln -s s/root root
3
# ln -s s/home home
4
# ln -s ../s/usr-local usr/local
5
# ln -s ../s/usr-X11R6 usr/X11R6
6
# ln -s s/tmp tmp
7
# ln -s s/var var
Copied!
  1. 1.
    接下来,停止Jail:
1
# service jail stop
Copied!
  1. 1.
    卸载原始文件系统,因为读写系统连接到只读系统(/s):
1
# umount /home/j/ns/s
2
# umount /home/j/ns
3
# umount /home/j/mail/s
4
# umount /home/j/mail
5
# umount /home/j/www/s
6
# umount /home/j/www
Copied!
  1. 1.
    移动旧的只读文件系统,并将其替换为新的文件系统。如果出现问题,这将用作旧的只读文件系统的备份和存档。此处使用的命名约定对应于创建新的只读文件系统时。将原来的 FreeBSD Ports 移到新的文件系统上 以节省一些空间和 inode:
1
# cd /home/j
2
# mv mroot mroot.20060601
3
# mv mroot2 mroot
4
# mv mroot.20060601/usr/ports mroot/usr
Copied!
  1. 1.
    此时,新的只读模板已准备就绪,因此唯一剩下的任务是重新挂载文件系统并启动 jail:
1
# mount -a
2
# service jail start
Copied!
使用 jls 来检查 Jail 是否正确启动。在每个 Jail 中运行 mergemaster 来更新配置文件