> For the complete documentation index, see [llms.txt](https://handbook.bsdcn.org/llms.txt). Markdown versions of documentation pages are available by appending `.md` to page URLs; this page is available as [Markdown](https://handbook.bsdcn.org/di-17-zhang-jail-yu-rong-qi/17.5.-shou-jail.md).

# 17.5.瘦 jail

虽然瘦 jail 使用与厚 jail 相同的技术，但创建过程是不同的。瘦 jail 可通过 OpenZFS 快照或使用模板和 NullFS 创建。使用 OpenZFS 快照和模板结合 NullFS 相比传统的 jail 有一些优势，例如能更快速地从快照中创建，或者能通过 NullFS 更新多个 jail。

## 17.5.1. 使用 OpenZFS 快照创建瘦 jail

由于 FreeBSD 和 OpenZFS 的良好集成，通过 OpenZFS 快照创建新的瘦 jail 非常容易。

要通过 OpenZFS 快照创建瘦 jail，第一步是按照[设置 jail 目录结构](/di-17-zhang-jail-yu-rong-qi/17.3.-zhu-ji-pei-zhi-jail.md)中的说明创建 jail 目录树。

接下来，创建模板。模板仅用于创建新的 jail。因此，它们以“只读”模式创建，以便基于不可变的基础创建 jail。

要为模板创建数据集，执行以下命令：

```sh
# zfs create -p zroot/jails/templates/15.1-RELEASE
```

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

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

下载完成后，需要通过以下命令将内容解压到模板目录中：

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

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

```sh
# cp /etc/resolv.conf /usr/local/jails/templates/15.1-RELEASE/etc/resolv.conf
# cp /etc/localtime /usr/local/jails/templates/15.1-RELEASE/etc/localtime
```

接下来，执行以下命令更新到最新的补丁级别：

```sh
# freebsd-update -b /usr/local/jails/templates/15.1-RELEASE/ fetch install
```

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

要从模板创建 OpenZFS 快照，执行以下命令：

```sh
# zfs snapshot zroot/jails/templates/15.1-RELEASE@base
```

创建 OpenZFS 快照后，即可使用 OpenZFS 克隆功能创建无限多个 jail。

要创建名为 `thinjail` 的瘦 jail，执行以下命令：

```sh
# zfs clone zroot/jails/templates/15.1-RELEASE@base zroot/jails/containers/thinjail
```

最后一步是配置 jail。需要在配置文件 **/etc/jail.conf** 或 **jail.conf.d** 目录中添加包含该 jail 参数的条目。

例如，配置可能如下所示：

```sh
thinjail {
  # 启动/日志记录
  exec.start = "/bin/sh /etc/rc";
  exec.stop = "/bin/sh /etc/rc.shutdown";
  exec.consolelog = "/var/log/jail_console_${name}.log";

  # 权限
  allow.raw_sockets;
  exec.clean;
  mount.devfs;

  # 主机名/路径
  host.hostname = "${name}";
  path = "/usr/local/jails/containers/${name}";

  # 网络
  ip4 = inherit;
  interface = em0;
}
```

执行以下命令启动 jail：

```sh
# service jail start thinjail
```

有关如何管理 jail 的更多信息，请参阅[管理 jail](/di-17-zhang-jail-yu-rong-qi/17.10.-guan-li-jail.md)一节。

## 17.5.2. 使用 NullFS 创建瘦 jail

通过使用瘦 jail 技术并利用 NullFS 有选择性地共享主机系统中的特定目录，可减少系统文件的重复，从而创建瘦 jail。

第一步是创建用于保存模板的数据集。如果使用 OpenZFS，请执行以下命令：

```sh
# zfs create -p zroot/jails/templates/15.1-RELEASE-base
```

如果使用 UFS，请执行以下命令：

```sh
# mkdir /usr/local/jails/templates/15.1-RELEASE-base
```

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

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

下载完成后，需要通过以下命令将内容解压到模板目录中：

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

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

```sh
# cp /etc/resolv.conf /usr/local/jails/templates/15.1-RELEASE-base/etc/resolv.conf
# cp /etc/localtime /usr/local/jails/templates/15.1-RELEASE-base/etc/localtime
```

将文件移动到模板中后，接下来执行以下命令更新到最新的补丁级别：

```sh
# freebsd-update -b /usr/local/jails/templates/15.1-RELEASE-base/ fetch install
```

除了基础模板外，还需要创建目录来存放 `skeleton`。一些目录将从模板复制到 `skeleton` 中。

如果使用 OpenZFS，请执行以下命令来创建 `skeleton` 的数据集：

```sh
# zfs create -p zroot/jails/templates/15.1-RELEASE-skeleton
```

如果使用 UFS，请执行以下命令：

```sh
# mkdir /usr/local/jails/templates/15.1-RELEASE-skeleton
```

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

执行以下命令创建这些目录：

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

接下来，执行以下命令创建指向 `skeleton` 的符号链接：

```sh
# cd /usr/local/jails/templates/15.1-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，执行以下命令：

```sh
# zfs snapshot zroot/jails/templates/15.1-RELEASE-skeleton@base
# zfs clone zroot/jails/templates/15.1-RELEASE-skeleton@base zroot/jails/containers/thinjail
```

如果使用 UFS，可使用 [cp(1)](https://man.freebsd.org/cgi/man.cgi?query=cp\&sektion=1\&format=html) 程序，执行以下命令：

```sh
# cp -R /usr/local/jails/templates/15.1-RELEASE-skeleton /usr/local/jails/containers/thinjail
```

然后创建目录，用于挂载基础模板和 `skeleton`：

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

在 **/etc/jail.conf** 或 **jail.conf.d** 目录的文件中添加 jail 条目，如下所示：

```sh
thinjail {
  # 启动/日志记录
  exec.start = "/bin/sh /etc/rc";
  exec.stop = "/bin/sh /etc/rc.shutdown";
  exec.consolelog = "/var/log/jail_console_${name}.log";

  # 权限
  allow.raw_sockets;
  exec.clean;
  mount.devfs;

  # 主机名/路径
  host.hostname = "${name}";
  path = "/usr/local/jails/${name}-nullfs-base";

  # 网络
  ip4.addr = 192.168.1.153;
  interface = em0;

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

然后创建 **/usr/local/jails/thinjail-nullfs-base.fstab** 文件，内容如下：

```sh
/usr/local/jails/templates/15.1-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
```

**fstab** 文件控制 [mount\_nullfs(8)](https://man.freebsd.org/cgi/man.cgi?query=mount_nullfs\&sektion=8\&format=html) 如何在 jail 内部呈现基础模板和 skeleton。基础模板以只读（`ro`）方式挂载，使每个 NullFS jail 共享一份不可变的基本系统副本。每个 jail 的 skeleton 以读写（`rw`）方式挂载，这是每个 jail 存放自己可写 **/etc**、**/var**、**/usr/local** 等本地目录的地方。由于所有 jail 共享同一份只读基础模板，更新该模板可同时更新所有 NullFS jail，这与必须分别独立更新的 OpenZFS 克隆不同。

执行以下命令启动 jail：

```sh
# service jail start thinjail
```
