https://github.com/leitbogioro/Tools
图库来自 imgur.com ,需要挂梯子全局访问才能正常显示。
这个帖子放在主贴 https://91ai.net/thread-1159839-1-1.html(Linux一键重装支持Debian 12,Ubuntu 22.04,史上最强)中,篇幅实在过于冗长,对仅需要使用 Linux 一键重装脚本的朋友来说会带来很大困惑,也有可能会忽略掉默认密码:LeitboGio0ro 等关键信息,让所以我把它单独开辟出来,供有兴趣的人自行研究。
Ubuntu 自从 18.04 版本后,采用的自动部署方式和 Debian 开始分家,引入了一种叫 cloud init 的部署工具,说实话,这个产品很强,它的厉害之处是把不同发行版本 Linux 的自动部署配置格式从顶层加以统一的抽象化,说人话就是写一套相同的配置文件,云服务商就可以快速给一台机器布置 Debian Kali Ubuntu AlpineLinux CentOS Almalinux RockyLinux Fedora 等等 Linux 系统,用户名、密码、网络配置等等关键参数都由 cloud init 来处理,不需要云服务商运维自己定期给不同的 Linux 发行版制作各种不同镜像,由于该项目是开源的,现在很多云服务厂家后台都是用 cloud init 来部署镜像,应用范围很广,是非常强势的一种应用。
但是,Ubuntu 的母公司 Canonical 在方便了云服务商的同时,却给普通用户造成了不小的麻烦,其中罪魁祸首就是把 debian installer 给移除。Ubuntu 支持兼容 Debian 的安装方法从 Ubuntu 20.04 后(这还是好多人不满,官方磨磨蹭蹭给的,声称是“兼容一些老用户的习惯”)就彻底放弃,比如 Ubuntu 22.04 官方源中,最小化传统网络启动(netboot)内核页面是空的:
http://ports.ubuntu.com/dists/jammy/main/installer-arm64/current/legacy-images/
Ubuntu netboot 页面:
https://cdimage.ubuntu.com/netboot/
虽然能看到 Ubuntu 22.04 jammy 的目录,但点击去就会发现,人家只是虚晃一枪,并不再提供相关文件,仅引导你去使用他们提供的 cloud init 安装方式:
https://cdimage.ubuntu.com/netboot/jammy/
从 Ubuntu 22.04 开始,仅支持读取 cloud init 格式的配置文件部署,不再与之前的 debian installer 兼容,这使得很多好用的,基于 Debian 安装方式部署 Ubuntu 系统的方式均已失效,我愿称之为 Canonical 损失了一大笔宝贵的遗产。
Canonical 一意孤行的同时,却没有给普通用户一个好的替选方案,我的意思就是供用户下载一个很小的网络启动文件,然后从 grub 引导启动,启动文件读取相应的配置文件,然后连接镜像源,完成系统的原生自动化安装工作。目前可行的方案仅有两种:
下载一个 iso 文件,烧录到外部存储设备,比如光盘或 U 盘,然后系统重启后从 iso 启动,读取 cloud init 进行自动化安装;
从 Ubuntu cloud images 网站下载每周官方打包好的 Ubuntu 对应版本镜像,转换格式后挂载,对这个镜像里的系统进行一些定制,然后再将其 unmount,像以前安装 ghostXP 一样,把镜像文件全盘解压到硬盘,在读取 cloud init 完成重启后的自动化部署。
注意,1中的 Ubuntu 安装文件是被压缩的,安装时需要重新解压,和我刚才说的网络启动方式“原生”安装一个系统的原理是一致的,2中的 Ubuntu 是一个已经完全被释放出来的 Ubuntu 系统包,这个系统只要重写到硬盘里,就能作为一个系统独立启动,只不过如果不加以配置,它的用户名、密码、网络等都是默认的,装完了你也连不上去。
所以问题来了,对于一个只有单硬盘,无法挂载外部存储设备的 VPS 来说,挂 iso 安装很明显是不现实的,独立于硬盘,可给对硬盘操作(格式化时硬盘不能自己操作自己)的存储设备就是内存,Debian、红帽系的网络安装都是基于加载在内存里的微缩系统来完成初始化,并往硬盘里写入系统、配置、启动的。既然 Ubuntu 暂时不提供网络安装选项,那么核心思路还是要先在内存里启动一个中介系统,才能保证后续操作最起码有可能。
煎饼哥的方式是采用 AlpineLinux 为中间系统,启动后用 AlpineLinux 给硬盘分区,预留一个存 Ubuntu iso 镜像的分区,然后给中间系统写入下一次从 Ubuntu iso 引导,再次重启后启动 Ubuntu 安装程序,读取 cloud init 配置完成后续安装,在新系统里还要埋一个自动扩展分区容量的脚本,否则新系统里会发现残留一个当时存储 iso 镜像的分区,以上步骤中,那个 iso 镜像分区就是“外部存储设备”,虽然它是虚拟的分区,不是额外的物理硬盘,也能完成预期效果。
我在思考和开发相关功能时,决定采取第二种办法,即简单修改一下 Ubuntu Cloud images 的内容,然后把它存放在服务器上,反正是 Ubuntu 官方每周构建的完整系统文件,兼容性和稳定性肯定值得信赖。然后启动中介系统,用 dd 方式将其下载并完全重写到目标硬盘,最后植入 cloud init 文件,让 Ubuntu 系统包完全释放到硬盘并重启后,按我预期的要求,完成自动化部署工作。
最初的中介系统选用的是和 dd Windows 一样的 Debian 12,因为相比仅支持 IPv4 动态或静态启动的 AlpineLinux 来说,Debian 12 可以以 IPv4 IPv6 任意静态或动态方式启动,兼容性无疑更强,但 Debian installer 具备数个无法有效解决的致命缺陷,包括但不限于:
Debian installer 环境为 busybox,一个超级精简的 Linux 系统,精简到什么程度呢?就连普通的 grep sed 等命令支持的参数也被精简,导致许多在正常 Linux 发行版下能正确运行的参数也无法执行的程度,很多正则表达式也不能识别;Debian installer 在系统安装时不同阶段,会按需加载需要的组件,如果在某阶段之前去执行,很多命令会因为组件还未加载完成无法执行,最典型的例子就是我在 VNC 里,过了 partition 分区阶段,手搓命令,可以挂载 dd 到硬盘后的 Ubuntu 系统文件,并写入 cloud init,但如果在 installer 刚启动时就开始手搓命令,挂载命令就无法执行。 如果你愿意和我一样把键盘搓冒烟,通过 Debian installer dd 也能获得一个能正常运行的 Ubuntu:
但是,一旦把以上案例中手搓的命令写入到 Debian installer 的自动应答文件 preseed.cfg 里,手搓效果和脚本执行效果就完全不同,Debian installer 始终无法完成 mount dd 到硬盘中的 Ubuntu 镜像文件,并把参数传递给 cloud init,这一步至关重要,如果无法完成,重启后的 Ubuntu 没有被进行过任何配置,包括 ssh 服务等都没有初始化,机器是无法连接的,整个安装过程,包括从服务器下载镜像,可以说是完全白费力气。preseed.cfg 本质上是一个规范 Debian 安装程序该如何自定义 Debian 系统安装的工具,它用来安装 Debian 系统足够优秀,但并不能作为一个可以让命令在 Debian installer 里自由运行,配置的脚本,preseed 中虽然可以通过指定 d-i partman/early_command string、d-i preseed/run string、d-i preseed/late_command string 等方法让 Debian installer 去执行一些有限功能的命令,但这些方法执行命令时要么时机太靠前(刚刚开始时就运行),要么太靠后(装完 Debian 后再执行),相关命令和依赖也不能自由地加载和安装,所以除了将其用于 dd Windows 用,dd Ubuntu 只能放弃。