第二十二章:JAILS

虚拟化(Virtualization )将操作系统实例与底层硬件分离。虚拟化允许您通过复制文件将操作系统安装从一个硬件移动到另一个硬件。虚拟化需要在硬件上安装操作系统,但这种安装通常非常简单,没有面向公众的服务,并且很容易在新硬件上复制。这可能是几十年来系统管理方面最大的变化。

虚拟化类似于客户端-服务器环境。硬件及其核心操作系统实例是主机,而客户端都是虚拟化的操作系统实例。客户端依赖主机提供基本服务,如存储、处理器性能和内存。对主机的更改可以反映在虚拟化客户端中,但客户端上的更改除了消耗资源外,对主机没有影响。 FreeBSD支持两种类型的虚拟化:jails和bhyve。

jails 是一种轻量级的虚拟化方法,有时也称为操作系统级虚拟化(OS-level virtualization)。jail通常包含在现有FreeBSD系统之上运行的完整操作系统用户区。jail依赖于主机的文件系统,但仅限于目录树的一个子集。它甚至可能在ZFS池中有一大块专用空间。jail没有自己的内核,而是在主机内核的受限部分运行。主机可以在不进入jail的情况下管理jail内的进程,或者如果愿意,也可以在jail内运行进程。jail没有图形控制台。使用jail虚拟化相同版本或更早版本的FreeBSD安装,或运行简单的虚拟Linux系统。

Bhyve 是一个更重的虚拟化系统。bhyve模拟硬件,而不是使用主机的内核和文件系统。主机提供一块磁盘空间供虚拟机用作磁盘。bhyve虚拟机必须配备自己的文件系统、内核和支持基础设施。Bhyve虚拟机需要比监狱更多的资源,但它们也通过虚拟网络计算(virtual network computing —— VNC)提供控制台,可以运行真正的外部操作系统,如微软Windows。由于Bhyve的快速发展,它正在迅速变化,所以这本书没有涵盖它。一旦它稳定下来,我就会写关于Bhyve。

在考虑bhyve之前,先看看监狱是否能满足你的需求。

Jail 基础

jail是一种超级chroot,不仅适用于文件系统,也适用于进程和网络堆栈。jail内的系统只能访问文件系统的一小部分,看不到jail外的进程。传统上,每个jail都被分配了一个专用的IP地址,jail只能查看该特定IP的流量。每个jail甚至都有自己的用户帐户。jail中的根帐户完全控制着jail,但无法访问jail以外的任何内容。

对于拥有jail root访问权限的用户来说,jail看起来就像一个几乎完整的FreeBSD系统,只缺少几个设备节点。用户可以安装她喜欢的任何软件,而不会干扰主机或其他jail。jail中运行的所有进程只能影响jail的文件和进程。jail内的用户无法看到jail以外的任何东西;她被关起来了。如果jail被黑客入侵,入侵者也会被关在jail里。

jail可以使用基于 vnet(9) 的虚拟网络堆栈。这是一个高级用途,我们不会在这里介绍,但如果你需要为jail提供自己的路由表,这就是你的做法。

从FreeBSD 9开始,多个jail可以共享一个IP地址,但系统管理员需要配置每个jail,为每个网络服务使用唯一的TCP/IP端口。您不能在单个IP的端口22上运行多个SSH实例!为简单起见,以下示例为每个jail使用一个IP,但请记住,您还有其他选择。

许多人把他们所有的服务都放在jail里,即使host是专门为特定目的服务的。jail数据集的ZFS快照或目录树的tarball是jail的完整备份。软件升级失败后的恢复只需提取tarball或回滚到快照即可。

jail对于软件开发和测试也很有用。部署新服务通常需要安装和测试相当多的软件包。在选择解决方案并继续生产之前,在jail里进行测试可以防止废弃文件和不需要的软件污染主机。

根据您的硬件和系统负载,单个FreeBSD主机可以支持数十个甚至数百个jail。不过,如果你想认真运行那么多jail,请确保你的主机有两个单独的网络接口。一个负责jail,另一个负责管理host。

一切都从配置jail主机开始。

Jail 主机服务器设置

作为jail主机的服务器必须在一些恼人的限制下工作。在构建第一个jail之前,请正确配置您的主机。

