我想到一种很新的安装操作系统方式 - ipxe & kexec

346 天前
 zhlxsh

一种通过 kexec 切换内核并安装系统的思路

背景

底层原理

Linux 内核崩溃的时候会将当前内存的一些信息保存到硬盘方便调试并重启,而内核内核崩溃了是谁存储到信息呢?答案是另一个内核

Linux 通过 kdump 服务在自身崩溃的时候拉起自己的一个“分身”,通过特定内核参数让“分身”收集日志。

这背后的技术就是 kexec

由于 kexec 切换内核会跳过 bios 自检等环节,大大缩短重启时间( x86 物理机开机约 5-10 分钟)

很自然的就想到,可不可以用 kexec 技术重装系统?

必要条件

  1. 物理机,且硬盘需要组 RAID
  2. 机器比较多,机房人少。需要通过 pxe 装机
  3. 物理机重装

之所以 k 搞这么复杂,一来是因为特殊场景,二来是提高一种 k 思路和可能性。少量机器推荐通过 u 盘安装

不直接用官方 ios 的原因是

  1. 系统安装之前物理机做一些操作,比如组 raid
  2. 如果不划 vlan 机器启动项又把网卡放到硬盘前面,重启就等于重装。qwq
  3. 技术探讨

一次 pxe-kexec 装机流程

pxe+bootOS+kexec+官方镜像

流程

  1. server 机安装好 pxe/ipxe 环境。主要是基础服务如 dhcp 、tftp 、ipxe 、nginx 、dns 。能达到无人值守安装官方镜像的程度。
  2. 使用官方镜像最小化安装,然后装上装上你顺手的工具,如 fish/zsh 。配好 ssh 免密登陆。将所有数据打包到一个 initramfs 里面,配上内核这将是我们的 bootOS
  3. 步骤 2 的两个文件放到步骤 1 的相应位置。pxe 是 tftp 目录,ipxe 则是 nginx 的目录。
  4. client 开机等待网络引导进入 bootOS ,此时系统将完全运行在内存中
  5. 登入 bootOS ,执行组 raid 脚本升级 bmc 固件等操作,此处可以用开机自启动脚本,或者先到 server 上拿到 dhcp IP ,然后通过 ansible/paramiko 库等自动执行
  6. 将原版镜像的 ios 镜像或者里面的 vmlinuzg 和 initrd 两个文件下载到 client ,并通过 kexec 命令切换到其内核。注意不要忘了带上可以无人值守装机的内核参数
  7. 此时屏幕将看到内核引导的日志,稍等片刻将进行系统安装

描述的比较粗略,实际每个步骤都可以写一篇教程,当然网上也都可以搜到

pxe-kexec 相比传统 pxe 的缺点

跟 pxe 相比可能不支持 Linux 外的一些系统,比如 esxi

理论上可行

不知道 bootOS 这种称呼对不对

不知道会不会有什么坑。理论上 Linux 都支持 bootOS 做一次就能满足所有 Linux 官方镜像

不知道大家批量装机,并且时不时重装等场景是怎么做到怎么做的。

3192 次点击
所在节点    Linux
18 条回复
huahsiung
346 天前
我做过差不多的事情,发现可以通过注入 /sbin/init 程序(现在差不多是 systemd )实现在不改变内核的版本下快速切换系统(类似 openvz 模板),准备多个模板,可以快速切换系统。我现在就在用呢。我编写了一个软件叫“init 截胡”。

后来发现也可以劫持 initrd.img 实现,这个可以实现不改变 mbr 启动项的情况下,启动其他系统,同时不会破坏原有硬盘数据,这个可以在有强制要求启动签名的 vps 上实现“软 dd”

[initrd.img 把真正的根 /dev/sda1 挂载到 /root ,然后 chroot /root 启动 /sbin/init ,你可以逆向最后一段

exec run-init ${drop_caps} "${rootmnt}" "${init}" "$@" <"${rootmnt}/dev/console" >"${rootmnt}/dev/console" 2>&1

]

劫持 iinitrd.img ,如果把根挂载到其他地方,或者挂载其他根,就可以实现“截胡”,启动其他系统。

这个我做出来了,程序也写出来了,在我的服务器上面用,所以可以确定这个方法可行。

kexec ???你可以写个程序验证一下

在不切换内核,实现“init 截胡”切换系统,这个我已经验证过了,就是要额外处理一下 kmod 而已。
huahsiung
346 天前
@huahsiung 我实现“init 截胡”遇到的坑就是不同的系统(模板)会加载不同的 kmod ,在却换系统的时候,“init 截胡”要实现卸载上一个系统的 kmod 。不然只能启动第一个系统,启动第二个的时候就会卡死。

