34.2 厚 Jail(Thick Jail)
34.2.1 编辑服务
使用文本编辑器编辑 /etc/rc.conf 文件,加入以下内容:
jail_enable="YES" # 启动 Jail 服务
jail_parallel_start="YES" # 并行启动 Jail 服务jail_parallel_start="YES" 启用 Jail 并行启动;默认情况下 Jail 串行启动,设置此选项后所有容器将并行启动。
网络配置(cloned_interfaces、bridge0、epair0 等)将在下文“配置宿主机网络”小节中统一设置。
运行以下命令为 Jail 安装基本系统,建议使用 base.txz 解压安装,省去编译的时间。注意 Jail 的用户空间版本不能比宿主机更新(FreeBSD 内核可向后兼容旧版本的用户空间),建议与宿主机保持一致。FreeBSD 的内核和用户空间是一个整体(基本系统,又称世界),用户空间不一致可能导致兼容性问题。
34.2.2 获取基本系统
不建议将基本系统解压到 /usr/jail 中。应在其中创建子目录,将每个容器都单独放在其中的目录里面,如此方便管理。注意下载解压和编译两种方法 任选一种方法 进行安装即可,切勿重复安装。
34.2.2.1 解压安装方式
# 创建 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 编译安装方式
# 进入源码目录
# cd /usr/src
# 构建世界(编译基础系统)
# make buildworld
# 将编译好的系统安装到指定 Jail 目录
# make installworld DESTDIR=/usr/jail/myjail
# 生成配套的配置文件
# make distribution DESTDIR=/usr/jail/myjail34.2.3 配置时间
沿用宿主机的时区和 DNS 配置,确保 Jail 内部网络和时间正常:
# 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 文件:
# 创建网桥和一对 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 网络拓扑结构如下:
物理网络 (示例家用路由器 192.168.1.1)
│
┌──────▼────────────────────────────────────────┐
│ 宿主机 (Host) │
│ │
│ [ 物理网卡 re0 ] │
│ │ │
│ [ 虚拟交换机 bridge0 ] <───(桥接) │
│ │ │
│ [ 虚拟网卡端 epair0a ] │
└─────────┼─────────────────────────────────────┘
│ (虚拟网线)
┌─────────┼─────────────────────────────────────┐
│ [ 虚拟网卡端 epair0b ] │
│ │
│ Jail (192.168.1.120) │
└───────────────────────────────────────────────┘配置好网络以后重启网络服务:
# service netif restart不建议在远程主机执行上述命令。请做好数据备份和应急手段。
34.2.5 配置容器网络
接下来配置容器网络,编写 Jail 配置文件 /etc/jail.conf(若不存在,请新建),对所有的容器生效,参考配置如下:
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 |
此外,目标登录用户所属登录分级的能力数据库中的环境变量也会被设置,JID、JNAME、JPATH 不会被设置。
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,添加如下内容:
ifconfig_epair0b="inet 192.168.1.120 netmask 255.255.255.0"
defaultrouter="192.168.1.1"34.2.6 启动容器
配置完成以后使用 service 命令启动:
# service jail start myjail启动以后使用 jls 命令查看,若容器创建成功,且正在运行,该容器将出现在列表中。
$ jls
JID IP Address Hostname Path
1 myjail.local /usr/jail/myjailVNET 模式中,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 确认已经连接到互联网:
# 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 ms34.2.7 测试容器
首先安装包管理器,执行 pkg 命令,遇到提示 Do you want to fetch and install it now? [y/N]: 选择 y。
若安装成功,将得到类似输出:
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,成功后将得到如下输出:
# 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。
# 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 正常工作,将得到如下输出:
$ fetch -o - http://192.168.1.120 | grep Welcome
- 896 B 5646 kBps 00s
<title>Welcome to nginx!</title>
<h1>Welcome to nginx!</h1>