17.5.瘦 jail

尽管 Thin 1001 使用与 Thick 1002 相同的技术,但创建过程是不同的。Thin 1003 可以使用 OpenZFS 快照或使用模板和 NullFS 创建。使用 OpenZFS 快照和使用 NullFS 的模板相对于经典 1004 有一定优势,例如能够更快地从快照创建它们,或者能够使用 NullFS 更新多个 1005。

创建一个瘦Jail,使用 OpenZFS 快照

由于 FreeBSD 和 OpenZFS 之间的良好集成,使用 OpenZFS 快照创建新的瘦Jail非常容易。

要使用 OpenZFS 快照创建一个瘦Jail,第一步是创建一个模板。

模板将仅用于创建新的jail。因此,它们是以“只读”模式创建的,以便使用不可变的基础创建jail。

要为模板创建数据集,请执行以下命令:

# zfs create -p zroot/jails/templates/13.2-RELEASE

然后执行以下命令下载用户空间:

# fetch https://download.freebsd.org/ftp/releases/amd64/amd64/13.2-RELEASE/base.txz -o /usr/local/jails/media/13.2-RELEASE-base.txz

下载完成后,需要执行以下命令在模板目录中提取内容:

# tar -xf /usr/local/jails/media/13.2-RELEASE-base.txz -C /usr/local/jails/templates/13.2-RELEASE --unlink

将用户空间提取到模板目录中后,需要执行以下命令将时区和 DNS 服务器文件复制到模板目录中:

# cp /etc/resolv.conf /usr/local/jails/templates/13.2-RELEASE/etc/resolv.conf
# cp /etc/localtime /usr/local/jails/templates/13.2-RELEASE/etc/localtime

接下来要做的事情是通过执行以下命令更新到最新的补丁级别:

# freebsd-update -b /usr/local/jails/templates/13.2-RELEASE/ fetch install

更新完成后,模板就准备好了。

要从模板创建一个 OpenZFS 快照,请执行以下命令:

# zfs snapshot zroot/jails/templates/13.2-RELEASE@base

创建了 OpenZFS 快照以后,就可以使用 OpenZFS 克隆功能创建无限个jail。

创建一个名为 thinjail 的 Thin Jail,执行以下命令:

# zfs clone zroot/jails/templates/13.2-RELEASE@base zroot/jails/containers/thinjail

最后一步是配置jail。需要向配置文件/etc/jail.conf 或jail.conf.d 中添加一个条目,其中包含jail的参数。

一个例子是以下内容:

thinjail {
  # STARTUP/LOGGING
  exec.start = "/bin/sh /etc/rc";
  exec.stop = "/bin/sh /etc/rc.shutdown";
  exec.consolelog = "/var/log/jail_console_${name}.log";

  # PERMISSIONS
  allow.raw_sockets;
  exec.clean;
  mount.devfs;

  # HOSTNAME/PATH
  host.hostname = "${name}";
  path = "/usr/local/jails/containers/${name}";

  # NETWORK
  ip4 = inherit;
  interface = em0;
}

执行以下命令启动 jail:

# service jail start thinjail

可在Jail管理部分找到有关如何管理 jail 的更多信息。

17.5.2. 使用 NullFS 创建一个瘦 Jail。

通过使用精简的系统文件副本和使用 NullFS 以从主机系统有选择性地分享特定目录到 虚拟映像,可以创建 Thin 客户机。

第一步是创建数据集以保存模板,如果使用 OpenZFS,则执行以下命令:

# zfs create -p zroot/jails/templates/13.2-RELEASE-base

如果使用 UFS,则执行以下命令:

# mkdir /usr/local/jails/templates/13.2-RELEASE-base

然后执行以下命令下载用户空间:

# fetch https://download.freebsd.org/ftp/releases/amd64/amd64/13.2-RELEASE/base.txz -o /usr/local/jails/media/13.2-RELEASE-base.txz

下载完成后,需要通过执行以下命令将内容提取到模板目录中:

# tar -xf /usr/local/jails/media/13.2-RELEASE-base.txz -C /usr/local/jails/templates/13.2-RELEASE-base --unlink