我的方法是写了一个守护程序,但是不知道为什么污染了 /dev/pts ,导致控制台输入没有回显,原因未知,可能是我程序问题。反正我是在服务器上用 ssh,不用控制台,这个 bug 没有影响就没有修复
leonshaw
346 天前
相当于把 linux 当 boot loader 用,区别就是加载的物理地址受限制,然后有的硬件或者驱动可能初始化状态不对?
@huahsiung 看一下 switch_root 或者 pivot_root ,man 里有一些对 console 的处理。实际上从 initramfs 切换到最终 root 就是这样做的。
WuSiYu
346 天前
kexec 挺有意思的用法,不过服务器不能直接用 bmc 装系统吗?按说和物理上机操作是一样的,就是通过网络挂 iso 比较慢
nuk
346 天前
前几年试过 UEFI 直接 tftp 加载 kernel 和 ramfs 作为 rootfs (加载速度非常快),个人感觉 ipxe 完全可以定制化引导,安装成功后不再提供引导项,不管是 DHCP 选项,还是 tftp 文件,都可以和 MAC 地址和 IP 地址绑定。kexec 限制蛮多的,相比 ipxe 来说是锯了大腿了。
ysc3839
346 天前
一般来说服务器为了求稳还是建议跑一遍自检从头开始启动内核的,kexec 可能影响稳定性。
bt7vip
345 天前
@ysc3839 忘了在哪里看到的了,大致是既然 Linux 内核崩溃会自动进入另一个可以确保可以进系统的内核,那为什么不始终用那个可以进系统的那个呢。
答:只是确保能进,其他的都做最保守的策略,直接用哪个内核跑很多东西用不了或者性能低。差不多就是像 Windows 的安全模式一样,只加载启动,很多驱动都不加载。
zhlxsh
345 天前
@WuSiYu bmc 网速慢是一个问题,还有就是各厂商调用方法不同,不如 pxe 适用性强
zhlxsh
345 天前
@ysc3839 只是安装的时候通过 kexec 切环境,安装好了,官方镜像是会重启的。
zhlxsh
345 天前
@nuk ipxe.efi 确实能做很多事情,甚至本身就是一个操作系统了,在我说的这种场景下,(先组 raid ,然后用官方镜像装系统)。不用 kexec 会遇到一个问题,就是没有很好的办法区分两次进 pxe ,需要返回的内核文件…

你说的 mac 地址和 IP 绑定,然后返回不同 boot.scripts 区分应该可以,这样的话批量安装要改造 dhcp ?或者写脚本动态删减 dhcp 的配置?


组 raid 和升级固件的操作肯定是不能放进 uefi 和 ipxe 里面的。或者改造过于复杂,。。

这块能详细说一下怎么实现吗:个人感觉 ipxe 完全可以定制化引导,安装成功后不再提供引导项
tywtyw2002
345 天前
nixos 目前就已经支持用 ipxe 和 kexec 去装。
我远程装,很多时候都是用 debian img 然后 kexec 了
huahsiung
345 天前
@leonshaw 发现"init 截胡"出 bug 了,无法创建 user namespace 。今天使用 docker 时候发现的。

之后调试发现使用 clone()的 CLONE_NEWUSER 的时候返回-1 ,而其他 CLONE_NEWNS,CLONE_NEWPID 等等都没有问题。

疑似 kmod 没有切除处理干净导致???

使用 unshare 验证 unshare -m bash ,unshare -p xxx ,unshare -n ,unshare -i 等等都正常,只有 unshare -U,提示`unshare: unshare failed: Operation not permitted`

原因未知???。

看来奇淫技巧还是要付出一些代价
nuk
345 天前
@zhlxsh 是的,要改造 dhcp 和 tftp ,安装完了之后就删除 DHCP option ,最好是写一个自己的 tftp 服务器,比如一个文件对不同 IP 第一次下载和第二次下载返回不同的文件,tftp 本身就能做很多事情了
zhlxsh
344 天前
@nuk 写一个 tftp 难度会不会很高?
看网上资料和实际体验,tftp 的速度被限制的很慢,这个可以解决吗。
leonshaw
344 天前
@huahsiung chroot 是这样的,得用 pivot_root
leonshaw
344 天前
@huahsiung

man 2 unshare:

ERRORS
EPERM (since Linux 3.9)
CLONE_NEWUSER was specified in flags and the caller is in a chroot environment (i.e., the caller's root directory does not match the root directory of the mount namespace
in which it resides).
nuk
344 天前
@zhlxsh 不会,tftp 是最简单的,一个 readhandler 就全解决了,UEFI 的速度受到底层驱动限制,换其他的 UEFI 也解决不了的,除非先加载小的 rootfs ,然后加载驱动后再加载另一个大的 rootfs ,不过只是安装系统的话我觉得 100M 都够了
huahsiung
340 天前
@leonshaw 感谢提醒,发现了 pivot_root()和 switch_root()这两种方式,可以解决 chroot 的 bug 。十分感谢

这是一个专为移动设备优化的页面(即为了让你能够在 Google 搜索结果里秒开这个页面),如果你希望参与 V2EX 社区的讨论,你可以继续到 V2EX 上打开本讨论主题的完整版本。

https://www.v2ex.com/t/941395

V2EX 是创意工作者们的社区,是一个分享自己正在做的有趣事物、交流想法,可以遇见新朋友甚至新机会的地方。

V2EX is a community of developers, designers and creative people.

© 2021 V2EX