使用 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包管理器 包管理器。
考虑到 linuxulator 和 FreeBSD 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功能
sysrc jail_enable="YES"
# 配置所有jails在后台启动
sysrc jail_parallel_start="YES"
Jail目录树
使用了
jail_zfs环境变量来指定ZFS位置,为Jail创建目录树:
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目录结构
zfs create $jail_dir
zfs create $jail_dir/media
zfs create $jail_dir/templates
zfs create $jail_dir/containers
完成后检查
df -h可以看到磁盘如下:
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配置复制到模板目录:
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 部分保持读写)
为模版创建快照(完整快照):
zfs snapshot $jail_dir/templates/$bsd_ver-RELEASE@base
基于快照(snapshot)的Thin Jail 比 NullFS 类型简单很多,只要在模块快照基础上创建clone就可以生成一个新的Thin Jail:
jail_name 环境变量,方便后续调整jail命名# 假设这里创建名为lrdev的jail
jail_name=lrdev
lrdev 的Thin Jail(后续将进一步改造为 FreeBSD Linux Jail )zfs clone $jail_dir/templates/$bsd_ver-RELEASE@base $jail_dir/containers/$jail_name
现在可以看到相关ZFS数据集如下:
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:
/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:
/etc/jail.conf.d/lrdev.conflrdev {
# 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系统:
rhbootstrap 类似
debootstrap用于 Rocky/CentOS/Fedora 系统构建bootstraprinse: 在debian上提供的一个获取并安装rpm包构建一个RedHat系系统的工具,在Ubuntu上帮助系统中有介绍 rinse manual ,也可以参考 Building an RPM based (Red Hat, Fedora, CentOS) Xen Guest Root Filesystem using RinseKickstart: Red Hat系用来自动安装系统的复杂工具
Mock: 用于 Fedora 和 Rocky Linux 构建包的chroot环,也可以用来构建一个类似
debootstrap的包测试环境Container Tools: podman 或 Docker 使用的创建基本最小系统的工具,可以用来下载一个Rocky Linux镜像,并用它作为一个构建定制环境
我已经实践 使用 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进程管理器 ,应该可以共用。
解压缩下载
Rocky-9-Container-Base.latest.x86_64.tar.xz:
# 创建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使用:
/etc/resolv.conf 复制给Jail# 在Host主机上执行
cp /etc/resolv.conf /$jail_dir/containers/$jail_name/compat/rocky/etc/
使用Linux Jail
一切就绪 现在可以启动名为 lrdev 的Linux Jail
lrdev Linux Jailservice 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)'