UP | HOME

厚 Jail (Thick Jail)

Table of Contents

编辑服务

使用文本编辑器编辑 /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 Bridgeepair0a 是虚拟交换机上的一个 端口

可将之视为一个虚拟交换机,其上插着一根无形的网线,水晶头插在交换机上
  • 网线网桥侧端口称为 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 是正常的
Table 1: 常用管理命令
命令 解释
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 安装

安装成功后:

  1. 执行 pkg update -f 强制重新获取软件仓库目录
  2. 执行 pkg ins nginx
  3. 执行 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 容器管理