jail系统有自己的sysctl树 security.jail 。您只能从主机系统更改这些sysctls。某些sysctls会影响主机上运行的所有jail。以 security.jail.param 开头的系统可以按jail设置。我们将在本章中讨论这些问题。

Jail 主机存储

我强烈建议您仅将jail主机用于管理jail,并将所有服务都放在jail内。首先,将主机的存储配置为将jail和主机操作系统分开。

许多用于虚拟化的主机在主板上为操作系统配备了SATA DOM闪存驱动器。这些驱动器的大小通常小于100GB,但FreeBSD的基本安装容量远小于1GB。如果您有SATA DOM或类似产品,请将其用于主机操作系统。如果您有多组冗余硬盘,请使用一对来镜像操作系统,并将其他所有内容专用于jail。

如果您没有这样的硬件,请为主机操作系统分配空间。为UFS文件系统使用分区,或为ZFS使用数据集保留。无论哪种情况,10GB的空间都应该足够了。如果你需要额外的空间来应对紧急情况,你可以从jail借一些。

虽然ZFS对jail非常有用,但它不是必需的。我在UFS上运行很多年 jail。使用适合你和你的环境的东西。

一旦您对主机进行了分区并安装了操作系统,请查看网络。

Jail 网络

jail网络有两个看似矛盾的方面:第一,每个jail都希望完全控制分配给它的任何IP地址;其次,jail可以与其他jail甚至主机共享IP地址。您可以使用主机上的任何IP地址启动一个jail,但该jail无法将任何面向网络的服务与在该IP上运行的其他服务进行协调。如果你的jail共享主机的IP地址,并且主机在端口22上运行SSH,那么jail就不能使用端口22。如果你试图在jail中启动sshd(8),程序会抱怨它无法使用端口22并崩溃。在jail之间,甚至在jail和主机之间共享IP地址,需要系统管理员协调哪些端口属于哪些主机,并相应地配置所有内容。

配置jail的最简单方法是为每个jail分配自己的IP地址,并为主机提供自己的IP位址。然后,每个jail都可以完全控制自己的IP地址。一旦你掌握了这个窍门,你就可以开始在jail之间共享地址。这意味着主机不能让守护进程监听分配给jail的IP地址。让主机的守护进程监听jail的IP不会阻止jail启动,但会阻止jail在该端口上启动自己的服务。像Bert这样的用户如果无法通过SSH连接到他们的私人jail,就会抱怨!

配置jail主机最干净的方法是决定主机只提供jail。在主机上运行的任何服务都必须在jail里。如果您需要简单的服务,如名称服务器或邮件交换器,请在jail中配置它们。这不仅比正确重新配置所有这些服务器以仅连接到所选IP地址更容易;它还为您的其他jail提供了额外的安全保障。对主机的入侵会自动授予入侵者访问您所有jail的权限,而对单个jail的入侵会将入侵者限制在该jail内。

如第9章所述,使用 sockstat(1) 识别网络上正在监听的程序。添加 -46 标志仅显示IPv4和IPv6流量,添加 -l仅显示侦听套接字。

这个相当默认的FreeBSD安装有两个监听网络的程序:ntpdsshd 。两者都在监听所有IP地址。我们必须将所有这些守护进程配置为只监听主服务器地址。

以下是一些在主机服务器上引起问题的常见守护进程。在所有这些中,我将假设jail主机的IP为198.51.100.50。

syslogd

系统记录器 syslogd(8) 打开一个UDP套接字,以便它可以向其他主机发送消息。如果您不远程登录,或者使用其他日志记录解决方案,请使用 rc.conf 中的 -ss 标志关闭网络组件:

如果需要发送syslogd消息,请使用 -b 标志强制syslogd仅附加到单个IP地址:

无论哪种解决方案,jail管理员都可以单独决定是否通过网络登录。有关syslogd的完整讨论,请参阅第21章。

inetd

如果你需要 inetd(见第20章),你几乎肯定应该在jail里运行它,而不是在主机上运行。但是,如果您无法逃避在主机上运行inetd,请使用 -a 标志将其限制为单个IP地址,如以下 rc.conf 代码段所示。

如果我只指定了 -a 标志和IP地址,它就会覆盖 /etc/defaults/rc.conf 中inetd的默认标志。过去几十年来FreeBSD的每个版本都使用了 -wW -C 60 的默认标志;我将 -a 和IP地址添加到这些标志中。

