在前面的文章中, 我们已经提到, initrd 本身就是精简版的根盘文件系统, 主要目的是用于内核启动后 OS 环境的初始化, 比如你是 Soft Raid,需要在这个时候读取 /etc/fstab 文件,比如根盘文件在特定的 Raid 设备卷中的分区上, 需要预加载指定 Raid 驱动等等.总之这个环境主要用于真正用户 OS 启动之前的准备.

通常在各个发行版本都有各自的 initrd 的构建工具,各自的目的呢, 也仅限于我们上述提到的功能. 而我们是需要将整个 OS 塞到这个内存镜像中,所以稍微还是有区别,调研了下一些业界的实现, 这里的几个链接供参考:

上述链接可以看到, 一般是使用 https://virt-manager.org/和http://libguestfs.org/ 这两个项目的工具来构建镜像.可以尝试下这个方法, 完全可行, 但是有个问题是这个流程真的太长了, 比如要按上述流程构建的话, 需要用virt-install完整安装一遍目标 OS
, 继续用virt-sysprep对镜像做一遍清理, 将生成的镜像导入到 virt-builder, 继续在 KVM 虚拟机中配置一遍 OS 默认信息, 然后就可以将镜像更新到 virt-builder 基础镜像中, 然后拿到其他地方使用, 比如 Ramdisk boot/Vagrant/OpenStack/Docker中使用.

其实上述安装过程是依赖于各个发行版本的安装器, 完整走过一遍各发行版本的安装流程, 然后对磁盘内容进行整理和优化, 然后作为最终的镜像使用.但是其实我们的述求是很简单的,就是根盘目录所有的内容,一番调研之后, Debian/Ubuntu 系列 OS 提供的 debootstrap 工具用于构建完整的 OS 根目录, 而且操作及其简单, 一行命令就可以完成, 相比我们使用上面的流程将更加简便和可靠, 局限就是只能使用 Debian/Ubuntu 系列发行版. 其他发行版本经过查找, 不确定是否包含该类似工具.

好接下来,我们就介绍下 debootstrap 工具:

main # mkdir /stable-chroot
main # debootstrap stable /stable-chroot http://deb.debian.org/debian/

官方的 debootstrap 的使用教程,请参考 https://wiki.debian.org/Debootstrap

使用 debootstrap 工具我们构建了根盘, 但是还是以目录形式存在,将如何使用呢? 在使用层面, 我们和 http://www.espenbraastad.no/posts/centos-7-rootfs-on-tmpfs/ 文章所使用的逻辑保持一致.

内核启动后, 默认执行的第一个程序就是 pid=0 的 init 程序.而发行版的默认的 init 程序在各个历史阶段皆不相同, 早期大多使用 SysVInit, 较新的版本使用 Systemd 作为 init 程序, init 程序默认是放置在系统根盘(/)下, 一般是通过软链接的方式链接到/init. 而我们这里是希望在内存镜像中集成完整版本的 OS.就涉及到两个过程, 一个是内核启动后initrd中默认的 init 程序,另一个是 initrd 中的初始化完成后, 使用 switch_root 切换到用户端 OS 的 init 程序, 我们重点关注第一个过程中 init 程序, 需要重新定义这里的初始化逻辑. 第二个过程中的 init 进程一般和 OS 的 init 程序挂钩, 早期是 SysVinit,目前更多是 Systemd.

我们需要构建一个工作目录,比如 ~/work/,接下来构建一些必须的子目录:

mkdir -p ~/work/build # 用于存放最终的 initrd 文件
mkdir -p ~/work/initramfs # initrd 中存放的文件内容,主要包括 一阶段 init 程序和根盘压缩内容
mkdir -p ~/work/chroot #用于存放操作系统的根盘内容

初始化 OS 的根盘内容

我们这里使用 Ubuntu 18.04 作为内存 OS, 我们这里主要用于 VirtualBox 实验环境, 安装 linux-virtual 内核包就可以,如果是在物理机上真实使用, 安装 linux-generic 内核包.

debootstrap --arch amd64 bionic ~/work/chroot http://mirrors.163.com/ubuntu
chroot ~/work/chroot apt -y install linux-virtual

根盘文件系统好了之后, 需要将其压缩打包:

cd ~/work/chroot
time tar -cf - . | xz -v --threads=24 > ~/work/initramfs/rootfs.tar.xz
````2019-06-21-build_ram_os.md*

接下来我们需要下载 `busybox` 来作为执行环境, 减少 init 脚本的编写成本

wget -O ~/work/initramfs/bin/busybox https://busybox.net/downloads/binaries/1.21.1/busybox-x86_64


编写 init 文件内容(这里可以可以参考各个发行版本的 iso 中的 init 工具的编写方式, 大同小异)

vim ~/work/initramfs/init


~/work/initramfs/init文件的内容如下:

!/bin/busybox sh

Dump to sh if something fails

error() {

echo "Jumping into the shell..."
setsid cttyhack sh

}

Populate /bin with binaries from busybox

/bin/busybox --install /bin

mkdir -p /proc
mount -t proc proc /proc

mkdir -p /sys
mount -t sysfs sysfs /sys

mkdir -p /sys/dev
mkdir -p /var/run
mkdir -p /dev

mkdir -p /dev/pts
mount -t devpts devpts /dev/pts

Populate /dev

echo /bin/mdev > /proc/sys/kernel/hotplug
mdev -s

echo "mount rootfs... "
mkdir -p /newroot
mount -t tmpfs -o size=80% tmpfs /newroot || error

xz -d -c -f rootfs.tar.xz | tar -x -f - -C /newroot || error

mount --move /sys /newroot/sys
mount --move /proc /newroot/proc
mount --move /dev /newroot/dev

exec switch_root /newroot /sbin/init || error


到此整个 initramfs 的内容,我们就构建完成了.最终需要输出为cpio文档格式.

cd ~/work/initramfs
find . -print0 | cpio --null -ov --format=newc | gzip -9 > ~/work/build/initramfs.gz


最终生成的 initramfs 文件为 `~/work/build/initramfs.gz`, 将其拷贝到 PXE Server 的 `/var/lib/tftpboot/ubuntu-installer/amd64/`, 接下来你就可以去我们的 PXE 环境调试下, 将 PXE Server 的 `/var/lib/tftpboot/ubuntu-installer/amd64/boot-screens/txt.cfg 中的内容调整为如下:

default install
label install
menu label ^Automatically Install Ubuntu 16.04
kernel ubuntu-installer/amd64/linux
append vga=788 initrd=ubuntu-installer/amd64/initramfs.gz


然后启动一下 PXE Client 虚拟机, 看看是否启动了一个完整的 OS.

【腾讯云】境外1核2G服务器低至2折,半价续费券限量免费领取!
https://cloud.tencent.com/act/cps/redirect?redirect=1068&cps_key=e4b50f6c64a4480367f8a8d16fd07c5a&from=console

标签: pxe, init, ramos, libguestfs, virt-manager, debootstrap

添加新评论