在模板目录中提取用户空间后,需要通过执行以下命令将时区和 DNS 服务器文件复制到模板目录中:

# cp /etc/resolv.conf /usr/local/jails/templates/13.2-RELEASE-base/etc/resolv.conf
# cp /etc/localtime /usr/local/jails/templates/13.2-RELEASE-base/etc/localtime

将文件移动到模板后,下一步是通过执行以下命令更新到最新的补丁级别:

# freebsd-update -b /usr/local/jails/templates/13.2-RELEASE-base/ fetch install

除了基本模板外,还需要创建一个目录,该目录将位于 skeleton 处。一些目录将从模板复制到 skeleton。

在使用 OpenZFS 时,执行以下命令创建 skeleton 的数据集:

# zfs create -p zroot/jails/templates/13.2-RELEASE-skeleton

或者在使用 UFS 时

# mkdir /usr/local/jails/templates/13.2-RELEASE-skeleton

然后创建 skeleton 目录。skeleton 目录将保存jail的本地目录。

执行以下命令来创建目录:

# mkdir -p /usr/local/jails/templates/13.2-RELEASE-skeleton/home
# mkdir -p /usr/local/jails/templates/13.2-RELEASE-skeleton/usr
# mv /usr/local/jails/templates/13.2-RELEASE-base/etc /usr/local/jails/templates/13.2-RELEASE-skeleton/etc
# mv /usr/local/jails/templates/13.2-RELEASE-base/usr/local /usr/local/jails/templates/13.2-RELEASE-skeleton/usr/local
# mv /usr/local/jails/templates/13.2-RELEASE-base/tmp /usr/local/jails/templates/13.2-RELEASE-skeleton/tmp
# mv /usr/local/jails/templates/13.2-RELEASE-base/var /usr/local/jails/templates/13.2-RELEASE-skeleton/var
# mv /usr/local/jails/templates/13.2-RELEASE-base/root /usr/local/jails/templates/13.2-RELEASE-skeleton/root

创建符号链接到 skeleton 的下一步是执行以下命令:

# cd /usr/local/jails/templates/13.2-RELEASE-base/
# mkdir skeleton
# ln -s skeleton/etc etc
# ln -s skeleton/home home
# ln -s skeleton/root root
# ln -s ../skeleton/usr/local usr/local
# ln -s skeleton/tmp tmp
# ln -s skeleton/var var

有了 skeleton 准备好后,将需要将数据复制到 jail 目录中。

如果使用 OpenZFS,在执行以下命令时可以使用 OpenZFS 快照轻松地创建尽可能多的 jail。

# zfs snapshot zroot/jails/templates/13.2-RELEASE-skeleton@base
# zfs clone zroot/jails/templates/13.2-RELEASE-skeleton@base zroot/jails/containers/thinjail

在使用 UFS 时,可以通过执行以下命令使用 cp(1) 程序:

# cp -R /usr/local/jails/templates/13.2-RELEASE-skeleton /usr/local/jails/containers/thinjail

然后创建一个目录,在该目录中将挂载基础模板和骨架:

# mkdir -p /usr/local/jails/thinjail-nullfs-base

在 /etc/jail.conf 中添加一个 jail 条目,或者在 jail.conf.d 中添加一个文件,内容如下:

thinjail {
  # STARTUP/LOGGING
  exec.start = "/bin/sh /etc/rc";
  exec.stop = "/bin/sh /etc/rc.shutdown";
  exec.consolelog = "/var/log/jail_console_${name}.log";

  # PERMISSIONS
  allow.raw_sockets;
  exec.clean;
  mount.devfs;

  # HOSTNAME/PATH
  host.hostname = "${name}";
  path = "/usr/local/jails/${name}-nullfs-base";

  # NETWORK
  ip4.addr = 192.168.1.153;
  interface = em0;

  # MOUNT
  mount.fstab = "/usr/local/jails/${name}-nullfs-base.fstab";
}

然后按照以下步骤创建 /usr/local/jails/thinjail-nullfs-base.fstab 文件:

/usr/local/jails/templates/13.2-RELEASE-base  /usr/local/jails/thinjail-nullfs-base/ nullfs   ro          0 0
/usr/local/jails/containers/thinjail     /usr/local/jails/thinjail-nullfs-base/skeleton nullfs  rw  0 0

执行以下命令启动 jail:

# service jail start thinjail

17.5.3. 创建 VNET Jail

FreeBSD VNET Jails具有自己独特的网络堆栈,包括接口,IP 地址,路由表和防火墙规则。

创建 VNET jail的第一步是通过执行以下命令来创建桥接(4):

# ifconfig bridge create

输出应类似于以下内容:

bridge0

使用创建的 bridge,需要执行以下命令将其附加到 em0 接口:

# ifconfig bridge0 addm em0

要使此设置在重启后持久化,将以下行添加到/etc/rc.conf:

defaultrouter="192.168.1.1"
cloned_interfaces="bridge0"
ifconfig_bridge0="inet 192.168.1.150/24 addm em0 up"

下一步是按照上述指示创建jail。

可以使用经典的Jail(厚Jail)程序和瘦Jails程序。唯一会改变的是/etc/jail.conf 文件中的配置。

路径/usr/local/jails/containers/vnet 将作为创建的jail的示例。

以下是一个 VNET jail的配置示例:

vnet {
  # STARTUP/LOGGING
  exec.start = "/bin/sh /etc/rc";
  exec.stop  = "/bin/sh /etc/rc.shutdown";
  exec.consolelog = "/var/log/jail_console_${name}.log";

  # PERMISSIONS
  allow.raw_sockets;
  exec.clean;
  mount.devfs;
  devfs_ruleset = 5;

  # PATH/HOSTNAME
  path = "/usr/local/jails/containers/${name}";
  host.hostname = "${name}";

  # VNET/VIMAGE
  vnet;
  vnet.interface = "${epair}b";

  # NETWORKS/INTERFACES
  $id = "154"; 
  $ip = "192.168.1.${id}/24";
  $gateway = "192.168.1.1";
  $bridge = "bridge0"; 
  $epair = "epair${id}";

  # ADD TO bridge INTERFACE
  exec.prestart  = "ifconfig ${epair} create up";
  exec.prestart += "ifconfig ${epair}a up descr jail:${name}";
  exec.prestart += "ifconfig ${bridge} addm ${epair}a up";
  exec.start    += "ifconfig ${epair}b ${ip} up";
  exec.start    += "route add default ${gateway}";
  exec.poststop = "ifconfig ${bridge} deletem ${epair}a";
  exec.poststop += "ifconfig ${epair}a destroy";
}
代表Jail的 IP,必须是唯一的。

指的是之前创建的桥接。

17.5.4. 创建 Linux Jail

FreeBSD 可以在jail中使用 Linux 二进制兼容性和 debootstrap(8)运行 Linux。Jails没有内核。它们在主机的内核上运行。因此,需要在主机系统中启用 Linux 二进制兼容性。

要在启动时启用 Linux ABI,请执行以下命令:

# sysrc linux_enable="YES"

启用以后,可以通过执行以下命令而无需重启来启动。

# service linux start

接下来的步骤是根据上面的指示创建一个jail,例如在使用 OpenZFS 快照创建一个瘦的Jail时,但不执行配置。FreeBSD Linux jail需要一个将在下面详细说明的特定配置。

如果按上述说明创建了jail,执行以下命令来执行jail所需的配置并启动它:

# jail -cm \
    name=ubuntu \
    host.hostname="ubuntu.example.com" \
    path="/usr/local/jails/ubuntu" \
    interface="em0" \
    ip4.addr="192.168.1.150" \
    exec.start="/bin/sh /etc/rc" \
    exec.stop="/bin/sh /etc/rc.shutdown" \
    mount.devfs \
    devfs_ruleset=4 \
    allow.mount \
    allow.mount.devfs \
    allow.mount.fdescfs \
    allow.mount.procfs \
    allow.mount.linprocfs \
    allow.mount.linsysfs \
    allow.mount.tmpfs \
    enforce_statfs=1