sshd

/etc/ssh/sshd_config 中的 ListnAddress 选项告诉 sshd(8) 要绑定到哪个地址。将其仅限于您的主机IP。

如果你的jail host提供的唯一服务是 sshd(8) ,那么你做得很好。

NFS

网络文件系统程序,如 rpcbind(8)nfsd(8) ,无论你做什么,都会绑定到主机上的所有IP地址。不要在jail内运行这些程序,也不要从jail内运行NFS。如果您的客户端需要NFS挂载,请让host运行这些程序并提供NFS挂载。

网络时间协议

jail host最有问题的服务是计时。所有jail都从host获取系统时钟。FreeBSD内置的时间守护进程 ntpd(8) 监听主机上的所有IP地址,包括jail内的IP地址。不过,作为唯一罕见的例外,我要告诉你继续在主机上运行ntpd。

jail缺乏更改内核时间的适当权限。虽然你可以在监狱里运行ntpd,但它实际上什么也做不了。继续在你的jail host上运行ntpd,不要担心它会监听所有IP地址。任何试图在端口123上运行除ntpd之外的基于UDP的服务的人都可能试图逃避数据包过滤器。让他们更努力地工作。

如果你想避免碰撞的可能性,请安装 openntpd 包。与基本系统 ntpd(8) 不同,OpenNTPD可以配置为监听单个IP地址。

IP 地址

每个jail可以有一个或多个IP地址。在你开始jail之前,这些地址必须附在主人身上。jail将在没有任何网络的情况下运行,但在主机之外无法访问。在 /etc/rc.conf 中添加任何必要的IP地址作为别名。

启动时的 jails

要让FreeBSD在启动时启动jail,请在rc.conf中设置jail_enable:

FreeBSD默认启动 /etc/jail.conf 中列出的所有jail。如果您希望系统在启动时仅启动这些jail的一个子集,请使用 jail_list rc.conf 选项。在这里,我有两个jail,分别是mariadbhttpd。我希望它们按此顺序启动,以便我的数据库监狱在调用它的web服务器之前运行:

在系统关闭期间,FreeBSD会按照启动jail的顺序停止jail。您的应用程序可能不喜欢这样。在我的示例中,我希望在数据库后端之前关闭web服务器。我宁愿让一个网站完全不可用,也不愿让用户看到可怕的“数据库服务器崩溃”错误:

如果jail启动顺序不重要,你可以同时启动和停止所有jail:

现在,您可以配置一个jail。

Jail 设置

现在我有了主机,我可以安装一些jail。我会从一个叫 mariadb 的jail开始,因为它运行 MariaDB。

每个jail都需要一个专用的根目录。我所有的示例jail都位于/jail 之下。我通常会将每个jail放在一个以jail名称命名的目录中——在本例中为 /jail/mariadb

每个jail都需要一个主要IP。它也可以有其他IP,我们稍后会看到,但让我们从一个开始。jail mariadb得到203.0.113.51。

每个jail都需要一个互联网主机名,就像它是一个真正的主机一样。这个jail将变成 mariadb.mwl.io

现在我们可以把一个用户区关进jail。

Jail 用户区

虽然你可以在jail中安装任何用户区组件,但jail所需要的只是基础系统。获取您所需FreeBSD版本的 base.txz 发行版集,并将其解压缩到jail的根目录中。

这是基本操作系统的完整安装。如果需要其他分发集,例如调试符号,请以相同的方式提取它们。

如果你已经构建了自己的FreeBSD基础系统,你可以在jail里安装它:

jail还需要支持目录和由安装过程创建的各种碎片,而不是由 make installworld 创建的。make distribution 命令创建这些文件。不过,如果您已经有了这些目录和文件,请不要重新运行 make distribution :它将覆盖任何本地更改。不要忘记DESTDIR设置,除非您喜欢重置主机的配置!

您还可以构建一个自定义用户区,只使用足够运行单个程序的二进制文件,就像您构建传统chrooted程序一样。对我们大多数人来说,这是一项太多的工作,但如果你想打破 ldd(1) 并变得疯狂,别让我阻止你。

一旦你有了jail用户区,在 /etc/jail.conf 中告诉FreeBSD你的jail。

