11.3 Qjail 管理工具
Jail 管理工具的技术选型:三种方案对比
Qjail 是用于部署 Jail 环境的工具,源自 ezjail 3.1,它在继承 ezjail 设计理念的基础上进行了功能扩展与优化。
常见的 Jail 管理工具包括 ezjail、Qjail 和 iocage,这三种工具代表了不同的技术路线与设计哲学。
ezjail 在 2015 年更新至 3.4.2 后未再进行关键更新,其 ports 更新依赖 portsnap,现已废弃,不再推荐用于新部署。
iocage 依赖 ZFS 文件系统的高级特性,因此使用 UFS 文件系统的用户无法使用,这在一定程度上限制了其适用范围。
Qjail 不存在这些方面的限制,具有更广泛的文件系统兼容性。
ezjail 不支持 Jail 的 vnet 功能,而 iocage 和 Qjail 支持该功能。vnet(Virtual Network)是 FreeBSD Jail 的网络虚拟化功能,可为每个 Jail 提供独立的网络协议栈。
ezjail 和 Qjail 使用 sh(Shell 脚本)编写,iocage 使用 Python 编写,不同的实现语言带来了不同的可维护性和扩展性特征。
下文中部署的 Jail 在概念上的结构如下图所示:

预留 Jail 的 IP 地址:网络接口配置
在 /etc/rc.conf 文件中添加如下配置。克隆接口 lo1 可将 Jail 网络与宿主机网络配置分开,增强隔离性。如要生成多个接口,应在同一行中以空格分隔描述,而不是另外创建多行,应如 cloned_interfaces="lo1 lo2"。分行书写时,只有第一行会生效:
重启所有网络接口以应用配置:
lo1 将获得 10 个 IP 地址,其中 1-9 号 IP 将用于分配给各个 Jail。
安装 Qjail 工具
使用 pkg 安装 Qjail:
或者使用 Ports 安装:
设置 qjail 服务开机自启动:
部署 Qjail 使用的目录结构
在使用 Qjail 之前,首先需要部署 Qjail 所使用的目录结构,可通过以下两种方式完成:
附录:从官方镜像站自动下载
此时 Qjail 会从 FreeBSD 官网下载 base.txz 文件,示例输出如下:
附录:从境内镜像站下载
由于境内网络访问限制,也可以使用镜像站手动下载,以中国科学技术大学镜像为例。使用 freebsd-version 命令可确认宿主机的 FreeBSD 版本,Qjail 要求文件版本与宿主机一致。以下示例为 FreeBSD amd64 15.0:
部署好 Qjail 的目录结构后 /usr/jails 目录下会自动生成 sharedfs、template、archive、flavors 四个目录,这四个目录构成了 Qjail 的核心文件系统架构:
sharedfs 包含一份只读的操作系统可执行文件库,通过 nullfs(一种特殊的文件系统,用于在同一主机的不同位置挂载同一文件系统)挂载,在各个 Jail 之间共享,以节省存储空间
template 包含操作系统的配置文件模板,将被复制到每个 Jail 的基本文件系统中,作为新 Jail 的初始配置
archive 保存 jail archive 命令产生的存档文件,用于 Jail 的备份与恢复
flavors 包含系统风格(flavors)和用户创建的自定义风格,其实就是自己定义的配置文件集合,用于快速定制新 Jail 的配置
部署 jail
创建名为 jail1 的 Jail,指定网络接口和 IPv4 地址:
-n指定使用 lo1 作为网络接口-4指定 IPv4 地址
生成 jail1 后,/usr/jails/ 目录下会创建 jail1 目录(/usr/jails/jail1/)用于保存对应文件。
可以在前述的 flavors 目录中创建自定义配置文件,以便在部署新的 Jail 时自动复制。例如,新建 /usr/jails/flavors/default/usr/local/etc/pkg/repos/FreeBSD.conf,则之后创建的 Jail 会自动复制该文件:
建立 jail2 后,自动建立 /usr/jails/jail2/usr/local/etc/pkg/repos/FreeBSD.conf,即修改了之后所有 Jail 的默认 pkg 镜像。但对应 jail1 并没有生成这个文件,因为生成 jail1 时,还没有在 flavors 目录中写入相应文件。
Qjail 基本用法
列出 Qjail 管理的 Jail:
启用 Jail:
停止 Jail:
重启 Jail:
进入 Jail 控制台:
进入 Jail 控制台后,将以 Jail 中的 root 账户身份操作(无需输入密码)。由于 Jail 可能开启对外服务,为安全起见,建议设置 root 账户密码。
备份 Jail:
从备份中恢复 Jail:
删除 Jail:
更新 Jail
下面更新 Jail 的部分不针对单个 Jail,而是针对所有 Jail,因为这些文件通过 nullfs 共享一份。
更新 Jail 中的基本系统
更新 sharedfs 中的文件:
更新 ports
这里有 -p(小写)、-P(大写)两个选项,-p(小写)使用 portsnap 更新 jail 的 ports tree。-P(大写)使用宿主机的 ports 更新 jail 的 ports。若主机已有 ports,则建议使用 -P(大写),避免重复下载 ports:
更新系统源代码
更新过程
完整的更新流程如下。更新源代码树可通过 git 或 svn 命令完成,更新 Ports 树可通过 git 或 portsnap 命令完成:
jail 设置
Qjail 提供 qjail config 命令以对每个 jail 进行定制化配置。由于 Jail 的核心配置参数在其运行状态下无法安全地进行修改,运行该命令前须先停用目标 Jail。
qjail config 命令提供丰富的配置选项,以下列出几个常用参数,完整说明请参考手册页,手册页是获取命令完整技术文档的权威来源。
qjail -- Utility for deployment of jail environments 备份。官方手册提供完整命令参数说明,是 Qjail 使用的权威技术文档。
-h
-h为 jail1 快速配置 ssh 服务:
该命令会快速开启 jail1 的 ssh 服务,新建一个 wheel 组用户,用户名和密码同 jail 名,首次用这个用户登录要求修改密码。也可以在登录 jail 控制台后,自行配置 sshd 服务。
-m、-M
-m、-M设置 jail1 为手动启动状态:
设置 jail1 需手动启动(manual 状态),qjail_enable="YES" 写入 /etc/rc.conf 后在系统启动时会自动启动各个 jail,设为手动启动后则不会在系统启动时自动启动相应的 jail,须用 qjail start jailname 启动。
对应小写的 -m 选项,有大写的 -M 选项,作用为关闭手动启动状态,即清除 manual 状态,可以在系统启动时自动启用 jail。Qjail 中有大量类似的选项,小写字母的选项启用某个功能,大写字母的选项关闭对应功能。如果下文中同时出现小写和大写的选项就不再过多作出说明。
-r、-R
-r、-R将 jail1 设为不允许启动(norun 状态):
该配置相当于禁用该 jail。
-y、-Y
-y、-Y启用 jail1 的 System V IPC(进程间通信)机制:
System V IPC 是一套经典的 UNIX 进程间通信机制,包括共享内存、信号量和消息队列,在 jail 中部署 PostgreSQL 等依赖共享内存和信号量的应用时,必须启用该选项。
网络设定
部分教程中会提到使用 qjail config -k jailname 打开 raw_sockets 功能来实现外网访问,这是不正确的理解。raw_sockets 仅为 ping 等工具所需,并非网络访问的必要条件。在 jail 中打开 raw_sockets 存在安全风险,这是 jail 环境默认的安全设计。因此除非确实需要在 jail 中使用 ping 之类的工具,否则不建议打开 raw_sockets 功能。
此时的 Jail 还不能连接网络,因为 Jail 绑定在 lo1 网络接口上,lo1 并不能直接访问外网,接下来通过 pf 设定网络,其中 em0 为外网接口。使用 ifconfig 命令可查找系统中的外网接口名称。
在 /etc/pf.conf 中写入配置。NAT(网络地址转换)可使 Jail 访问外部网络,端口重定向可使外部网络访问指定 Jail 的服务:
启动防火墙服务:
此时,绑定在 lo1 上的 jail 可以访问宿主机外网络,宿主机外网络可以通过宿主机 22 号端口连接 jail1 的 22 号端口。
示例:部署 PostgreSQL Jail
假设已经如上文所述预留 Jail IP,并成功运行 qjail install 命令。
这里以 PostgreSQL 15 为例,其它版本也适用。
宿主机中操作
创建并配置 PostgreSQL Jail:
编辑 /etc/pf.conf 文件:
注意:直接向外提供 PostgreSQL 连接存在安全风险,应根据实际需要谨慎开启端口转发。
启动防火墙服务 pf:
进入名为 postgres 的 jail 的控制台:
Jail 控制台中的操作
下面命令皆在 Jail 控制台下运行,pkg 安装与否使用镜像请自行决定,若使用镜像可以在 Jail 控制台中如同宿主机般进行设置,请参考相关文章。
使用 pkg 安装 PostgreSQL:
或者使用 Ports 安装:
配置 PostgreSQL:
此处使用 initdb 而非安装时提示的 /usr/local/etc/rc.d/postgresql initdb,目的是避免在设置数据库密码时反复修改 pg_hba.conf 文件。下面对各选项进行简要说明:
-A为本地用户指定在pg_hba.conf中使用的默认认证方法-E选择模板数据库的编码-W让 initdb 提示要求为数据库超级用户给予一个口令-D指定数据库集簇应该存放的目录
至此 PostgreSQL 服务已经可以运行。
如果在上述过程中未使用 qjail config -y postgres 命令开启 SysV IPC,可能会出现如下错误:
初始化数据库集簇时的错误

启动 PostgreSQL 时的错误

此时在宿主机控制台下执行 qjail config -y postgres 即可修正错误,具体如下:
再次进入 Jail 的控制台就可以正常初始化数据库集簇和运行 PostgreSQL 服务了。
课后习题
使用 Qjail 部署两个 PostgreSQL 数据库 Jail,配置数据隔离与共享基础系统,并验证两个数据库间的隔离性。
修改 Qjail 的 flavor 机制,自定义一个新 flavor 并应用于新 Jail,并将其贡献至 Ports。
使用 AI 自行构建一个 Jail 管理工具,实现 Qjail 的既有功能。
最后更新于