替代chroot、docker,使用systemd-nspawn容器搭建ARM交叉编译环境(1)

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_exeecho 0 | sudo tee /proc/sys/fs/binfmt_misc/arm64_dyn

问题:sudo无法执行。
解决:这个问题一般是在完整启动系统的时候会出现,错误原因是因为systemd默认挂载的根目录有nosuid标志,这个标志导致sudo无法正常执行,只需要正确配置好fstab就不会有这个标志。

问题:无法完整启动系统,看不到登陆提示。
解决:这个是因为有的rootfs没有安装systemd导致的,比如ubuntu-base就不再预装systemd,而是让用户选择自己喜欢的服务管理器,只需要正确安装systemd即可,这里一般不是缺少getty导致的,除非是busybox有可能缺少getty。

### Linux驱动开发学习教程入门指南 对于希望进入Linux驱动开发领域的人来说,理解操作系统原理以及硬件交互机制至关重要。可以从基础概念入手,逐步深入到具体技术细节。 #### 单片机程序和Linux程序对比 单片机编程通常针对特定微控制器进行低级操作,而Linux环境下的设备驱动则运行于复杂多变的操作系统之上。前者往往直接控制外设寄存器完成任务;后者通过标准接口与内核通信来访问硬件资源[^1]。 #### 掌握必要的预备知识 - **C语言**: 由于大部分驱动代码都是用C编写的,因此熟练掌握这门语言非常重要。 - **数据结构与算法**: 这些基础知识有助于更好地理解和优化驱动逻辑。 - **计算机组成原理**: 对CPU架构、存储层次等方面的知识能够帮助开发者更高效地处理性能瓶颈问题。 - **操作系统理论**: 特别是对进程调度、同步原语等内容的理解可以加深对并发环境下工作的认识。 #### 实践项目建议 参与实际项目的练习是提高技能的有效途径之一。可以选择简单的字符型设备作为起点,比如LED灯或者按键开关等简单外围电路对应的驱动模块编写工作。随着经验积累再尝试更加复杂的块设备或网络适配器类别的开发。 #### 参考资料推荐 除了官方文档之外,《Unix设计与实现》这本书提供了关于如何构建稳定可靠系统的宝贵见解,尽管其侧重点在于解释设计理念而非详尽展示源码片段,但对于想深入了解内部运作方式的学习者来说非常有价值[^2]。 ```c // 示例:创建一个最简化的字符设备注册函数 #include <linux/module.h> #include <linux/kernel.h> #include <linux/fs.h> static int major_number; int register_char_device(void){ major_number = register_chrdev(0, "example", &fops); if (major_number<0){ printk(KERN_ALERT "Registering char device failed with %d\n", major_number); return major_number; } printk(KERN_INFO "I was assigned major number %d. To talk to\n", major_number); return 0; } ```
评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值