厚 Jail (Thick Jail)
编辑服务
使用文本编辑器编辑 /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 的内核和用户空间是一个整体(基本系统,又称世界),用户空间不一致可能导致兼容性问题
获取基本系统
不建议将基本系统解压到 /usr/jail 中。应在其中创建子目录,将每个容器都单独放在其中的目录里面,如此方便管理
注意下载解压和编译两种方法 任选一种方法 进行安装即可,切勿重复安装
解压安装方式
# 创建 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
编译安装方式
# 进入源码目录 $ cd /usr/src # 构建世界(编译基础系统) $ make buildworld # 将编译好的系统安装到指定 Jail 目录 $ make installworld DESTDIR=/usr/jail/myjail # 生成配套的配置文件 $ make distribution DESTDIR=/usr/jail/myjail
配置时间
沿用宿主机的时区和 DNS 配置,确保 Jail 内部网络和时间正常:
$ cp /etc/resolv.conf /usr/jail/myjail/etc/ $ cp /etc/localtime /usr/jail/myjail/etc/
配置宿主机网络
必须在本地控制台执行以下网络配置操作(修改网桥、物理网卡 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
配置容器网络
接下来配置容器网络,编写 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"
启动容器
配置完成以后使用 service 命令启动:
$ service jail start myjail
启动以后使用 jls 命令查看,若容器创建成功,且正在运行,该容器将出现在列表中
$ 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 确认已经连接到互联网:
$ 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
测试容器
首先安装包管理器,执行 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>
| Next: Qjail | Previous: Jail 概述 | Home: Jail 容器管理 |