/etc/jail.conf

传统上,FreeBSD在 /etc/rc.conf 中配置jail。这很笨重。虽然FreeBSD仍然支持jails的 rc.conf 配置,但我建议使用更灵活的 /etc/jail.conf 。此文件不在UCL中,尽管它看起来像是UCL可以支持的东西。用名字定义每个jail。在jail名称后用括号括起jail参数。每个参数定义都以分号结尾。

许多jail参数都有等号,我们给参数赋值。在这里,我将参数路径设置为值/jaire/mariadb:

其他参数仅通过其存在来启用或禁用功能。在这里,我告诉这个jail打开 mount.devfs 功能:

Jail支持一大堆“挂载(mount)”参数,并为不同的文件系统提供子参数。此特定参数专门用于挂载devfs。

通过在特定参数前添加 no ,可以关闭jail的切换。如果我不想启用devfs,我不会关闭整个mount参数;我会在 devfs 前面放置 no

以下是我如何定义一个名为mariadb的jail:

参数 host.hostname 给出了jail的主机名。虽然jail的名字是 mariadb,但这个主机通过互联网主机名 mariadb.mwl.io 来标识自己。

IP地址在 ip4.addr 中。我已将地址203.0.113.51分配给这个jail。此IP必须首先在主机上。

jail的根目录放在 path 变量中。在这里,它被设置为 /jail/mariadb

几乎每个jail都需要访问 /dev 中的特定设备节点,这需要在jail中挂载devfs(见第13章)。使用 mount.devfs 设置启用devfs。jail默认只获得几个非常特定的设备节点。不受信任的用户有时可以使用设备节点逃离jail,因此在没有仔细研究的情况下不要添加其他设备。您可以允许其他设备节点使用自定义devfs规则集。使用devfs_ruleset jail.conf 参数为jail分配自定义devfs规则集。我强烈建议使用默认的jail devfs规则作为基础,并取消隐藏此jail所需的其他设备,而不是从头开始构建自定义的devfs规则集。

一个jail内的进程可以从父进程继承其环境的一部分。exec.clean 选项告诉 jail(8) 去掉除$TERM之外的所有环境。环境变量$HOME、$USER和$SHELL被设置为目标环境,通常是jail根帐户的目标环境。你几乎总是想要 exec.clean

exec.startexec.stop 选项告诉FreeBSD如何启动和停止jail。

jail内启动

Jails可以模拟一个完整的FreeBSD用户区,运行一个进程,或者介于两者之间的任何东西。您必须使用 exec.start jail.conf 参数来告诉FreeBSD在jail中运行哪个进程,或者使用persistent 参数来声明您希望jail存在,即使其中没有任何进程。在这里,我使用正常的FreeBSD启动脚本启动一个完整的FreeBSD用户区:

如果你只需要一个命令在jail中运行,你可以编写自己的启动脚本,并在jail启动时使用 exec.start 运行它。你的新jail还没有 rc.conf ,所以它不会启动任何额外的进程。

您可以设置 persistent 选项,而不是 exec.start 。这告诉FreeBSD,jail可以在没有任何进程运行的情况下存在。包括 persistentexec.start 意味着FreeBSD将为jail启动一个进程,但当进程停止运行时,jail不会自行关闭。

你可以告诉jail在用 exec.poststart 选项启动后运行一个额外的命令。一旦正常的 /etc/rc 启动过程(包括任何启用的包)完成,exec.poststart 中列出的任何命令或脚本都会在主机中运行。这使您可以编写脚本将jail粘在一起。

同样,您可以使用 exec.prestop 选项在停止jail之前在主机上运行命令。当系统管理员关闭jail时,主机首先运行此命令,然后jail运行正常的关机命令。

exec.stop 命令告诉FreeBSD在jail中运行什么命令来关闭jail。如果你正在模拟一个完整的jail,你可能会像上一节中的例子一样运行 /bin/sh /etc/rc.shutdown

Jail 默认设置

你会发现你的许多jail都有共同的设置。您可以在配置的前面定义这些设置。除非你覆盖这些设置,否则所有jail都将使用这些设置。在使用单一jail时,这似乎没有多大意义。

然而,考虑到这种配置,添加另一个jail就变成了包括括号在内的五行。

