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

# 17.4.传统 jail（厚 jail）

这些 jail 类似于真正的 FreeBSD 系统。它们差不多能像普通宿主系统一样管理，并可独立更新。

## 17.4.1. 创建传统 jail

原则上，jail 只需要主机名、根目录、IP 地址以及用户空间。

jail 的用户空间可从 FreeBSD 官方下载服务器获取。

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

```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
```

下载完成后，需要将其内容解压到 jail 的目录中。

执行以下命令将用户空间解压到 jail 目录：

```sh
# mkdir -p /usr/local/jails/containers/classic
# tar -xf /usr/local/jails/media/15.1-RELEASE-base.txz -C /usr/local/jails/containers/classic --unlink
```

将用户空间解压到 jail 目录后，需要复制时区和 DNS 服务器的配置文件：

```sh
# cp /etc/resolv.conf /usr/local/jails/containers/classic/etc/resolv.conf
# cp /etc/localtime /usr/local/jails/containers/classic/etc/localtime
```

文件复制完成后，下一步是执行以下命令更新到最新的补丁级别：

```sh
# freebsd-update -b /usr/local/jails/containers/classic/ fetch install
```

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

示例如下：

```sh
classic {
  # 启动与日志
  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.addr = 192.168.1.151;
  interface = em0;
}
```

执行以下命令启动该 jail：

```sh
# service jail start classic
```

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

## 17.4.2. 获取 jail 用户空间