要访问jail,需要安装 sysutils/debootstrap。

执行以下命令以访问 FreeBSD Linux jail:

# jexec -u root ubuntu

在 jail 中,执行以下命令安装 sysutils/debootstrap 并准备 Ubuntu 环境:

# pkg install debootstrap
# debootstrap jammy /compat/ubuntu

当进程完成并在控制台显示消息 Base system installed successfully 时,需要通过执行以下命令在主机系统上停止 jail:

# service jail onestop ubuntu

然后在 /etc/jail.conf 中为 Linux jail 添加一个条目:

ubuntu {
  # STARTUP/LOGGING
  exec.start = "/bin/sh /etc/rc";
  exec.stop = "/bin/sh /etc/rc.shutdown";
  exec.consolelog = "/var/log/jail_console_${name}.log";

  # PERMISSIONS
  allow.raw_sockets;
  exec.clean;
  mount.devfs;
  devfs_ruleset = 4;

  # HOSTNAME/PATH
  host.hostname = "${name}";
  path = "/usr/local/jails/containers/${name}";

  # NETWORK
  ip4.addr = 192.168.1.155;
  interface = em0;

  # MOUNT
  mount += "devfs     $path/compat/ubuntu/dev     devfs     rw  0 0";
  mount += "tmpfs     $path/compat/ubuntu/dev/shm tmpfs     rw,size=1g,mode=1777  0 0";
  mount += "fdescfs   $path/compat/ubuntu/dev/fd  fdescfs   rw,linrdlnk 0 0";
  mount += "linprocfs $path/compat/ubuntu/proc    linprocfs rw  0 0";
  mount += "linsysfs  $path/compat/ubuntu/sys     linsysfs  rw  0 0";
  mount += "/tmp      $path/compat/ubuntu/tmp     nullfs    rw  0 0";
  mount += "/home     $path/compat/ubuntu/home    nullfs    rw  0 0";
}

然后可以像往常一样使用以下命令启动 jail:

# service jail start ubuntu

可以使用以下命令访问 Ubuntu 环境:

# jexec ubuntu chroot /compat/ubuntu /bin/bash

更多信息可以在章节 Linux 二进制兼容性中找到。

17.5.5. 配置服务Jails

通过/etc/rc.conf 或 sysrc(8)完全配置了一个服务jail。基础系统服务是服务jail就绪的。它们包含一个配置行,可以启用网络或解除jail的其他限制。配置为不作为服务jail启动的基础系统服务,即使在/etc/rc.conf 中启用了,也就是在jail中不合理运行的服务。此类服务的一些示例是希望在启动或停止方法中挂载或卸载某些内容,或者仅配置某些内容,如路由、防火墙或类似内容。

第三方服务可能会具备服务jail功能,也可能不具备。要检查服务是否具备服务jail功能,可以使用以下命令:

# grep _svcj_options /path/to/rc.d/servicename

如果没有输出,则该服务未具备服务jail功能,或者不需要任何额外特权,如网络访问权限。

如果服务未具备服务jail功能,并且需要网络访问权限,则可以通过向 /etc/rc.conf 添加必要的配置使其具备服务能力。

# sysrc servicename_svcj_options=net_basic

对于所有可能的 _svcj_options 请参阅 rc.conf(5) 手册页。

要为给定服务启用服务 jail,服务需要停止,然后将 servicename_svcj 变量设置为是。要将 syslogd(8) 放入服务 jail,请使用以下命令序列:

# service syslogd stop
# sysrc syslogd_svcj=YES
# service syslogd start

如果 servicename_svcj 变量发生更改,则在更改之前必须停止服务。如果不停止,则 rc 框架将无法检测服务的正确状态,也无法执行所请求的操作。

服务 jail 仅通过 rc.conf(5) / sysrc(8) 和 service(8) 命令进行管理。如《Jail管理》中说明的 jls(8) 等jail实用工具可用于调查操作,但不应使用 jail(8) 命令来管理它们。

最后更新于

FreeBSD 中文社区