在数十个jail中,它省去了很多麻烦。

您可以覆盖jail定义中的默认值。如果我不想在jail中挂载devfs(5),我会为那个特定的jail设置 mount.nodevfs

jail.conf 变量

你可以在jail中使用变量替换。虽然你可以定义其中一些变量,但你也可以从jail的设置中提取一些。变量在双引号和无引号字符串中展开,但在单引号字符串中不展开。

在这里,我为包含我所有jail的目录定义了一个变量,并在监狱定义中使用它:

如果我必须将jail移动到新的文件系统或池中,我可以通过更改一个变量来更新jail.conf,而不是编辑每个定义。

参数作为变量

一旦定义了jail参数,就可以将其用作变量。每个jail至少有一个参数,名字。您可以使用这些参数进一步展开默认设置。

通过将全局默认路径设置为 $j/$name ,我消除了为每个单独的jail定义路径的需要。

您可以通过将参数括在大括号中来使用带句点的多术语参数。虽然这对 mount.devfs 等参数没有意义,但对 host.hostname 等每个jail都会用到的参数很有用。

我更喜欢把我的jail放在以较短名称命名的目录中,而不是主机名,但请随意放纵自己的偏见。

将参数和变量与连贯的目录布局相结合,可以将每个jail定义压缩到一个配置语句中。

测试和配置 Jail

一旦你有了jail的文件,就把自己锁起来。运行 jail(8) 命令在jail内运行一个命令。您需要四个参数:路径、jail名称、主IP和要运行的命令:

以下示例,我使用 /jail/mariadb 中的jail,名为 mariadb ,IP地址为203.0.113.51,来运行命令 /bin/sh

运行 ls(1) 。您位于jail文件系统的根目录中。这个jail并不完全处于单用户模式,但除了 /bin/sh 之外,没有其他程序在这里运行。您可以进行一些基本的设置,但即使是 devfs(5) 也无法挂载。

是的,正常的jail启动过程会挂载 /dev ,但jail没有用户帐户、根密码、没有运行的守护进程,而且绝对没有可选的。在启动之前配置jail。

从主机那里偷东西

一些主机设置信息在jail中也很有用。你可以将这些信息从主机复制到监狱,但你必须从主机而不是jail复制。

每个jail都执行自己的DNS解析。您可能可以将主机的 /etc/resolv.conf 复制到jail中。 你的jail可能与主人共享同一时区。将主机的 /etc/localtime 复制到jail中,或在jail内运行tzsetup(8) 以选择新的时区。

创建 /etc/fstab

许多程序和脚本,包括 /etc/rc,都希望找到 /etc/fstab,如果它不在那里,就会发脾气。在真实的服务器中,要求 /etc/fstab 是完全合理的,但jail内的机器不需要文件系统表。创建一个空的文件系统表:

我不介意不愉快的节目。我只是不想听他们抱怨。

创建 /etc/rc.conf

您可以从主机进行所有jail管理,也可以通过SSH管理jail。您需要一个 /etc/rc.conf 条目用于sshd:

在创建此文件时添加所需的任何其他设置。如果你知道一些设置包需要,在需要之前设置它们也没什么坏处。

用户账户和root密码

您只能在jail内添加用户帐户和更改密码。使用 passwd(1) 设置根密码,并运行adduser(8) 为SSH添加至少一个用户。虽然SSH不是访问主机的唯一方式,但在大多数情况下要容易得多。

Jail 启动和关机

主机将每个jail视为一个独立的服务,就像 sshd(8) 、web服务器或任何其他守护进程一样。是的,每个jail可能运行一大堆需要独立管理的服务,但从主机的角度来看,每个jail都是一个包含一组进程的单一实体。这是host和jail分离的一部分。

使用 service(8) 启动、停止和重新启动jail。你需要提供一个额外的参数:jail的名称。FreeBSD在引导时自动启动它们,但一旦系统运行,您可以单独停止、启动和重新启动它们。让我们关闭我的数据库jail,再次启动它。

我可以使用restart命令,但在页面上看起来并没有那么令人印象深刻。

如果省略jail名称,service(8) 命令将影响FreeBSD在启动时启动的所有jail。

这使您能够连贯地重新初始化生产jail基础设施。

