VNET + Thin Jail

在实践了不同的FreeBSD Jail技术之后,我在 cloud-atlas.dev 实践中,采用了FreeBSD VNET + Thin Jail 来构建基础环境:

  • 使用 NullFS Thin Jail尽可能节约磁盘空间,同时提供FreeBSD核心的升级同时共享给多个Jail

  • 选择 VNET 来构建完整的网络堆栈,以允许容器内部能够使用socks等网络底层技术

备注

本文记录完整部署步骤,也就是从主机激活Jail功能开始到通过辅助脚本快速启动jail

本文步骤也是 云图「架构」: VNET + Thin Jail

主机激活 jail

  • 执行以下命令配置在系统启动时启动 Jail :

激活jail
# 配置在系统启动时激活Jail功能
sysrc jail_enable="YES"

# 配置所有jails在后台启动
sysrc jail_parallel_start="YES"

Jail目录树

备注

Jail文件的位置没有规定,在FreeBSD Handbook中采用的是 /usr/local/jails 目录。

我为了方便管理和数据存储最大化,使用了 stripe 模式 ZFS 存储池 zdata 下的 /zdata/jails

注意,我使用了 jail_zfs 环境变量来指定ZFS位置,对应目录就是 /$jail_zfs

  • 设置环境变量:

设置 jail目录和release版本环境变量
export jail_dir="zdata/jails"
export bsd_ver="14.3"
# 在FreeBSD中root用户的shell默认是sh,所以调整 ~/.shrc
echo 'jail_dir="zdata/jails"' >> ~/.shrc
echo 'bsd_ver="14.3"' >> ~/.shrc
  • 创建jail目录结构

jail目录结构
zfs create $jail_dir
zfs create $jail_dir/media
zfs create $jail_dir/templates
zfs create $jail_dir/containers
  • 完成后检查 df -h 可以看到磁盘如下:

jail目录的zfs形式
Filesystem                   Size    Used   Avail Capacity  Mounted on
...
zdata                        6.1T     96K    6.1T     0%    /zdata
zdata/jails                  6.1T    104K    6.1T     0%    /zdata/jails
zdata/jails/media            6.1T     96K    6.1T     0%    /zdata/jails/media
zdata/jails/templates        6.1T     96K    6.1T     0%    /zdata/jails/templates
zdata/jails/containers       6.1T     96K    6.1T     0%    /zdata/jails/containers

备注

  • media 将包含已下载用户空间的压缩文件

  • templates 在使用 Thin Jails 时,该目录存储模板(共享核心系统)

  • containers 将存储jail (也就是容器)

快照(snapshot) 型 vs. 模板和NullFS

FreeBSD Thin Jail是基于 ZFS 快照(snapshot)模板和NullFS 来创建的 瘦 Jail:

  • 使用区别:

    • 快照(snapshot) 型: 快照只读的,不可更改的 - 这意味着 没有办法简单通过更新共享的ZFS snapshot来实现Thin Jail操作系统更新

    • 模板和NullFS 型: 可以通过 直接更新NullFS底座共享的ZFS dataset可以瞬间更新所有Thin Jail

  • 安装区别:

    • ZFS snapshot Thin Jail: 将FreeBSD Release base存放在 只读14.3-RELEASE@base 快照上

    • NullFS Thin Jail: 将FreeBSD Release base存放在 读写14.3-RELEASE-base 数据集上

通过结合Thin Jail 和 NullFS 技术可以创建节约文件系统存储开销(类似于 ZFS snapshot clone出来的卷完全不消耗空间),并且能够将Host主机的目录共享给 多个 Jail。

  • 创建 读写模式14.3-RELEASE-base (注意,大家约定俗成 @base 表示只读快照, -base 表示可读写数据集)

创建 读写模式14.3-RELEASE-base
zfs create -p $jail_dir/templates/$bsd_ver-RELEASE-base
  • 下载用户空间:

下载用户空间
fetch https://download.freebsd.org/ftp/releases/amd64/amd64/$bsd_ver-RELEASE/base.txz -o /$jail_dir/media/$bsd_ver-RELEASE-base.txz
  • 将下载内容解压缩到模版目录: 内容解压缩到模板目录( 14.3-RELEASE-base 后续不需要创建快照,直接使用)

解压缩
tar -xf /$jail_dir/media/$bsd_ver-RELEASE-base.txz -C /$jail_dir/templates/$bsd_ver-RELEASE-base --unlink
  • 将时区和DNS配置复制到模板目录:

将时区和DNS配置复制到模板目录
cp /etc/resolv.conf /$jail_dir/templates/$bsd_ver-RELEASE-base/etc/resolv.conf
cp /etc/localtime   /$jail_dir/templates/$bsd_ver-RELEASE-base/etc/localtime
  • 更新模板补丁:

更新模板补丁
freebsd-update -b /$jail_dir/templates/$bsd_ver-RELEASE-base/ fetch install

这里有一个疑惑,我的host主机 FreeBSD更新和升级14.3-RELEASE 升级到 14.3-RELEASE ,这时我使用 $bsd_ver-RELEASE/base.txz 下载的 14.3-RELEASE/base.txz ,解压缩以后使用上面的命令进行更新,输出的提示信息

更新模版补丁时候的输出信息显示是 14.3-RELEASE-p0
src component not installed, skipped
Looking up update2.FreeBSD.org mirrors... none found.
Fetching metadata signature for 14.3-RELEASE from update2.FreeBSD.org... done.
Fetching metadata index... done.
Inspecting system... done.
Preparing to download files... done.

No updates needed to update system to 14.3-RELEASE-p0.
No updates are available to install.

可以看到host主机对模版更新是自动按照 14.3-RELEASE 的元数据进行,而不是模版的 14.3-RELEASE 。那么jail模版现在是 14.3-RELEASE 么?

  • 创建一个特定数据集 skeleton (骨骼) ,这个 "骨骼" skeleton 命名非常形象,用意就是构建特殊的支持大量thin jial的框架底座

创建特定数据集 skeleton (骨骼)
zfs create -p $jail_dir/templates/$bsd_ver-RELEASE-skeleton
  • 执行以下命令,将特定目录移入 skeleton 数据集,并构建 baseskeleton 必要目录的软连接关系

特定目录移入 skeleton 数据集
mkdir -p /$jail_dir/templates/$bsd_ver-RELEASE-skeleton/home
mkdir -p /$jail_dir/templates/$bsd_ver-RELEASE-skeleton/usr
# 我单独创建一个docs目录用于后续将host主机的docs映射到jail中
mkdir -p /$jail_dir/templates/$bsd_ver-RELEASE-skeleton/docs

# etc目录包含发行版提供的配置文件
mv /$jail_dir/templates/$bsd_ver-RELEASE-base/etc /$jail_dir/templates/$bsd_ver-RELEASE-skeleton/etc
# local目录是空的
mv /$jail_dir/templates/$bsd_ver-RELEASE-base/usr/local /$jail_dir/templates/$bsd_ver-RELEASE-skeleton/usr/local
# tmp 目录是空的
mv /$jail_dir/templates/$bsd_ver-RELEASE-base/tmp /$jail_dir/templates/$bsd_ver-RELEASE-skeleton/tmp
# var 目录有很多预存目录,但是直接mv移动时有报错显示 var/empty 目录没有权限,这会导致目标目录破坏,所以改为rsync同步
rsync -avz /$jail_dir/templates/$bsd_ver-RELEASE-base/var /$jail_dir/templates/$bsd_ver-RELEASE-skeleton/var
mv /$jail_dir/templates/$bsd_ver-RELEASE-base/var /$jail_dir/templates/$bsd_ver-RELEASE-base/var.bak
# root 目录是管理员目录,有基本profile文件
mv /$jail_dir/templates/$bsd_ver-RELEASE-base/root /$jail_dir/templates/$bsd_ver-RELEASE-skeleton/root

备注

按照handbook,是执行 mv /$jail_zfs/templates/$bsd_ver-RELEASE-base/var /$jail_zfs/templates/$bsd_ver-RELEASE-skeleton/var 有如下报错:

报错
mv: /zdata/jails/templates/14.2-RELEASE-base/var/empty: Operation not permitted
mv: /zdata/jails/templates/14.2-RELEASE-base/var: Directory not empty
mv: /bin/rm /zdata/jails/templates/14.2-RELEASE-base/var: terminated with 1 (non-zero) status

这是因为 var/empty 目录没有权限删除: mv var/empty: Operation not permitted ,所以我采用 rsync 方法workround绕过(见上文)。

我之前有一个错误的步骤,我先采用了 mv var 报错以后,再使用 mv var var.bak 来修复,也就是执行了如下命令:

错误的mv方法 我发现目标var目录损坏了
mv /$jail_dir/templates/$bsd_ver-RELEASE-base/var /$jail_dir/templates/$bsd_ver-RELEASE-skeleton/var
# 这里有报错,导致源var目录残留,也就无法创建link
# 这个方法其实是错误的,因为我当时没有注意到目的var目录其实是残缺的,导致后续无法在jail上运行pkg和fetch等更新命令

# 我最初采用再次mv源var目录的方法,但是只是解决了link问题,上述目标var目录其实已经损坏无效了
cd /$jail_dir/templates/$bsd_ver-RELEASE-base/
mv var var.bak

所以必须使用类似 rsync 的命令先复制好var目录,然后再移除原来的var方便后续建立link

  • 执行以下命令创建软连接:

创建软连接
cd /$jail_dir/templates/$bsd_ver-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
# 这里增加一个docs目录用于存放数据(从Host主机映射到jail中)
ln -s skeleton/docs docs

警告

我在实践NullFS的Thin Jails,发现移动到 skeleton 目录下的 /etc 目录有一个子目录 /etc/ssl/certs 。这个证书目录下的文件是软链接到 ../../../usr/share/certs/trusted/ 目录下的证书文件。由于 /etc 目录移动后会导致这些相对链接失效,所以需要有一个修复软链接的步骤。

如果不执行这个证书软链接修复,则后续host主机上执行 pkg -j <jail_name> install <package_name> 会报错;而在jail中执行 pkg 命令会显示证书相关错误:

在jail中执行 pkg 命令会显示证书相关错误
Certificate verification failed for /C=US/O=Let's Encrypt/CN=E6
  • 在host上执行 修复 /etc/ssl/certs 目录下证书文件软链接

修复软链接
#cd /$jail_dir/templates/$bsd_ver-RELEASE-base/etc/ssl/certs
cd /$jail_dir/templates/$bsd_ver-RELEASE-skeleton/etc/ssl/certs

# 先保存一份原始列表记录
ls -lh > /tmp/fix_link.txt

# 生成unlink命令
ls | sed "s@^@unlink @" > /tmp/unlink.sh

# 生成fix命令
# 这里不能使用绝对路径链接,否则会报错 link: ffdd40f9.0: Cross-device link
# ls -lh | awk '{print $NF, $(NF-2)}' | cut -c 9- | tail -n +2 | sed  "s@^@link @" > /tmp/fix_link.sh
ls -lh | awk '{print $NF, $(NF-2)}' | tail -n +2 | sed 's@^@ln -s ../@' > /tmp/fix_link.sh

# 检查一下 /tmp/fix_link.sh 是否满足要求
# 没有问题在执行以下2条命令

sh /tmp/unlink.sh
sh /tmp/fix_link.sh

备注

我最初是在运行的NullFS thin jail上执行 Jail环境初始化 发现报错:

安装报错
Updating FreeBSD repository catalogue...
pkg: An error occured while fetching package: No error
pkg: An error occured while fetching package: No error
repository FreeBSD has no meta file, using default settings
pkg: An error occured while fetching package: No error
pkg: An error occured while fetching package: No error
pkg: An error occured while fetching package: No error
pkg: An error occured while fetching package: No error
Unable to update repository FreeBSD
Updating FreeBSD-kmods repository catalogue...
pkg: An error occured while fetching package: No error
pkg: An error occured while fetching package: No error
repository FreeBSD-kmods has no meta file, using default settings
pkg: An error occured while fetching package: No error
pkg: An error occured while fetching package: No error
pkg: An error occured while fetching package: No error
pkg: An error occured while fetching package: No error
Unable to update repository FreeBSD-kmods
Error updating repositories!

在jail内部尝试运行 pkg install sudo ,发现需要更新 pkg ,但是似乎 /usr/src 目录导致错误:

在jail内部安装报错
root@dev:/ # pkg install sudo
The package management tool is not yet installed on your system.
Do you want to fetch and install it now? [y/N]: y
Bootstrapping pkg from pkg+https://pkg.FreeBSD.org/FreeBSD:14:amd64/quarterly, please wait...
Certificate verification failed for /C=US/O=Let's Encrypt/CN=E6
0810A54FD11D0000:error:16000069:STORE routines:ossl_store_get0_loader_int:unregistered scheme:/usr/src/crypto/openssl/crypto/store/store_register.c:237:scheme=file
0810A54FD11D0000:error:80000002:system library:file_open:No such file or directory:/usr/src/crypto/openssl/providers/implementations/storemgmt/file_store.c:267:calling stat(/etc/ssl/certs/4042bcee.0)
0810A54FD11D0000:error:16000069:STORE routines:ossl_store_get0_loader_int:unregistered scheme:/usr/src/crypto/openssl/crypto/store/store_register.c:237:scheme=file
...
0810A54FD11D0000:error:0A000086:SSL routines:tls_post_process_server_certificate:certificate verify failed:/usr/src/crypto/openssl/ssl/statem/statem_clnt.c:1890:
pkg: Attempted to fetch pkg+https://pkg.FreeBSD.org/FreeBSD:14:amd64/kmods_quarterly_3/Latest/pkg.pkg
pkg: Attempted to fetch pkg+https://pkg.FreeBSD.org/FreeBSD:14:amd64/kmods_quarterly_3/Latest/pkg.txz
pkg: Error: Authentication error
A pre-built version of pkg could not be found for your system.

原来是 NullFS 的Thin Jail构建的移动 /etc 目录到 skeleton/etc 之后,所有在 /etc/ssl/certs 目录下原先的软连接到 ../../../usr/share/certs/trusted/ 目录下的证书的连接全部失效了。非常奇怪:

/etc/ssl/certs 目录下软连接失效
root@dev:/etc/ssl/certs # ls -lh
total 75
lrwxr-xr-x  1 root wheel   56B Jun  6 16:33 002c0b4f.0 -> ../../../usr/share/certs/trusted/GlobalSign_Root_R46.pem
lrwxr-xr-x  1 root wheel   57B Jun  6 16:33 0179095f.0 -> ../../../usr/share/certs/trusted/BJCA_Global_Root_CA1.pem
...
lrwxr-xr-x  1 root wheel   82B Jun  6 16:33 ff34af3f.0 -> ../../../usr/share/certs/trusted/TUBITAK_Kamu_SM_SSL_Kok_Sertifikasi_-_Surum_1.pem
lrwxr-xr-x  1 root wheel   62B Jun  6 16:33 ffdd40f9.0 -> ../../../usr/share/certs/trusted/D-TRUST_BR_Root_CA_2_2023.pem

root@dev:/etc/ssl/certs # ls -lh ../../../usr/share/certs/trusted/D-TRUST_BR_Root_CA_2_2023.pem
ls: ../../../usr/share/certs/trusted/D-TRUST_BR_Root_CA_2_2023.pem: No such file or directory

root@dev:/etc/ssl/certs # ls -lh ../../../
total 51
drwxr-xr-x  30 root wheel  106B Jun 15 17:27 etc
drwxr-xr-x   2 root wheel    2B Jun 15 17:25 home
drwxr-x---   2 root wheel    8B Jun 15 17:58 root
drwxrwxrwt   6 root wheel    6B Jun 15 17:28 tmp
drwxr-xr-x   3 root wheel    3B Jun 15 17:26 usr
drwxr-xr-x  24 root wheel   24B Jun 15 17:27 var

root@dev:/etc/ssl/certs # ls -lh ../../../usr/share
ls: ../../../usr/share: No such file or directory

root@dev:/etc/ssl/certs # ls -lh ../../../usr
total 1
drwxr-xr-x  2 root wheel    2B Jun  6 15:31 local

root@dev:/etc/ssl/certs # cd ../../../
root@dev:/ # ls -lh
total 88
-rw-r--r--   1 root wheel  1.0K Jun  6 15:40 .cshrc
-rw-r--r--   1 root wheel  495B Jun  6 15:39 .profile
-r--r--r--   1 root wheel  6.0K Jun  6 16:17 COPYRIGHT
drwxr-xr-x   2 root wheel   49B Jun  6 15:40 bin
drwxr-xr-x  14 root wheel   69B Jun  6 16:17 boot
dr-xr-xr-x  10 root wheel  512B Jun 15 17:27 dev
lrwxr-xr-x   1 root wheel   12B Jun 15 17:27 etc -> skeleton/etc
lrwxr-xr-x   1 root wheel   13B Jun 15 17:27 home -> skeleton/home
drwxr-xr-x   4 root wheel   78B Jun  6 15:55 lib
drwxr-xr-x   3 root wheel    5B Jun  6 15:38 libexec
drwxr-xr-x   2 root wheel    2B Jun  6 15:31 media
drwxr-xr-x   2 root wheel    2B Jun  6 15:31 mnt
drwxr-xr-x   2 root wheel    2B Jun  6 15:31 net
dr-xr-xr-x   2 root wheel    2B Jun  6 15:31 proc
drwxr-xr-x   2 root wheel  150B Jun  6 15:51 rescue
lrwxr-xr-x   1 root wheel   13B Jun 15 17:27 root -> skeleton/root
drwxr-xr-x   2 root wheel  150B Jun  6 16:03 sbin
drwxr-xr-x   8 root wheel    8B Jun 15 17:26 skeleton
lrwxr-xr-x   1 root wheel   11B Jun  6 15:31 sys -> usr/src/sys
lrwxr-xr-x   1 root wheel   12B Jun 15 17:27 tmp -> skeleton/tmp
drwxr-xr-x  13 root wheel   14B Jun 15 17:27 usr
lrwxr-xr-x   1 root wheel   12B Jun 15 17:27 var -> skeleton/var
drwxr-xr-x  24 root wheel   24B Jun  6 15:31 var.bak

