VNET + Thin Jail
在实践了不同的FreeBSD Jail技术之后,我在 cloud-atlas.dev 实践中,采用了FreeBSD VNET + Thin Jail 来构建基础环境:
使用 NullFS Thin Jail尽可能节约磁盘空间,同时提供FreeBSD核心的升级同时共享给多个Jail
选择 VNET 来构建完整的网络堆栈,以允许容器内部能够使用socks等网络底层技术
主机激活 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
设置环境变量:
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目录结构
zfs create $jail_dir
zfs create $jail_dir/media
zfs create $jail_dir/templates
zfs create $jail_dir/containers
完成后检查
df -h
可以看到磁盘如下:
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配置复制到模板目录:
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
数据集,并构建base
和skeleton
必要目录的软连接关系
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 /$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
命令会显示证书相关错误:
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
目录导致错误:
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则非常方便使用快照:
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数据集如下:
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 模式配置):
/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
配置中需要添加:
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
写了一个简单的脚本帮助创建配置文件:
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