Skip to content

34.2 厚 Jail(Thick Jail)

34.2.1 编辑服务

使用文本编辑器编辑 /etc/rc.conf 文件,加入以下内容:

ini
jail_enable="YES"	# 启动 Jail 服务
jail_parallel_start="YES" # 并行启动 Jail 服务

jail_parallel_start="YES" 启用 Jail 并行启动;默认情况下 Jail 串行启动,设置此选项后所有容器将并行启动。

网络配置(cloned_interfacesbridge0epair0 等)将在下文“配置宿主机网络”小节中统一设置。

运行以下命令为 Jail 安装基本系统,建议使用 base.txz 解压安装,省去编译的时间。注意 Jail 的用户空间版本不能比宿主机更新(FreeBSD 内核可向后兼容旧版本的用户空间),建议与宿主机保持一致。FreeBSD 的内核和用户空间是一个整体(基本系统,又称世界),用户空间不一致可能导致兼容性问题。

34.2.2 获取基本系统

不建议将基本系统解压到 /usr/jail 中。应在其中创建子目录,将每个容器都单独放在其中的目录里面,如此方便管理。注意下载解压和编译两种方法 任选一种方法 进行安装即可,切勿重复安装。

34.2.2.1 解压安装方式

sh
# 创建 Jail 目录
# mkdir -p /usr/jail/myjail
# 获取基本系统 (FreeBSD 15 Release)
# fetch https://download.freebsd.org/releases/amd64/amd64/15.0-RELEASE/base.txz
# 解压文件到容器目录
# tar -xf base.txz -C /usr/jail/myjail

也可通过编译方法安装。

34.2.2.2 编译安装方式

sh
# 进入源码目录
# cd /usr/src
# 构建世界(编译基础系统)
# make buildworld
# 将编译好的系统安装到指定 Jail 目录
# make installworld DESTDIR=/usr/jail/myjail
# 生成配套的配置文件
# make distribution DESTDIR=/usr/jail/myjail

34.2.3 配置时间

沿用宿主机的时区和 DNS 配置,确保 Jail 内部网络和时间正常:

sh
# cp /etc/resolv.conf /usr/jail/myjail/etc/
# cp /etc/localtime /usr/jail/myjail/etc/

34.2.4 配置宿主机网络

警告

必须在本地控制台执行以下网络配置操作(修改网桥、物理网卡 IP、重启网络服务等),禁止通过 SSH 远程操作。若通过 SSH 执行,操作过程中网络中断将导致宿主机失联,无法继续完成配置。请做好数据备份和应急手段。

首先配置宿主机网络。创建网桥 bridge0 和虚拟以太网对 epair,供 VNET (Virtualized Network Stack 虚拟网络栈) 使用,然后将虚拟网卡 epair0a 挂载到网桥。编辑 /etc/rc.conf 文件:

ini
# 创建网桥和一对 epair 虚拟网卡
cloned_interfaces="bridge0 epair0"
# 把物理网卡 re0 和虚拟网卡宿主机端 epair0a 都加入网桥并启动
# 将原 ifconfig_re0 中的 IP 配置迁移到 bridge0 上,同时注释掉或删除 ifconfig_re0 的原有 IP 配置
# 否则将物理网卡加入网桥后,宿主机会失去网络连通性
ifconfig_bridge0="inet 192.168.1.100/24 addm re0 addm epair0a up"
# 确保 epair0a 处于启动状态
ifconfig_epair0a="up"

bridge0 是虚拟交换机 (Network Bridge) , epair0a 是虚拟交换机上的一个端口。

可将之视为一个虚拟交换机,其上插着一根无形的网线。水晶头插在交换机上。网线网桥侧端口称为 epair0a,容器侧称为 epair0b

epair 是由内核指定的固定前缀,后面接着代表第几对虚拟连接的数字。

若要更改网卡名称,可执行命令 ifconfig epair0a name newname 更改。为了避免名称混淆和混乱,不建议如此。

Jail VNET 网络拓扑结构如下:

sh
物理网络 (示例家用路由器 192.168.1.1)

┌──────▼────────────────────────────────────────┐
 宿主机 (Host)                                 │

  [ 物理网卡 re0 ]

  [ 虚拟交换机 bridge0 ] <───(桥接)            

  [ 虚拟网卡端 epair0a ]
└─────────┼─────────────────────────────────────┘
 (虚拟网线)
┌─────────┼─────────────────────────────────────┐
  [ 虚拟网卡端 epair0b ]

 Jail (192.168.1.120)                        │
└───────────────────────────────────────────────┘

配置好网络以后重启网络服务:

sh
# service netif restart

不建议在远程主机执行上述命令。请做好数据备份和应急手段。

34.2.5 配置容器网络

接下来配置容器网络,编写 Jail 配置文件 /etc/jail.conf(若不存在,请新建),对所有的容器生效,参考配置如下:

ini
sysvmsg=new;
sysvsem=new;
sysvshm=new;

exec.clean;
mount.devfs;

myjail {
    host.hostname = "myjail.local";
    path = "/usr/jail/myjail";
    vnet;
    vnet.interface = "epair0b";
    allow.raw_sockets = 1;
    exec.created = "ifconfig epair0b up";
    exec.start = "/bin/sh /etc/rc";
    exec.stop = "/bin/sh /etc/rc.shutdown";
}

配置中前三行允许在 Jail 内部使用 System V IPC(进程间通信)机制,包括共享内存、信号量和消息队列;

