1: 替代chroot、docker,使用systemd-nspawn容器搭建ARM交叉编译环境(1)
2: 替代chroot、docker,使用systemd-nspawn容器搭建ARM交叉编译环境(2)
简介
chroot功能简陋使用不方便,docker适合生产环境,开发环境使用复杂,系统打包平移也不方便。最近发现了 systemd-nspawn这个神器,比chroot方便,不需要自己挂载目录,也不容易吧主机系统弄崩溃,可以直接使用一个目录作为根,方便迁移,整个容器可以随便打包抬走,不像docker使用overlay需要导出导入,还有版本操作等等,开发使用过于繁琐。根据这两天的使用体验给大家分享一下。
什么是 systemd-nspawn?
systemd 项目认为应当将容器技术变成桌面的基础部分,并且应当和用户的其余系统集成在一起。为此,systemd 提供了 systemd-nspawn,这款工具能够使用多种 Linux 技术创建容器。它也提供了一些容器管理工具。
systemd-nspawn 和 chroot 在许多方面都是类似的,但是前者更加强大。它虚拟化了文件系统、进程树以及客户系统中的进程间通信。它的吸引力在于它提供了很多用于管理容器的工具,例如用来管理容器的 machinectl。由 systemd-nspawn 运行的容器将会与 systemd 组件一同运行在宿主系统上。举例来说,一个容器的日志可以输出到宿主系统的日志中。
主机环境搭建
在 debian系列的系统下system-nspawn放在了一个单独的软件包里面,使用apt安装:
sudo apt install systemd-container
因为我们要搭建交叉编译环境,这里还是使用qemu-user-static来做二进制翻译,使用apt安装一下
sudo apt install qemu-user-static
systemd-nspawn基本命令
在进入容器之前我们都需要一个最基本的根文件系统,对于systemd-nspawn来说,这个文件系统可以是一个raw格式的镜像文件,也可以是一个目录,下面主要以一个目录作为容器的根节点来说明systemd-nspawn的使用方法。
systemd-nspawn可以像chroot一样以一个目录作为根来启动一个容器,并且不需要手动挂载proc、run、dev等目录,退出容器也会自动清理资源,不容易吧主机系统弄崩溃。
chroot进入一个容器:
sudo systemd-nspawn -D rootfs
systemd-nspawn不仅能像chroot一样以一个目录作为一个新系统的根,并且还能以一个完整的系统启动流程来启动一个容器。
启动一个完整的系统:
sudo systemd-nspawn -bD rootfs
制作ubuntu rootfs
到这里下载一个自己喜欢的ubuntu base版本:
http://cdimage.ubuntu.com/ubuntu-base/releases/
比如我这里下载的是:ubuntu-base-20.04.3-base-arm64.tar.gz
解压并做一些简单配置:
mkdir ubuntu20.04
sudo tar -xzvf ubuntu-base-20.04.3-base-arm64.tar.gz -C ubuntu20.04
#拷贝主机上的qemu-user-static到rootfs中,这样才能直接执行异构二进制程序
sudo cp /usr/bin/qemu-aarch64-static ubuntu20.04/usr/bin/
#照抄主机上的/etc/resolv.conf,等下进入容器才有网络
sudo vim ubuntu20.04/etc/resolv.conf
#修改主机名,可以照抄主机的
sudo vim ubuntu20.04/etc/hosts
sudo vim ubuntu20.04/etc/hostname
这里我们先以简单容器的方式进入系统,因为这个时候系统还不具备完整启动流程的能力。
sudo systemd-nspawn -D ubuntu20.04
进入容器后做一些基本的软件安装操作
apt update
apt install systemd
apt install systemd-sysv
apt install net-tools
apt install ping
apt install sudo
adduser username
#启动root权限,copy root那一行,改成自己的用户名
vim /etc/sudoers
配置磁盘挂载,很重要,否则sudo无法使用
#记下根分区挂载设备,我的是/dev/sdb2
mount
#配置fstab
vim /etc/fstab
#可以照下面样子写
# UNCONFIGURED FSTAB FOR BASE SYSTEM
/dev/sdb2 / ext4 rw,relatime 0 1
退出容器
exit
重启进入完整系统
sudo systemd-nspawn -bD ubuntu20.04
可以看到系统以完整的systemd流程在启动
输入刚才创建的用户名和密码进入系统,我们不需要使用网络相关的服务,网络服务会让容器启动变慢。
停用网络服务
sudo systemctl disable network-*
在容器里面关机重启都是可以的,是不是很强大。
关机
sudo poweroff
#或者
sudo halt
重启
sudo reboot
到此基本的系统环境搭建就结束了,systemd-nspawn还支持图形化与音频,实现也不复杂,以后再说了
关闭容器
有时候以完整模式启动容器会卡住无法退出,需要借助一些其他方法,这里不推荐在主机上直接kill掉容器,可能造成主机不稳定。下面推荐两种强制关闭容器的方法:
1、使用systemd-container自带的命令machinectl
#列出当前正在运行的容器
machinectl list
#强制关闭一个容器
machinectl poweroff comtainer-name
2、使用快捷键,直接在容器运行的终端中按住ctrl
再按三下]
就能强制退出容器
可能遇到的一些问题
问题:sudo systemd-nspawn -D ubuntu20.04
或者sudo chroot ubuntu20.04
都无法启动容器,报/bin/bash
不存在之类的错误。
解决:可以在主机直接执行容器中的/bin/bash
会发现也是报不存在,但是文件以及权限都正常,遇到这种问题一般是二进制翻译环境配置不正确。第一种解决办法是检查一下qemu-user-static安装是否正常,另外是否有其他二进制翻译产生了冲突,比如安卓模拟器一般会安装houini。如果是冲突的情况可以禁用其他二进制翻译器,比如禁用houini:echo 0 | sudo tee /proc/sys/fs/binfmt_misc/arm64_exe
,echo 0 | sudo tee /proc/sys/fs/binfmt_misc/arm64_dyn
。
问题:sudo无法执行。
解决:这个问题一般是在完整启动系统的时候会出现,错误原因是因为systemd默认挂载的根目录有nosuid
标志,这个标志导致sudo无法正常执行,只需要正确配置好fstab就不会有这个标志。
问题:无法完整启动系统,看不到登陆提示。
解决:这个是因为有的rootfs没有安装systemd导致的,比如ubuntu-base就不再预装systemd,而是让用户选择自己喜欢的服务管理器,只需要正确安装systemd即可,这里一般不是缺少getty导致的,除非是busybox有可能缺少getty。