使用 Rocky-Container-base tgz 包部署Linux Jail Rocky

说明

我在 在 FreeBSD Linuxulator 中运行NVIDIA Cuda 实践中遇到执行 miniconda-installer 运行报错,推测和Python3运行环境相关。想对比尝试 Linuxulator 快速起步 中更新 linuxulator 中 Rocky Linux 9 的Python(系统提供的 linux-rl9 中python配置有问题)。但是发现发行版的 linuxulator linux userland实际上是非常非常精简的系统,甚至没有提供 DNF包管理器 包管理器。

考虑到 linuxulatorFreeBSD Linux Jail 实际底层原理一致,既然 使用 ubuntu-base tgz 包部署Linux Jail Ubuntu 能够通过Ubuntu core来构建,那么Rocky Linux应该也可以以相同方式构建 linuxulator userland 环境。

同理,也可以使用 Rocky-9-Container-base 来构建 FreeBSD Linux Jail ,就像 使用 ubuntu-base tgz 包部署Linux Jail Ubuntu 一样。这样思路打开了,完全可以构建不同Linux发行版的 Linux Jail 或 linuxulator

Rocky Linux download > 9 > images > x86_64 提供了 Rocky-9-Container-base.latest.x86_64.tar.xz ,虽然是针对 Container 的镜像压缩包,但是jail非常类似container,实际上都剥离了 Systemd进程管理器 ,应该可以共用。

Linux Jail

FreeBSD Linux Jail是在FreeBSD Jail中激活支持Linux二进制程序的一种实现,通过一个允许Linux系统调用和库的兼容层来实现转换和执行在FreeBSD内核上。这种特殊的Jail可以无需独立的linux虚拟机就可以运行Linux软件。

VNET + Thin Jail(Snapshot)

主机激活 jail

  • 执行以下命令配置在系统启动时启动 Jail :

激活jail
# 配置在系统启动时激活Jail功能
sysrc jail_enable="YES"

# 配置所有jails在后台启动
sysrc jail_parallel_start="YES"

Jail目录树

  • 使用了 jail_zfs 环境变量来指定ZFS位置,为Jail创建目录树:

设置 jail目录和release版本环境变量
export jail_dir="zdata/jails"
export bsd_ver="14.3"
# 在FreeBSD中root用户的shell默认是sh,所以调整 ~/.shrc
echo 'export jail_dir="zdata/jails"' >> ~/.shrc
echo 'export bsd_ver="14.3"' >> ~/.shrc
  • 创建jail目录结构

jail目录结构
zfs create $jail_dir
zfs create $jail_dir/media
zfs create $jail_dir/templates
zfs create $jail_dir/containers
  • 完成后检查 df -h 可以看到磁盘如下:

jail目录的zfs形式
Filesystem                   Size    Used   Avail Capacity  Mounted on
...
zdata                        6.1T     96K    6.1T     0%    /zdata
zdata/jails                  6.1T    104K    6.1T     0%    /zdata/jails
zdata/jails/media            6.1T     96K    6.1T     0%    /zdata/jails/media
zdata/jails/templates        6.1T     96K    6.1T     0%    /zdata/jails/templates
zdata/jails/containers       6.1T     96K    6.1T     0%    /zdata/jails/containers

快照(snapshot)

备注

快照(snapshot) 型 vs. 模板和NullFS 型 Thin Jail 说明两种不同的Thin Jail,本文是 OpenZFS Snapshots 类型的Thin Jail构建记录:

  • ZFS snapshot Thin Jail: 将FreeBSD Release base存放在 只读14.3-RELEASE@base 快照上

  • NullFS Thin Jail: 将FreeBSD Release base存放在 读写14.3-RELEASE-base 数据集上

在 Linux Jail 中采用 ZFS snapshot Thin Jail 是为了避免复杂的 RELEASE-base 分离以及NullFS挂载 对Linux文件系统挂载的冲突影响。

  • 为OpenZFS Snapshot Thin Jail 准备模版dataset:

创建 14.3-RELEASE 模版
zfs create -p $jail_dir/templates/$bsd_ver-RELEASE
  • 下载用户空间:

下载用户空间
fetch https://download.freebsd.org/ftp/releases/amd64/amd64/$bsd_ver-RELEASE/base.txz -o /$jail_dir/media/$bsd_ver-RELEASE-base.txz
  • 将下载内容解压缩到模版目录: 内容解压缩到模板目录(后续要在14.3-RELEASE上创建快照,这就是和NullFS的区别)

解压缩
tar -xf /$jail_dir/media/$bsd_ver-RELEASE-base.txz -C /$jail_dir/templates/$bsd_ver-RELEASE --unlink
  • 将时区和DNS配置复制到模板目录:

将时区和DNS配置复制到模板目录
cp /etc/resolv.conf /$jail_dir/templates/$bsd_ver-RELEASE/etc/resolv.conf
cp /etc/localtime   /$jail_dir/templates/$bsd_ver-RELEASE/etc/localtime
  • 更新模板补丁:

更新模板补丁
freebsd-update -b /$jail_dir/templates/$bsd_ver-RELEASE/ fetch install

备注

从这里开始 Snapshot 类型Thin Jail 和 NullFS 类型Thin Jail开始出现步骤差异: 这里需要为base模版建立快照,然后clone(NullFS则创立快照,但只clone skeleton 部分保持读写)

  • 为模版创建快照(完整快照):

为RELEASE模版创建base快照
zfs snapshot $jail_dir/templates/$bsd_ver-RELEASE@base
  • 基于快照(snapshot)的Thin Jail 比 NullFS 类型简单很多,只要在模块快照基础上创建clone就可以生成一个新的Thin Jail:

为了能够灵活创建jail,这里定义一个 jail_name 环境变量,方便后续调整jail命名
# 假设这里创建名为lrdev的jail
jail_name=lrdev
clone出一个名为 lrdev 的Thin Jail(后续将进一步改造为 FreeBSD Linux Jail )
zfs clone $jail_dir/templates/$bsd_ver-RELEASE@base $jail_dir/containers/$jail_name
  • 现在可以看到相关ZFS数据集如下:

ZFS数据集显示jail存储
Filesystem                                     Size    Used   Avail Capacity  Mounted on
...
zdata/jails                                    1.3T    116K    1.3T     0%    /zdata/jails
zdata/jails/media                              1.3T    201M    1.3T     0%    /zdata/jails/media
zdata/jails/containers                         1.3T    104K    1.3T     0%    /zdata/jails/containers
zdata/jails/templates                          1.3T    104K    1.3T     0%    /zdata/jails/templates
...
zdata/jails/templates/14.3-RELEASE             1.3T    460M    1.3T     0%    /zdata/jails/templates/14.3-RELEASE
zdata/jails/containers/lrdev                    1.3T    460M    1.3T     0%    /zdata/jails/containers/lrdev

配置Jail

备注

VNET + Thin Jail(NullFS) 配置基础上完成

  • 适合不同Jail的公共配置 /etc/jail.conf :

混合多种jail的公共 /etc/jail.conf
# STARTUP/LOGGING
exec.start = "/bin/sh /etc/rc";
exec.stop = "/bin/sh /etc/rc.shutdown";
exec.consolelog = "/var/log/jail_console_${name}.log";

# PERMISSIONS
allow.raw_sockets;
exec.clean;
mount.devfs;

allow.mount;
allow.mount.devfs;

enforce_statfs = 1;

# HOSTNAME
host.hostname = "${name}";

# NETWORK - VNET/VIMAGE
#ip4 = inherit;
interface = igc0bridge;
vnet;
vnet.interface = "${epair}b";
# common NETWORK config
$gateway = "192.168.7.221";
$bridge = "igc0bridge";
$epair = "epair${id}";

# ADD TO bridge INTERFACE
exec.prestart += "ifconfig ${epair} create up";
exec.prestart += "ifconfig ${epair}a up descr jail:${name}";
exec.prestart += "ifconfig ${bridge} addm ${epair}a up";
exec.start    += "ifconfig ${epair}b ${ip} up";
exec.start    += "route add default ${gateway}";
exec.poststop = "ifconfig ${bridge} deletem ${epair}a";
exec.poststop += "ifconfig ${epair}a destroy";