明白了,原来是 14.2-RELEASE-base/etc 被移动到 14.2--RELEASE-skeleton/etc
而这个 skeleton 被挂载到 /skeleton 目录,这导致 /etc 目录变成了 /skeleton/etc
这样对于 /etc/ssl/certs 目录就变成了 /skeleton/etc/ssl/certs 目录
此时 /skeleton/etc/ssl/certs 目录原先 ../../../ 表示的根目录变成了 /skeleton 目录,就找不到对应 /usr/share 目录
需要修订这个相对软连接,改为绝对路径的软连接

root@dev:/ # cd /
root@dev:/ # cd skeleton/etc/ssl/certs/
root@dev:/skeleton/etc/ssl/certs # pwd
/skeleton/etc/ssl/certs

原因找到了,是因为原先 /etc/ssl/certs/ 目录下的软链接都是相对链接,当 /etc 目录被移动到 skeleton 目录下之后,这个相对软链接就失效了。所以就有了上述修复脚本来完成软链接修正。

修复以后 skeleton/etc/ssl/cets/ 目录下的软链接应该类似如下:

修复以后的软链接
...
lrwxr-xr-x  1 root wheel   85B Jun 15 22:08 ff34af3f.0 -> ../../../../usr/share/certs/trusted/TUBITAK_Kamu_SM_SSL_Kok_Sertifikasi_-_Surum_1.pem
lrwxr-xr-x  1 root wheel   65B Jun 15 22:08 ffdd40f9.0 -> ../../../../usr/share/certs/trusted/D-TRUST_BR_Root_CA_2_2023.pem
  • skeleton 就绪之后,需要将数据复制到 jail 目录(如果是UFS文件系统),对于ZFS则非常方便使用快照:

创建skeleton快照,然后再创建快照的clone(jail)
zfs snapshot $jail_dir/templates/$bsd_ver-RELEASE-skeleton@base
# 假设这里创建名为dev的jail
jail_name=dev
zfs clone $jail_dir/templates/$bsd_ver-RELEASE-skeleton@base $jail_dir/containers/$jail_name
  • 现在可以看到相关ZFS数据集如下:

ZFS数据集显示jail存储
Filesystem                                     Size    Used   Avail Capacity  Mounted on
zroot/ROOT/default                             192G    1.2G    191G     1%    /
...
zdata/jails                                    6.1T    112K    6.1T     0%    /zdata/jails
zdata/jails/media                              6.1T    197M    6.1T     0%    /zdata/jails/media
zdata/jails/templates                          6.1T    104K    6.1T     0%    /zdata/jails/templates
zdata/jails/containers                         6.1T     96K    6.1T     0%    /zdata/jails/containers
zdata/jails/templates/14.3-RELEASE-base        6.1T    446M    6.1T     0%    /zdata/jails/templates/14.3-RELEASE-base
zdata/jails/templates/14.3-RELEASE-skeleton    6.1T    4.4M    6.1T     0%    /zdata/jails/templates/14.3-RELEASE-skeleton
zdata/jails/containers/dev                     6.1T    4.4M    6.1T     0%    /zdata/jails/containers/dev
  • 创建一个 base template的目录,这个目录是 skeleton 挂载所使用的根目录

