前言

在一些精简的Linux发行版里,很多时候会有无法运行需要某些依赖的程序的情况。

然而,会搭载这种精简系统的设备,一般无法重新安装系统;例如:路由器、手机等其他嵌入式设备。

而且受限于系统内核(缺少cgroup的一些高级特性等),也无法安装docker。

同时,在不同的Linux发行版下,使用的C语言标准库也不尽相同;如:glibc、musl等。

即使CPU支持程序所使用的指令集,使用glibc所编译的程序,也无法在musl环境下运行。(使用兼容层也会出现依赖问题)

容器技术分析

以下仅为个人理解,仅供参考,欢迎纠错。

  • chroot jail: 使用chroot命令以特定目录作为根目录执行程序,被执行的程序无法访问新根目录以外的文件,实现了文件系统层的隔离。(无需内核支持)
  • LXC(Linux Containers): 在chroot的基础上,追加了进程隔离独立的网络环境。(需要内核支持)
  • Docker: 早期基于LXC实现,再在LXC的基础上,实现了镜像的逐层叠加、打包、发布,优化了应用部署流程。(同样需要内核支持)

在使用docker的过程中,我发现大部分镜像都是基于Alpine Linux;一般情况下,容器宿主机是使用glibc作为C语言标准库,而alpine则是使用musl。

这意味着,系统可以执行哪些程序,不是取决于哪个发行版系统,而具体是取决于使用哪套C语言标准库。

那么只要所使用的指令集相同,在使用musl的系统下,运行使用glibc的子系统镜像,自然也是可行的。

在Alpine下运行Ubuntu

像Alpine这样的系统,也算是非主流了。

如果要安装/运行像宝塔面板这样的傻瓜式服务器管理程序,自然是不行的;得使用Ubuntu/CentOS这样的主流系统。

那么,我非要在Alpine下运行宝塔的话,那么便要套一层Ubuntu了。

通过chroot使用LXC镜像

由于LXC是基于chroot的,自然也可以通过chroot使用LXC镜像。

  • 下载最新的Ubuntu根目录镜像(rootfs.tar.xz)

    • 注意要选择正确指令集的镜像。(以上链接为amd64架构)
  • 解压镜像,并进入chroot jail。

mkdir rootfs
tar xvf rootfs.tar.xz -C rootfs
chroot rootfs

这时,就从陌生的Alpine,进入了熟悉的Ubuntu了。

完善chroot容器

尽管进入了Ubuntu,但此时还什么都做不了;那是因为没有挂载相关的系统资源。

  • 挂载资源
mount --bind "/proc" "rootfs/proc"
mount --bind "/sys"  "rootfs/sys"

mount --bind "/dev" "rootfs/dev"
mkdir -p "rootfs/dev/pts"
mount -t devpts none "rootfs/dev/pts"

chmod 664 "rootfs/dev/random"
chmod 775 "rootfs/dev/urandom"
  • 如需要挂载宿主系统目录,同样使用mount --bind [src] [dest]即可。
  • 处理DNS、时区等杂项
rm -f "rootfs/etc/resolv.conf"
rm -f "rootfs/etc/localtime"

cp -f "/etc/resolv.conf" "rootfs/etc"
cp -f "/etc/localtime" "rootfs/etc"

到这里,Ubuntu容器已经基本可用了。

  • PS:每次开机都需要重新挂载,故需要自行编写开机启动脚本

完善服务管理

但是由于系统不是systemd引导的,systemctl无法使用,无法管理服务。

  • 解决方案(二选一)
    • 一、使用supervisor来管理
      • 优点:Python实现,所有发行版系统都支持,只要启动supervisord,其关联的所有子项都会被自动启动。
      • 缺点:增加学习成本,要了解supervisor的配置编写。
      • 安装方法:包管理
    • 二、使用docker-systemctl-replacement替代systemctl
      • 优点:替换systemctl后,与原生systemd管理差异不大。
      • 缺点:有部分功能没实现,如status无法查看运行时输出;每一项服务都需要自己手动控制启动。
      • 安装方法:放到“/opt”或者随便哪个目录,软链接到“/usr/local/bin”即可。(或配置环境变量)

完善服务管理后,与原生Ubuntu体验没啥区别;但是需要在宿主系统,加入开机启动子系统服务的脚本。

2022.11.19 补充:方案三

前段时间无意间使用 apt 搜索了 systemctl,发现有以下结果:

systemctl/jammy 1.4.4181-1.1 all
  daemonless "systemctl" command to manage services without systemd

提供了与 docker-systemctl-replacement 同样功能的 systemctl,但部署起来更加简单。

apt purge --allow-remove-essential systemd
apt install systemctl

安装宝塔

正常流程安装即可。(不是重点)

总结

  • Linux很自由,可以在宿主系统运行n个子系统。
  • chroot仅对文件系统隔离,对于有安全性要求的环境慎用。
  • 对于使用Linux,内核又不支持使用Docker/LXC的设备,chroot可以增加不少可玩性。