exec.clean 用于在容器启动时,让 exec.start 等命令在干净的环境中运行,而非沿用启动 Jail 时的环境变量;环境变量会被丢弃,仅保留以下变量:

变量设置方式
HOME设为目标登录用户的默认值
SHELL设为目标登录用户的默认值
TERM从当前环境中导入
USER设为目标登录用户名
PATH设为 /bin:/usr/bin

此外,目标登录用户所属登录分级的能力数据库中的环境变量也会被设置,JIDJNAMEJPATH 不会被设置。

mount.devfs 用于在容器的 /dev 目录挂载 devfs 文件系统,并应用默认规则集限制容器内可见的设备节点。

最后的 myjail {...} 用于创建 Jail 示例 myjail

第一行设置容器主机名;

第二行设置容器路径;

vnet; 启用 VNET 虚拟网络栈;

vnet.interface 设置容器网卡;

allow.raw_sockets = 1; 允许容器创建原始套接字,使 ping 等命令能够正常工作;FreeBSD Jail 默认的安全策略禁止容器直接创建原始套接字,而 ping 命令需要利用 Raw Socket 来发送 ICMP 报文。若未添加此配置,执行 ping 将提示 Operation not permitted

最后三行设定容器启动和停止时的行为;

exec.created 在宿主机环境中将 epair0b 接口设为 up 状态。此命令在 vnet.interface 将接口移入 Jail 之前执行,因此接口仍位于宿主机网络栈中。接口移入 Jail 后会保留 up 状态,确保 Jail 内的网络配置能够正常工作。

在容器内的 /etc/rc.conf 中设置静态 IP 地址,协议族设定为 inet (IPv4) ,将 IP 设定为 192.168.1.120,子网掩码设为 255.255.255.0,设置默认网关为 192.168.1.1,编辑容器内配置文件:/usr/jail/myjail/etc/rc.conf,添加如下内容:

ini
ifconfig_epair0b="inet 192.168.1.120 netmask 255.255.255.0"
defaultrouter="192.168.1.1"

34.2.6 启动容器

配置完成以后使用 service 命令启动:

sh
# service jail start myjail

启动以后使用 jls 命令查看,若容器创建成功,且正在运行,该容器将出现在列表中。

sh
$ jls
   JID  IP Address      Hostname                      Path
     1                  myjail.local                  /usr/jail/myjail

VNET 模式中,IP 地址由容器内部管理, Address 字段看不到 IP 是正常的。

常用管理命令如下:

命令解释
service jail start myjail启动容器 myjail
service jail restart myjail重启容器
service jail stop myjail停止容器
jls查看运行中的容器列表
jexec myjail sh进入容器命令行

执行 jexec myjail sh 进入容器命令行(此操作需要 Root 权限),成功后将看到命令提示符 #,此时可输入命令操作容器。

若已按照前面的方法允许容器创建原始套接字,可使用 ping example.com 确认已经连接到互联网:

sh
# ping example.com
PING example.com (104.20.23.154): 56 data bytes
64 bytes from 104.20.23.154: icmp_seq=1 ttl=47 time=95.063 ms
64 bytes from 104.20.23.154: icmp_seq=3 ttl=47 time=94.726 ms
^C
--- example.com ping statistics ---
4 packets transmitted, 2 packets received, 50.0% packet loss
round-trip min/avg/max/stddev = 94.726/94.895/95.063/0.169 ms

34.2.7 测试容器

首先安装包管理器,执行 pkg 命令,遇到提示 Do you want to fetch and install it now? [y/N]: 选择 y

若安装成功,将得到类似输出:

sh
Bootstrapping pkg from pkg+https://pkg.FreeBSD.org/FreeBSD:15:amd64/quarterly, please wait...
Verifying signature with trusted certificate pkg.freebsd.org.2013102301... done
[myjail.local] Installing pkg-2.6.2_1...
[myjail.local] Extracting pkg-2.6.2_1: 100%
pkg: not enough arguments
Usage: pkg [-v] [-d] [-l] [-N] [-j <jail name or id>|-c <chroot path>|-r <rootdir>] [-C <configuration file>] [-R <repo config dir>] [-o var=value] [-4|-6] <command> [<args>]

For more information on available commands and options see 'pkg help'.

若网络受限无法安装,可按照本书前面章节方法更换软件源,或者使用 Ports 安装。

安装成功后,可执行 pkg update -f 强制重新获取软件仓库目录,然后执行 pkg ins nginx,执行 service nginx onestart 单次启动 nginx,成功后将得到如下输出:

sh
# service nginx onestart
Performing sanity check on nginx configuration:
nginx: the configuration file /usr/local/etc/nginx/nginx.conf syntax is ok
nginx: configuration file /usr/local/etc/nginx/nginx.conf test is successful
Starting nginx.

使用 ifconfig 命令确认 IP 地址,若完全按本节步骤进行,地址应为 192.168.1.120

sh
# ifconfig | grep 192
	inet 192.168.1.120 netmask 0xffffff00 broadcast 192.168.1.255

Ctrl+D 或输入 exit 可退出 Jail 容器的命令行。

回到宿主机环境,执行 fetch -o - http://192.168.1.120 | grep Welcome 可查看 NGINX 是否正常工作。

若容器网络通畅,且 Nginx 正常工作,将得到如下输出:

sh
$ fetch -o - http://192.168.1.120 | grep Welcome
-                                                      896  B 5646 kBps    00s
<title>Welcome to nginx!</title>
<h1>Welcome to nginx!</h1>