.include "/etc/jail.conf.d/*.conf";
  • 用于Snapshot类型的 lrdev 独立配置 /etc/jail.conf.d/lrdev.conf :

用于Snapshot类型 /etc/jail.conf.d/lrdev.conf
lrdev {
  # thin jail devfs_ruleset 5 和Linux Jail的4不同
  devfs_ruleset=4;

  # HOSTNAME/PATH - Snapshot
  path = "/zdata/jails/containers/${name}";

  # NETWORKS/INTERFACES
  $id = "253";
  $ip = "192.168.7.${id}/24";

  # MOUNT
  mount += "devfs     $path/compat/ubuntu/dev     devfs     rw  0 0";
  mount += "tmpfs     $path/compat/ubuntu/dev/shm tmpfs     rw,size=1g,mode=1777  0 0";
  mount += "fdescfs   $path/compat/ubuntu/dev/fd  fdescfs   rw,linrdlnk 0 0";
  mount += "linprocfs $path/compat/ubuntu/proc    linprocfs rw  0 0";
  mount += "linsysfs  $path/compat/ubuntu/sys     linsysfs  rw  0 0";
  mount += "/tmp      $path/compat/ubuntu/tmp     nullfs    rw  0 0";
  mount += "/home     $path/compat/ubuntu/home    nullfs    rw  0 0";

}

部署 Rocky 9

在FreeBSD handbook中 Chapter 12. Linux Binary Compatibility 标准方法是采用 debootstrap 来构建userland,但是这个方法有2个不足:

  • debootstrap 只能用来构建 Debian 系的发行版userland

  • 我在实践中发现 debootstrap 总有非常奇怪的不报错但是也没有完成完整的 .deb 包(已下载)安装的问题,导致实际构建的userland无法正常使用(也可能和我使用FreeBSD 15 Alpha版本有关)

实际上现在发行版大多数会提供 core-base tgz包,通常用于 Container 容器。由于这种核心系统不包含 Systemd进程管理器 ,并且FreeBSD Jail的原理和容器相似,所以也能用于构建FreeBSD Linux Jail的userland部分,即Linux系统。

备注

对于 RedHat Linux 系列发行版,也有类似 debootstrap 的工具用于获取base系统:

我已经实践 使用 ubuntu-base tgz 包部署Linux Jail Ubuntu 构建了FreeBSD debootstrap 默认不支持的 Ubuntu 24.04 系统,验证这个方法是可行的。所以,这里也采用类似方法来构建 Rocky Linux userland。

备注

不要使用 Rocky-9-Container-Minimal.latest.x86_64.tar.xz ,这个 minimal 版本不包含 DNF包管理器 包管理器,也就是说,实际上FreeBSD linuxulator 提供的userland其实就是 minimal 版本。

Rocky Linux download > 9 > images > x86_64 提供了 Rocky-9-Container-base.latest.x86_64.tar.xz ,虽然是针对 Container 的镜像压缩包,但是jail非常类似container,实际上都剥离了 Systemd进程管理器 ,应该可以共用。

解压缩
# 创建Linux兼容层目录
mkdir -p /$jail_dir/containers/$jail_name/compat/rocky

# 解压缩下载的Rocky Linux 9 base压缩包
tar xfp Rocky-9-Container-Base.latest.x86_64.tar.xz -C /$jail_dir/containers/$jail_name/compat/rocky/
  • 在FreeBSD Host主机上将 /etc/resolv.conf 复制给Jail使用:

将Host主机的 /etc/resolv.conf 复制给Jail
# 在Host主机上执行
cp /etc/resolv.conf /$jail_dir/containers/$jail_name/compat/rocky/etc/

使用Linux Jail

一切就绪 现在可以启动名为 lrdev 的Linux Jail

启动 lrdev Linux Jail
service jail start lrdev
  • 进入 lrdev 的Linux环境:

进入 lrdev 的Linux环境
jexec lrdev chroot /compat/rocky /bin/bash
  • 更新:

更新系统
dnf update
  • 安装 config-manager 插件(用于管理后续仓库配置):

安装 config-manager 插件
dnf install 'dnf-command(config-manager)'

参考