创建 skeleton 挂载所使用的根目录
# 创建 dev 所使用的nullfs模板目录,这个目录就是jail的根PATH
# 和常规Jail仅命名 ${name} 不同,采用 ${name}-nullfs-base
mkdir -p /$jail_dir/$jail_name-nullfs-base

配置jail

备注

  • Jail的配置分为公共部分和特定部分,公共部分涵盖了所有jails共有的配置

  • 尽可能提炼出Jails的公共部分,这样就可以简化针对每个jail的特定部分,方便编写较稳维护

  • 创建所有jail使用的公共配置部分 /etc/jail.conf (使用了 VNET 模式配置):

所有jail使用的公共配置部分 /etc/jail.conf
# 这里 devfs_ruleset 和Linux Jail的4不同
devfs_ruleset=5;

# 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;

allow.mount;
allow.mount.devfs;

enforce_statfs = 1;

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

# NETWORK - VNET/VIMAGE
#ip4 = inherit;
interface = igc0bridge;
vnet;
vnet.interface = "${epair}b";
# common NETWORK config
$gateway = "192.168.7.101";
$bridge = "igc0bridge";
$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";

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

.include "/etc/jail.conf.d/*.conf";

备注

我实践发现,上述 jail.conf 配置中需要添加:

在jail.conf中添加 allow.mount 权限
allow.mount;
allow.mount.devfs;

enforce_statfs = 1;

如果没有添加上述3行配置,那么jail中 df -h 就只能看到根目录:

没有 配置配置允许挂载的时候
Filesystem                                  Size    Used   Avail Capacity  Mounted on
/zdata/jails/templates/14.3-RELEASE-base    6.1T    457M    6.1T     0%    /

而添加了允许挂载的权限之后才真的看到 devfs 被挂载上,而且 /skeleton 也被挂载上

配置配置允许挂载的时候
Filesystem                                  Size    Used   Avail Capacity  Mounted on
/zdata/jails/templates/14.3-RELEASE-base    6.1T    457M    6.1T     0%    /
/zdata/jails/containers/dev                 6.1T    860M    6.1T     0%    /skeleton
devfs                                       1.0K      0B    1.0K     0%    /dev
  • /etc/jail.conf.d/dev.conf 独立配置部分:

/etc/jail.conf.d/dev.conf
dev {
  # NETWORKS/INTERFACES
  $id = "253";
  $ip = "192.168.7.${id}/24";
}
  • 注意,这里配置引用了一个针对nullfs的fstab配置,所以还需要创建一个 /zdata/jails/dev-nullfs-base.fstab :

/zdata/jails/dev-nullfs-base.fstab
/zdata/jails/templates/14.3-RELEASE-base  /zdata/jails/dev-nullfs-base/         nullfs  ro  0 0
/zdata/jails/containers/dev               /zdata/jails/dev-nullfs-base/skeleton nullfs  rw  0 0
  • 最后启动 dev :

启动 dev
service jail start dev

通过 rexec dev 进入jail

  • 设置Jail dev 在操作系统启动时启动,修改 /etc/rc.conf :

/etc/rc.conf
jail_enable="YES"
jail_parallel_start="YES"
jail_list="dev"
jail_reverse_stop="YES"

脚本辅助配置jail

  • 写了一个简单的脚本帮助创建配置文件:

创建jail的辅助脚本
export jail_dir="zdata/jails"
export bsd_ver="14.2"

jail_name=$1
id=$2

zfs clone $jail_dir/templates/$bsd_ver-RELEASE-skeleton@base $jail_dir/containers/$jail_name
mkdir -p /$jail_dir/$jail_name-nullfs-base

cat << EOF > /$jail_dir/$jail_name-nullfs-base.fstab
/$jail_dir/templates/14.2-RELEASE-base  /$jail_dir/$jail_name-nullfs-base/         nullfs  ro  0 0
/$jail_dir/containers/$jail_name               /$jail_dir/$jail_name-nullfs-base/skeleton nullfs  rw  0 0
EOF

cat << 'EOF' > /etc/jail.conf.d/$jail_name.conf
JAIL_NAME {
  $id = "ID";
  $ip = "192.168.7.${id}/24";
}
EOF

sed -i '' "s@JAIL_NAME@$jail_name@" /etc/jail.conf.d/$jail_name.conf
sed -i '' "s@ID@$id@" /etc/jail.conf.d/$jail_name.conf

通过执行 ./jail_zfs.sh pg-1 111 就可以创建一个使用 192.168.7.111 为IP的名为 pg-1 的Jail