FreeBSD默认启动 /etc/jail.conf 中列出的所有jail。如第568页“启动时的jails”所述,您可以在 /etc/rc.conf 中更改。service(8) 命令可以控制不自动启动的jail,但您必须按名称指定它们。

Jail 依赖关系

如果你有一大堆jail,在 /etc/rc.conf 中列出开始顺序可能会变得乏味。您通常需要设置启动顺序来维护服务依赖关系。不过,您可以告诉一个jail它需要另一个jail,并使用 depend 选项,而不是在 rc.conf 中定义顺序:

在jail mariadb运行之前,jail httpd不会启动。depend 语句覆盖 rc.confjail_list 条目。

管理 Jails

虚拟化不会使系统管理任务消失;它只添加了执行典型sysadmin任务的选项。以下是其中一些选项。

查看 jails和 jail IDs

使用 jls(8) 查看系统上当前运行的所有jail:

每个jail都有一个唯一的jailID或JID。JID很像进程ID;虽然每个jail都有一个,但每次jail开始时,发放给jail的确切 JID 都会发生变化。我们将使用jail ID或名称来执行各种jail管理任务。

我们还可以获得每个jail的IP地址、主机名和jail文件的路径。你不会得到jail的名字,但我们这些使用基于jail名字的主机名的人很容易就能弄清楚。

Jail内进程

所有jail内的进程都会得到一个进程ID,就像任何其他Unix进程一样。进程ID并非jail独有;它们由host、jail和所有其他jail共享。您将找不到重复的进程ID。

jail内的进程显示在 ps(1) 中,带有 -J 标志。

进程ID 35002和35129是jail内的。

使用 -J 标志和jail名称使用 ps(1) 查看特定jail的进程:

使用 -J 0 可以从 ps(1) 输出中排除所有jail内的进程,使您更容易调试主机。

pgrep(1)pkill(1)killall(1) 等命令都接受 -j 参数来指定jail。如果您更喜欢使用 pgrep(1) 查看进程信息,请使用 pgrep -lfj和jail名称或JID:

为什么Sendmail在jail里运行?让我们杀了它。

再次运行pgrep表明Sendmail已死亡。

如果你想获取哪些进程在jail中运行的信息,这很有效,但有时你有一个进程ID,必须确定它属于哪个jail。这就是你需要 ps(1)-O 选项的地方。此选项支持一组关键字,这些关键字以常规命令行标志不支持的方式调整 ps(1) 的输出——具体来说,-O jail 为进程运行的jail的名称添加了一列。

这个进程正在jail mariadb 里进行。

在 jail 中执行命令

jexec(8) 命令允许jail主机管理员在jail内执行命令,而无需费心登录jail。这有助于保护jail主人的隐私感。当jail主人伯特打电话求助时,我不需要他的根密码,甚至不需要他的系统上的帐户。使用jexec需要知道jail的名字或JID。在这里,我使用主机的root帐户在jail mariadb中运行ps-ax:

此命令在jail内以root身份运行。不过,我可能想以另一个被jail的用户的身份运行该命令。给用户名加上 -U 标志。

好吧,那可不好。我希望伯特能运行我的数据库。让我们为他创建一个用户帐户。

这个jail现在有一个伯特的账户,使用他的首选用户名和一切。我已将其添加到jail内的wheel组中。记住,jail内的根访问并不等于主机上的根访问。这就是jail的全部意义。 我现在可以在jail里以那个用户的身份运行命令:

我被关在jail里了!具体来说,在伯特的jail里。

不过,这个被jail的过程会有点奇怪。过程保留其环境。在这种情况下,当我以用户身份运行时,我保留了我在非jail过程中的所有环境设置。这包括$SSH_AUTH_SOCK、我的IRC服务器设置等。我不想让这些东西出现在我被jail的环境中。如果我以伯特的身份登录,我想成为伯特。

要在进入jail之前剥夺你的环境,请使用jexec的 -l 标志。这模拟了一个干净的登录:

在jail里执行命令之前,你应该总是剥光你的环境吗?不,并非总是如此。这完全取决于你在做什么。

许多命令都支持在主机上运行它们,但目标是jail。请务必查看手册页以了解此类选项。一个很好的例子是 sysrc(8) ,它允许您使用 -j 指定一个jail。在这里,我在jail MariaDB上启用MariaDB。MariaDB选择继续使用MySQL命名约定,因此它通过 rc.conf 选项MySQL_enable启用:

这个jail现在已经准备好运行MariaDB了。

当然,除了没有安装MariaDB的部分。接下来我们来处理这个问题。

安装 jail 软件包

FreeBSD的软件包工具允许您从jail或主机中管理软件。如果主机管理员已为您分配了一个jail进行配置,您可能希望从jail管理包。Jail包的工作方式与任何其他FreeBSD主机上的包完全相同,如第15章所述。如果你负责整个系统,包括主机和该主机上的所有jail,你可能想从主机管理每个jail的包,而不是登录到每个jail。让我们花点时间在这件事上。

pkg(8) 命令的-j标志允许您指定要管理的jail。你需要一个参数,jail的名字或JID。在pkg(8) 子命令之前必须给出 -j 标志。在这里,我将MariaDB服务器安装在它的专用jail上:

请注意,pkg(8) 没有提供在jail中安装软件包的通知。它假设如果你使用 -j ,你就知道你在jail里工作。

当您从主机管理jail的包时,包工具不会安装在jail上。jail有自己的包数据库,存储在jail内,但jail无法直接使用该数据库。

不要在主机上管理包和在jail内管理包之间切换。选择一种方法并坚持下去。

升级 Jails

所以,你的host有无数个巴希里翁(bajillion ) jail,每个jail都致力于在完全隔离的情况下执行自己的任务。这很了不起,直到你必须对所有主机应用安全补丁。如果你已经从源代码构建了FreeBSD,你需要在每个jail中安装一个新世界。不过,如果你正在运行版本,freebsd-update(8) (见第18章)可以处理jail。

你不能在jail里使用 freebsd-update(8) 。将jail与主机系统隔离开来的同样事情也不允许freebsd-update(8) 所需的一些功能。相反,您可以从主机更新jail。

每当您需要更新系统时,请在更新jail之前更新主机。主机运行的FreeBSD版本必须等于或高于任何jail。

首先将 /etc/freebsd-update.conf 复制到备用文件,如 /etc/jail-freebsd-update.conf 。删除jail上未安装的所有组件。Jails没有内核,而且大多数都没有源代码,所以你可能会得到这样的条目:

当你运行 freebsd-update(8) 时,它会检查你运行的FreeBSD版本。它通过查询内核来实现这一点。如果你在FreeBSD 13.0系统上有FreeBSD 12.0 jail,更新程序会被混淆、阻塞,并因神秘的错误而死亡。您需要freebsd-update才能使用jail中安装的版本,而不是主机运行的版本。使用--current-run 选项告诉 freebsd-update(8) jail正在运行哪个版本。你必须使用jail的释放,包括补丁级别。虽然你可以很容易地从jail中提取这些信息,但我鼓励你让freebsd-update询问监狱当前运行的是哪个版本。使用 jexec(8) 查询监狱中运行的FreeBSD版本。

您还将使用 -b 标志告诉 freebsd-update(8) jail所在的目录。

在这里,我更新了jail的 test 。jail的文件在 /jail/test 里。我在backticks中使用 jexec(8) 命令来检查当前的FreeBSD版本。

一旦freebsd更新完成运行,请重新启动您的jail。它已经升级了。

许多人编写了脚本来运行 /etc/jail.conf 并升级他们所有的jail。如果你有不止几个jail,你会找到或写这样的剧本。

更多 jail 选项

你可以用各种方式定制jail。jail(8) 手册页包括当前的jail选项列表,但这里有一些我常用的功能。

您可以使用jid选项为每个jail分配一个永久ID,而不是让jail(8)分配jail ID:

securelevel 选项允许您在jail内提高安全级别(见第9章)。jail的安全级别永远不能低于host的安全级别。

您可以通过手动运行带有jail命令的 /etc/rc 来查看jail的启动消息。不过,这对常规故障排除来说很不方便。将jail的控制台消息定向到具有 exec.consolelog 选项的文件中。

除了挂载 /dev 之外,jail还可以拥有自己的 fdescfs(5)procfs(5) ,并带有 mount.fdescfsmount.procfs 选项。

Jailing 旧版 FreeBSD