上面展示的 fetch-and-extract 流程是填充 jail 根目录的传统方式，但不是唯一方式。同一用户空间也可通过 [bsdinstall(8)](https://man.freebsd.org/cgi/man.cgi?query=bsdinstall\&sektion=8\&format=html)、基本系统软件包或本地构建的源码树来安装。

[bsdinstall(8)](https://man.freebsd.org/cgi/man.cgi?query=bsdinstall\&sektion=8\&format=html) 提供了专用的 `jail` 目标，可在指定目录下为 [jail(8)](https://man.freebsd.org/cgi/man.cgi?query=jail\&sektion=8\&format=html) 设置新用户空间。它会获取并解压分发集而不安装内核，跳过了正常安装中的磁盘分区和网络步骤，因此是手动 fetch 与 [tar(1)](https://man.freebsd.org/cgi/man.cgi?query=tar\&sektion=1\&format=html) 序列的一条命令式、可脚本化的替代方案：

```sh
# bsdinstall jail /usr/local/jails/containers/classic
```

`jail` 目标默认安装基本分发（**base.txz**）。在 FreeBSD 15.0 及更高版本上，[bsdinstall(8)](https://man.freebsd.org/cgi/man.cgi?query=bsdinstall\&sektion=8\&format=html) 还可通过其 `pkgbase` 目标从基本系统软件包填充根目录；下面将介绍基于 pkg 的方法。

从 FreeBSD 15.0 开始，基本系统也以软件包形式发布，因此可完全使用 [pkg(8)](https://man.freebsd.org/cgi/man.cgi?query=pkg\&sektion=8\&format=html) 从 `FreeBSD-base` 存储库安装 jail 用户空间。通过全局 `--rootdir` 选项将 [pkg(8)](https://man.freebsd.org/cgi/man.cgi?query=pkg\&sektion=8\&format=html) 指向 jail 的根目录，并安装基本集的 jail 变体：

```sh
# pkg --rootdir /usr/local/jails/containers/classic install -r FreeBSD-base FreeBSD-set-base-jail
```

若要使用最小用户空间，可改用 `FreeBSD-set-minimal-jail`。以这种方式安装的 jail 此后通过 [pkg(8)](https://man.freebsd.org/cgi/man.cgi?query=pkg\&sektion=8\&format=html) 而非 [freebsd-update(8)](https://man.freebsd.org/cgi/man.cgi?query=freebsd-update\&sektion=8\&format=html) 来修补和升级；参见 [升级 pkgbase jail](/handbook/di-17-zhang-jail-yu-rong-qi/17.12.-geng-xin-jail.md)。

> **注意**
>
> 基本系统软件包在 FreeBSD 15.0 中是技术预览。`FreeBSD-base` 存储库在 **/etc/pkg/FreeBSD.conf** 中定义但默认禁用，因此需显式使用 `install -r FreeBSD-base` 选择它。目标根目录及其 **var/cache/pkg** 和 **var/db/pkg** 子目录可能需要先创建。传统的 **base.txz** 分发集在 FreeBSD 15.0 中仍然发布，因此 fetch-and-extract 方法在该版本上仍然可用。

从源码树构建的用户空间可通过 `DESTDIR` 变量安装到 jail 的根目录，这是在 jail 中运行 `-STABLE` 或自定义构建用户空间的方式。构建 world 后，将其及剩余的分发文件安装到 jail 目录：

```sh
# cd /usr/src
# make buildworld
# make installworld DESTDIR=/usr/local/jails/containers/classic
# make distribution DESTDIR=/usr/local/jails/containers/classic
```

`make distribution` 会在 jail 的 **/etc** 下安装默认配置文件，仅在填充 jail 时运行一次；在更新期间重复执行会覆盖 jail 内部的配置。要从源码更新此类 jail，请遵循与宿主相同的流程：使用相同的 `DESTDIR` 运行 `installworld`，通过指向 jail 根目录的 `etcupdate -D` 合并配置文件，并使用相同的 `DESTDIR` 通过 `make delete-old delete-old-libs` 移除过时文件和库，而不是使用 [freebsd-update(8)](https://man.freebsd.org/cgi/man.cgi?query=freebsd-update\&sektion=8\&format=html)。完整的源码更新流程请参见 [从源码更新 FreeBSD](/handbook/di-27-zhang-freebsd-geng-xin-yu-sheng-ji/27.1.-gai-shu.md)。

## 17.4.3. 将 jail 克隆为模板

一旦厚 jail 完全配置好——安装了软件包、启用了服务、设置了本地配置——它就可以作为模板镜像：一种可几乎瞬间部署大量相同 jail 的模板。

在 OpenZFS 上，这是通过对已配置 jail 的数据集进行快照和克隆来完成的。这要求源 jail 位于自己的数据集上，因此应使用 `zfs create` 创建，而不是上面传统 jail 流程中使用的 `mkdir`：

```sh
# zfs create -p zroot/jails/containers/classic
```

在快照之前停止 jail 以保证镜像一致性，然后对数据集进行快照并为每个新 jail 克隆一次：

```sh
# service jail stop classic
# zfs snapshot zroot/jails/containers/classic@template
# zfs clone zroot/jails/containers/classic@template zroot/jails/containers/web1
```

在 UFS 宿主上，改为复制已配置 jail 的目录树：

```sh
# cp -a /usr/local/jails/containers/classic /usr/local/jails/containers/web1
```

每个克隆都需要在 **/etc/jail.conf** 或 **jail.conf.d** 中拥有自己的条目，包含唯一的名称、路径和 IP 地址。由于上面示例中的 `path` 和 `host.hostname` 参数都是通过 `${name}` 从块名派生的，因此只有块名和地址不同：

```sh
web1 {
  # 启动与日志
  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.addr = 192.168.1.152;
  interface = em0;
}
```

模板镜像克隆不同于瘦 jail（参见 [瘦 jail](/handbook/di-17-zhang-jail-yu-rong-qi/17.5.-shou-jail.md)）。瘦 jail 保持共享只读基本系统并在模板处一次性维护，而每个模板镜像克隆都是一份完整的、可独立写入的副本，按照 [升级 jail](/handbook/di-17-zhang-jail-yu-rong-qi/17.12.-geng-xin-jail.md) 中所述独立修补和升级。OpenZFS 克隆最初作为与快照共享块的省空间写时复制副本，并保持对原始快照的依赖，直到 `zfs promote` 切断该依赖。要获得完全独立的副本，或将 jail 复制到另一个存储池或宿主，请使用 `zfs send` 通过管道传递给 `zfs receive`，而不是使用 `zfs clone`。


---

# Agent Instructions
This documentation is published with GitBook. GitBook is the documentation platform designed so that both humans and AI agents can read, navigate, and reason over technical content effectively. Learn more at gitbook.com.

## Querying This Documentation
If you need additional information that is not directly available in this page, you can query the documentation dynamically by asking a question.

Perform an HTTP GET request on the current page URL with the `ask` query parameter, and the optional `goal` query parameter:

```
GET https://book.bsdcn.org/handbook/di-17-zhang-jail-yu-rong-qi/17.4.-chuan-tong-jail-hou-jail.md?ask=<question>&goal=<endgoal>
```

`ask` is the immediate question: it should be specific, self-contained, and written in natural language.
`goal` is optional and describes the broader end goal you are ultimately trying to accomplish on behalf of the user. GitBook uses it to tailor the answer towards what is most useful for that goal.

The response will contain a direct answer to the question and relevant excerpts and sources from the documentation.

Use this mechanism when the answer is not explicitly present in the current page, you need clarification or additional context, or you want to retrieve related documentation sections.