根据我的经验,企业网络(enterprise network)这个词是“我们有很多没有人敢碰的古老东西”的同义词。jail可以帮助你应对其中一些系统。2014年,我在一家公司工作,该公司在FreeBSD 4.10上运行一个关键的定制PHP和MySQL应用程序。我不知道这台服务器是什么时候安装的,但FreeBSD 4.11是在2005年1月发布的,所以:在那之前。这个应用程序使用了Perl、PHP、OpenSSL等古老版本。

更糟糕的是,这个应用程序生活在一台重新调整用途的台式机上。配备标准配置的高品质台式硬盘。我在桌子下藏了一台相同年份的备用台式机,只是希望能安装FreeBSD 4.10。最合适的解决方案是重写或替换这个应用程序。几位系统管理员曾面临过这项任务,但都失败了。我决定将其虚拟化。FreeBSD 4.10在VMWare上运行不佳——是的,你可以找到 de(4)fxp(4) 驱动程序,但它们适用于这些卡十多年前的版本。我是这样把这个古老的FreeBSD系统关进jail的。

切换到单用户模式。卸载 /proc ——是的,FreeBSD 4仍然使用 /proc 。那是那些日子。阻塞整个文件系统,包括临时目录,如 /usr/obj/usr/ports/var/tmp 等。按照现代标准,它们根本不会占用太多空间,而且你无法知道以后可能需要什么文件。你可能会在互联网上找到一个旧的PHP 5.0.wever tarball,但这需要工作。

将tar文件复制到jail主机,并将其解压缩到jail目录中。

请确保使用 -p 标志来保留权限。

现在看看 /etc/rc.conf。 jail主机将处理所有网络功能,因此关闭任何设置IP地址或设置路由的语句。摆脱提供jail主机提供的服务(如时间、数据包过滤器和SSH)的守护进程。您被监禁的主机只需要直接支持应用程序的功能。在这个案子中,我需要Apache和MySQL。

考虑一下jail的 /etc/fstab 。您需要NFS文件系统还是其他特殊挂载?删除所有你不需要的东西。如果此应用程序需要 /proc,请为其提供jail选项 mount.procfs

删除旧的 /dev 。你不能在现代FreeBSD上使用FreeBSD 4设备节点。

配置主机以保护jail。虽然人们可以用Apache和PHP编写完美的应用程序,但即使是最狂热的Apache和MySQL粉丝也不会鼓励你将这些服务器的15年陈的版本暴露在互联网上。使用主机的数据包过滤器来保护jail。甚至不要考虑使用迁移主机的OpenSSH服务器。

由于接口分歧太大,您将无法在jail中使用一些FreeBSD 4命令。FreeBSD 4 ps(1) 无法成功查询现代FreeBSD内核。但是,您可以从主机 /rescue 复制大多数这些程序的静态链接版本,并将其复制到jail中。

就这么简单吗?不,不是真的。源系统越旧,问题就越多。我在这次迁移中遇到的大多数问题都意味着需要更改配置文件以适应新的底层文件系统。您需要执行通常的系统管理员调试。但这是在缺少设备驱动程序的系统上获得现代网络接口的一种方法,也是在FreeBSD 4系统上获得ZFS的唯一方法。

最后的Jail笔记

人们已经进化出许多使用jail的方式。完全涵盖所有这些功能几乎需要一本自己的书,但这里有一些提示。

您可以使用ZFS功能将数据集完全委托给jail管理员,以便jail所有者可以拍摄自己的快照并创建自己的子数据集。使用VIMAGE内核选项,您可以为jail提供自己的路由表。如果你很勇敢,nullfs(5) 可以让你回收操作系统安装并最大限度地减少磁盘利用率。您可以使用RCTL内核选项建立每个jail的资源限制。

如果你有很多jail,你可能更喜欢使用jail管理程序,比如iocage或ezjail。两者都可以在Ports Collection中找到。

成功使用jail需要自动化维护。每个jail都需要单独的安全补丁,既适用于用户区,也适用于已安装的软件包。您越能自动化此过程,就越有可能实际执行此类维护。我建议使用Ansible的jail模块,或者至少编写自己的shell脚本来应用补丁。

jail(8) 命令将允许您在没有命令行的情况下修改、创建和销毁jail。如果你正在做大量的jail工作,一定要阅读手册页。

现在让我们来看看FreeBSD的一些不太知名的角落。