
机房几十台机器要装系统而且不是装完就完事后面还有驱动、软件、初始化配置要挨个处理。这种活儿干过一次就知道U盘一个一个插、光盘一张一张换、装完再一台一台敲命令一整天下来人都麻了。所以当你看到“PXE 批量安装 Ubuntu 20.04”这个标题的时候我猜你多半也是被这种重复劳动折磨过的人。PXE 这个东西不是新玩意但在电脑教室、实验室、公司测试机房这些场景里它依然是批量装 Linux 最靠谱的路线。这篇文章我直接把一套可落地的 PXE 批量安装方案拆给你看。从网络架构怎么搭、服务装哪些、引导文件怎么放到 Ubuntu 20.04 专用的 autoinstall 自动应答配置怎么写再到实际装机时你会踩的坑全部按我自己的实操经验来写。你不需要有多深的网络基础只要会敲 Linux 命令跟着步骤走就能在一台普通服务器上把整套环境搭起来然后让客户端开机、选菜单、等进度条走完。文章涉及的场景主要是 Ubuntu 20.04 Server 的批量部署但思路同样能迁移到其他 Linux 发行版甚至 Windows 上。1. 先把批量安装的逻辑理清楚1.1 为什么偏偏选 PXE很多人一说批量装系统第一反应是“用克隆软件”。以 Clonezilla 为代表的整盘克隆确实快但有一个绕不开的问题目标机器的硬件配置不完全一样。你把一台机器的整个磁盘镜像复制到另一台机器上网卡、显卡、磁盘控制器、内核模块都可能对不上轻则启动后缺驱动重则直接开机崩溃。而且克隆出来的系统带着源机器的痕迹主机名、UUID、SSH host key 全是重复的后续每台机器还得手动改一遍反而更麻烦。PXE 走的是另一条路。它本质上把“安装系统”这个过程自动化了客户端网卡一开机就去网络上找安装源拉取内核和初始化镜像然后由安装器根据你提前写好的应答文件在本地硬盘上重新分区、格式化、装系统。每一台机器装出来的都是干净、独立的系统硬件差异由安装器自己去适配。这个逻辑比“复制整盘”要干净得多也最适合 Ubuntu 这种支持自动化安装的发行版。另外PXE 的环境搭建成本很低。你不需要一台很牛逼的服务器只要有一个能用 DHCP 和 TFTP 的机器就行——一台旧 PC、一台跑着 Docker 的 NAS比如飞牛 fnOS、甚至一台树莓派都能胜任。真正复杂的是配置细节也就是这篇文章要重点讲的部分。1.2 PXE 装 Ubuntu 20.04 的完整链路为了后面不迷路先把 PXE 装机的完整链路走一遍。整个流程涉及到四类角色DHCP 服务给客户端分配 IP同时告诉客户端“你的引导文件在哪台服务器上、叫什么名字”。TFTP 服务一个超简单的文件传输服务客户端网卡的固件只认这个协议用它来下载引导程序GRUB 或 pxelinux。HTTP 服务安装器启动后需要从网络拉取 Ubuntu 20.04 的 ISO 镜像这一步用 HTTP 比 NFS 省事也比 FTP 通用。自动应答文件你预先写好的配置告诉安装器“用户名是什么、密码是什么、磁盘怎么分、要装哪些软件包、装完执行哪些命令”。客户端开机的过程是这样的网卡固件通过 DHCP 获取 IP 地址以及 TFTP 服务器的地址和引导文件名。网卡从 TFTP 下载引导程序UEFI 机器下载 GRUB传统 BIOS 机器下载 pxelinux。引导程序读取菜单配置加载 Linux 内核 vmlinuz 和 initrd。内核启动后安装器根据内核参数里的 url 从 HTTP 服务器下载 ISO 镜像。同时安装器读取dsnocloud-net参数指向的 HTTP 路径拉取 autoinstall 的 seed 文件。安装器按照 seed 文件的配置自动完成分区、格式化、软件安装装完自动重启。这六步里任何一步断了都会导致安装失败。所以我后面每一章都会针对性地讲清楚怎么保证这一环不出问题。1.3 Ubuntu 20.04 的安装器跟老版本有什么区别在 Ubuntu 18.04 及以前官方用的安装器是 debian-installer自动化靠 preseed 文件。到了 Ubuntu 20.04官方换成了 Subiquity 安装器也就是你在屏幕上看到的那个现代化安装界面自动化方案也随之变成了 autoinstall配置文件是 cloud-init 风格的 YAML。很多人拿旧教程来套 Ubuntu 20.04结果发现 preseed 根本不生效这就是原因。autoinstall 不是一个简单的参数替换它的逻辑、字段、调试方式都跟 preseed 不一样。所以我这篇文章直接用 autoinstall 来讲这也是 Ubuntu 20.04 之后官方推荐且长期稳定的方式。如果你以后要装 22.04、24.04这套配置基础完全一样最多是新增字段不会有颠覆性变化。2. 服务器环境准备三件套搞定2.1 规划网络和目录结构我建议 PXE 服务器独立搭建在一个专用的局域网里尤其你如果是给机房几十台机器装机千万别拿公司生产环境的 DHCP 来改一个配置错误很容易让全网络断网。我们用一个独立的网段来举例PXE 服务器 IP192.168.100.10/24网关192.168.100.1DHCP 分配范围192.168.100.100 - 192.168.100.200服务器用 Ubuntu 20.04 或者 Debian 都可以配置这块基本通用。提前把 IP 固定好在/etc/netplan/下面写静态地址。服务器上的目录结构我也习惯固定下来方便日后维护/srv/tftp/ TFTP 根目录引导程序、内核、菜单文件都放这里 /srv/www/ HTTP 根目录 /srv/www/iso/ Ubuntu ISO 镜像放这里 /srv/www/seed/ autoinstall 的 user-data 和 meta-data 放这里然后你需要下载一份 Ubuntu 20.04 Server 的 ISO。建议到官方镜像站或者国内高校开源镜像站下载文件名类似ubuntu-20.04.6-live-server-amd64.iso。20.04 的最新维护版本是 20.04.6后续的 20.04.x 补丁包都会包含在 ISO 里所以尽量用新一点的维护版本省得装完还要打一堆补丁。2.2 安装并配置核心服务需要安装的软件包其实就三个核心dnsmasq、nginx外加一个 syslinux 相关的包用来提供传统 BIOS 启动的引导文件。apt update apt install -y dnsmasq nginx syslinux-common pxelinux grub-efi-amd64-bin注意dnsmasq 同时承担了 DHCP 和 TFTP 两个角色所以不需要再安装 tftpd-hpa。这一点很多人搞混装了 tftpd-hpa 又跟 dnsmasq 抢 69 端口反而起不来服务。装完之后先把 dnsmasq 默认的配置文件备份一下然后新建一个专门的配置文件mv /etc/dnsmasq.conf /etc/dnsmasq.conf.bak vim /etc/dnsmasq.conf写入以下配置# 只监听 PXE 服务器的网卡 interfaceeth0 bind-interfaces # DHCP 分配范围 dhcp-range192.168.100.100,192.168.100.200,12h # 分配网关和 DNS dhcp-optionoption:router,192.168.100.1 dhcp-optionoption:dns-server,192.168.100.1,223.5.5.5 # 启用 TFTP并指定 TFTP 根目录 enable-tftp tftp-root/srv/tftp # 根据客户端固件架构返回不同的引导文件 dhcp-matchset:efi-x86_64,option:client-arch,7 dhcp-matchset:efi-x86_64,option:client-arch,9 dhcp-matchset:bios,option:client-arch,0 dhcp-boottag:efi-x86_64,grub/x86_64-efi/core.efi dhcp-boottag:bios,pxelinux.0这里有个关键点我要特别说明现在的电脑绝大多数是 UEFI 启动但机房也难免混着几台老机器走传统 BIOS。dnsmasq 的dhcp-match会根据客户端发送的 DHCP 选项里的固件架构编号把它们分流到不同的引导文件。架构编号 7 和 9 对应 x86_64 的 UEFI编号 0 对应传统 BIOS。这样一套配置就能同时兼容两种机器不用区分对待。配置好后重启 dnsmasqsystemctl restart dnsmasq systemctl enable dnsmasq然后配置 nginx把/srv/www作为根目录并开启目录列表方便后面排查文件路径vim /etc/nginx/sites-available/defaultserver { listen 80 default_server; root /srv/www; index index.html; autoindex on; }重启 nginxsystemctl restart nginx检验 HTTP 服务通不通直接在服务器上访问http://192.168.100.10/能看到目录列表就说明服务正常。2.3 用 Docker/NAS 复刻这套环境现在不少人习惯用 NAS 当家里的基础设施比如飞牛 fnOS 自带的 Docker 管理器。PXE 服务完全可以容器化。思路是在 Docker 里跑两个容器一个跑 dnsmasq一个跑 nginx把/srv/tftp和/srv/www挂载到 NAS 的存储目录里。docker run -d --name pxe-dhcp \ --network host \ -v /vol1/pxe/tftp:/srv/tftp \ -v /etc/dnsmasq.conf:/etc/dnsmasq.conf \ jpillora/dnsmasq docker run -d --name pxe-http \ -p 80:80 \ -v /vol1/pxe/www:/usr/share/nginx/html:ro \ nginx容器化的好处是配置迁移方便但缺点也很明显容器里的 dnsmasq 如果要用network host模式对宿主机的网络配置要求比较高两套环境容易互相干扰。如果是第一次搭 PXE我建议先用普通方式搭好、跑通一遍再考虑容器化不然有问题的时候排查起来会多一层隔离。在张小规模机房里物理机直接装服务反而是最省心的。3. 构建 PXE 引导链从网卡到安装菜单3.1 放置引导文件PXE 引导链最烦的就是引导文件容易缺。我们现在要把两种启动方式的文件都准备齐全。首先把下载好的 ISO 挂载上把内核和 initrd 拷到 TFTP 目录mkdir -p /srv/tftp/ubuntu/2004 mount -o loop /srv/www/iso/ubuntu-20.04.6-live-server-amd64.iso /mnt cp /mnt/casper/vmlinuz /srv/tftp/ubuntu/2004/ cp /mnt/casper/initrd /srv/tftp/ubuntu/2004/然后生成 UEFI 启动需要的 GRUB 网络引导核心。这里我们用 GRUB 自带的grub-mknetdir命令它会自动生成一套完整的网络引导目录结构grub-mknetdir --net-directory/srv/tftp --subdirgrub执行完成后/srv/tftp/grub/x86_64-efi/目录下会生成core.efi和一系列.mod模块文件。GRUB 被网卡加载后会自动去 TFTP 根目录下找grub/grub.cfg所以我们把菜单文件放在这里。接着准备传统 BIOS 启动需要的文件。syslinux 和 pxelinux 包已经装好了直接拷贝cp /usr/lib/PXELINUX/pxelinux.0 /srv/tftp/ cp /usr/lib/syslinux/modules/bios/ldlinux.c32 /srv/tftp/ cp /usr/lib/syslinux/modules/bios/menu.c32 /srv/tftp/ cp /usr/lib/syslinux/modules/bios/libcom32.c32 /srv/tftp/ cp /usr/lib/syslinux/modules/bios/libutil.c32 /srv/tftp/ mkdir -p /srv/tftp/pxelinux.cfg这里有一个特别容易忽略的坑pxelinux.0运行时需要ldlinux.c32如果没有启动画面会卡住或者直接报Could not find kernel image。menu.c32依赖libcom32.c32和libutil.c32少一个菜单界面就显示不出来。这些依赖文件不像 pxelinux.0 那么显眼拷的时候一定不要漏。3.2 配置 GRUB 菜单UEFI 机器在/srv/tftp/grub/grub.cfg里写菜单这是 UEFI 客户端会读到的配置vim /srv/tftp/grub/grub.cfgset default0 set timeout10 loadfont unicode set gfxmodeauto terminal_output gfxterm menuentry Install Ubuntu 20.04 Server (AutoInstall) { linux /ubuntu/2004/vmlinuz ipdhcp urlhttp://192.168.100.10/iso/ubuntu-20.04.6-live-server-amd64.iso autoinstall dsnocloud-net;shttp://192.168.100.10/seed/ --- initrd /ubuntu/2004/initrd } menuentry Boot from Local Disk { exit }先解释一下这些内核参数因为后面所有排错都跟它们有关ipdhcp让安装器启动后用 DHCP 获取 IP。如果是服务器环境也可以提前规划好固定 IP用ip192.168.100.101::192.168.100.1:255.255.255.0::eth0:none这种写法不过批量装机里用 DHCP 省事。urlhttp://192.168.100.10/iso/ubuntu-20.04.6-live-server-amd64.iso这是 Ubuntu Live Server 的 casper 引导机制要求的安装器会去这个地址下载 ISO 镜像然后作为安装介质使用。文件必须能用 HTTP 直接访问到路径不能错。autoinstall告诉安装器进入全自动安装模式不需要人机交互。dsnocloud-net;shttp://192.168.100.10/seed/ds是 cloud-init 的数据源参数nocloud-net表示从网络读取配置后面s是 seed 文件的目录地址。cloud-init 会去这个目录下依次读取meta-data和user-data。最后的---这是 casper 的分隔符后面的参数会传给 initrd 的处理脚本不能省。3.3 配置 pxelinux 菜单传统 BIOS 机器传统 BIOS 客户端的菜单配置放在/srv/tftp/pxelinux.cfg/defaultvim /srv/tftp/pxelinux.cfg/defaultdefault menu.c32 prompt 0 timeout 100 menu title PXE Boot Menu label install menu label ^Install Ubuntu 20.04 Server (AutoInstall) kernel ubuntu/2004/vmlinuz append initrdubuntu/2004/initrd ipdhcp urlhttp://192.168.100.10/iso/ubuntu-20.04.6-live-server-amd64.iso autoinstall dsnocloud-net;shttp://192.168.100.10/seed/ --- label local menu label ^Boot from Local Disk localboot 0timeout 100的单位是 0.1 秒100 就是 10 秒。菜单默认第一个条目是远程安装如果不想装机得赶紧选第二项从本地硬盘启动或者干脆把默认项改成local。到这里引导链的配置就结束了。留意一下TFTP 目录里的文件路径和菜单里的路径是相对的比如ubuntu/2004/vmlinuz实际上对应/srv/tftp/ubuntu/2004/vmlinuz。写错一个字符都会导致找不到文件。4. 写 autoinstall 应答文件实现真正“无人值守”4.1 autoinstall 的目录结构接下来要做的是让安装全过程自动化。前面已经在内核参数里指定了shttp://192.168.100.10/seed/所以我们需要在/srv/www/seed/目录下创建两个文件user-data真正的自动安装配置也就是 autoinstall 的核心。meta-datacloud-init 要求的元数据文件内容可以为空但不能没有。mkdir -p /srv/www/seed touch /srv/www/seed/meta-datameta-data里其实可以写很多东西比如instance-id但对于纯安装场景留空就够了。cloud-init 只要能找到这个文件就不会报数据源错误。4.2 编写 user-data下面是一个我实际用过的、可以直接改改就用的user-data示例。这里的 YAML 格式要求非常严格缩进、空格、冒号任何一个错误都会导致安装器读不了配置忽略时特别难看懂所以建议用空格缩进不要用 Tab。vim /srv/www/seed/user-data#cloud-config autoinstall: version: 1 locale: zh_CN.UTF-8 keyboard: layout: cn identity: hostname: pxe-node username: sysadmin password: $6$random_salt$hashed_password ssh: install-server: true allow-password: true storage: layout: name: direct packages: - openssh-server - vim - net-tools - cloud-guest-utils late-commands: - echo Installed by PXE at $(date) /target/pxe-install.log我先逐个字段说明你再根据自己的需求改。identity这一段配置主机名和初始用户。password那一栏不能直接写明文得用加密后的密文。生成方式openssl passwd -6 -salt pxeinstall yourpassword把输出的$6$...整串拷贝到配置文件里注意 YAML 里如果包含特殊字符要用单引号包起来。早期 20.04 版本的部分安装器里这个字段可能叫user而非identity如果安装时提示字段错误就改成user试一下。这个差异很坑网上教程有的写这个有的写那个但实际以你的 ISO 版本为准。storage.layout.name: direct表示直接把整块磁盘作为系统盘不建 LVM。如果你希望使用 LVM 逻辑卷可以改成name: lvm。机房部署一般用 direct 最省心因为后续想扩容、想重做系统都方便。如果想自定义分区比如单独划分/home可以写完整的storage.config列表但那个篇幅很长对于批量装机反而没必要。packages是安装完系统后额外安装的软件包。因为 Ubuntu 20.04 Server 的最小安装里连 vim 都没有所以把常用的工具在这里列出来。如果你的环境是内网无法访问 Ubuntu 软件源那这些包可能装不上但你至少可以留一个openssh-server同时在安装时选好镜像源。在late-commands里可以执行装机完成后的命令这里是 autoinstall 最灵活的地方。比如把主机名改成有规律的名字、写入装机日志、下载 NVIDIA 驱动等。注意命令里的路径late-commands执行时实际的系统根目录是/target要用curtin in-target才能在目标系统里执行命令。比如late-commands: - curtin in-target --target/target -- sh -c apt-get update DEBIAN_FRONTENDnoninteractive apt-get install -y build-essential linux-headers-generic如果你要装 NVIDIA 驱动Ubuntu 20.04 自带的源里一般有nvidia-driver-470或者nvidia-driver-535但520这个版本通常需要从 NVIDIA 官网下载.run文件或者在late-commands里添加官方 PPA 再装。批量装机的场景我更推荐提前把.run文件放到 HTTP 目录下然后late-commands: - wget -O /target/tmp/nvidia.run http://192.168.100.10/drivers/nvidia-linux-x86_64-520.56.06.run - curtin in-target --target/target -- bash /tmp/nvidia.run --silent不过.run安装方式要求系统里必须提前装好内核头文件和编译工具所以两个命令要配合使用。如果你只是普通课程机房不涉及 CUDA 计算其实用源里的nvidia-driver-470就足够了稳定压倒一切。4.3 用 dry-run 验证配置autoinstall 的 YAML 配置一旦有语法错误安装器不会告诉你“哪里错了”而是直接跳过自动安装进入交互模式。所以强烈建议在正式批量装机之前先在虚拟机里做一次完整的验证。验证方式有两种。第一种是直接用你搭好的 PXE 环境开一台虚拟机选择 PXE 启动观察安装过程是不是全自动跑完。第二种是把你写好的user-data丢到一台已经启动的 Ubuntu 20.04 系统里用 Subiquity 的 dry-run 模式检查不过 20.04 的 dry-run 工具支持不完整最实际的方法还是用虚拟机跑一遍。我自己的习惯是第一次写好配置后一定要先手动控制台观察一次安装过程如果发现 installer 进入交互界面按 CtrlAltF2 切到日志终端查看/var/log/cloud-init-output.log和/var/log/installer/subiquity.log里面会明确告诉你卡在哪个配置项上。这一步不能省因为很多小错只会在日志里露出马脚你在菜单位置看半天也看不出来。4.4 关机、重启、以及安装完后的行为autoinstall 默认装完会停在安装完成的界面等人来按回车。这在大批量装机时很不方便。可以在user-data尾部补上autoinstall: shutdown: reboot这样系统安装完会自动重启。但是注意自动重启之后客户端又会从网卡启动又进 PXE 菜单如果你不手动选择“Boot from Local Disk”它可能重新进入安装流程相当尴尬。解决思路有几个在安装菜单里把默认项设为Boot from Local Disk远程安装作为第二项这样重启后直接进本地系统。或者用late-commands把 PXE 引导的 IP 地址记录下来在安装完成后通过efibootmgr设置优先从硬盘启动。最省事的办法是人看着重启前按几下 F12 选硬盘。大规模批量装机时我更倾向于在late-commands里写一个脚本把下次启动顺序调到硬盘同时把 DHCP 的租约时间调短一点。但说实话最可靠还是人工在 BIOS 里设置好硬盘启动顺序PXE 只在需要时装完就改回来。5. 客户端侧配置与批量实操5.1 BIOS/UEFI 设置要点服务端全部就绪后客户端这边还有几个设置项要做否则你可能连 PXE 菜单都看不到。第一进入 BIOS找到Secure Boot设置为关闭。如果开了 Secure BootGRUB 必须是由微软签名或 Ubuntu 签名的引导文件我们用的core.efi没有签名会被直接拒掉屏幕上出现类似Security Violation的提示然后启动失败。第二确认网卡启动了 PXE 功能。多数商用台式机的板载网卡默认支持需要在 BIOS 的Onboard LAN或Network Boot选项里设为 Enabled。第三启动顺序里把UEFI: Realtek PXE或IPv4 PXE这类条目排在硬盘前面。不同的电脑叫法不一样戴尔的叫Network Boot联想的叫Boot from LAN惠普的叫Network (PXE) Boot。你只要认得PXE和IPv4这两个词就行。第四确认用的是有线网卡。PXE 不支持无线网卡笔记本装系统时一定要插网线。当你看到屏幕出现Press [F12] for Network Boot或者直接出现 GRUB 菜单说明 PXE 链路已经通了。5.2 批量装机的两种节奏我自己在实际机房操作时会根据机器数量和网络条件选择不同节奏。如果只有十台以下的机器直接全部开机同时进 PXE 菜单让它们一起安装。安装过程中会有大量 ISO 下载流量局域网千兆环境下大概每台占用 100-200 Mbps十几台没问题。如果是三四十台甚至更多的机器建议分成两批到三批不要一次全开。原因有两个一是 dnsmasq 的 DHCP 服务很轻量但 HTTP 并发下载 ISO 时带宽会被吃满导致部分机器下载超时二是一旦某个批次的机器装完重启你还得及时处理个别安装失败的机器全开的话容易顾不过来。分批操作的时候可以在 dnsmasq 里调整 DHCP 租约时间为 2 小时装完一批下一批机器再开机时自然拿到新租约不会互相影响。5.3 批量装机后的初始化脚本系统装完之后通常还有一堆初始化工作要做。与其一台一台登录去操作不如把这些也写进 autoinstall 的late-commands里一次搞定。比如修改主机名按照机房座位号命名。创建普通用户并配置 sudo 权限。把时区强制设置为Asia/Shanghai。替换 apt 源为国内镜像。关闭不必要的系统服务。安装学校或公司要求的监控客户端、考试客户端。这里有一个相对完整的例子late-commands: - curtin in-target --target/target -- bash -c echo pxe-node-$(hostname) /etc/hostname - curtin in-target --target/target -- timedatectl set-timezone Asia/Shanghai - curtin in-target --target/target -- sed -i s/archive.ubuntu.com/mirrors.tuna.tsinghua.edu.cn/g /etc/apt/sources.list - curtin in-target --target/target -- bash -c echo pxe-install /root/install-method注意这些命令都在目标系统上执行所以要用curtin in-target包一层。late-commands里的命令不像普通 shell 那样有完整的PATH有些命令要用绝对路径或者直接在命令前加bash -c。如果你需要在安装后从本地仓库装 Python 依赖包比如办公室要用到的一堆 whl 文件可以把 whl 目录放到 HTTP 服务器上然后在late-commands里- curtin in-target --target/target -- bash -c wget -qO- http://192.168.100.10/pkgs/install-wheels.sh | bash这样做的好处是后续想加软件包、改初始化逻辑只需要在服务器上改一次脚本客户机重新装机即可生效不用一台台登录处理。6. 常见问题与排查实录6.1 启动阶段的“黑色三分钟”PXE 报错最早出现的就是启动阶段。这里我列一个排查速查表基本都是我实际遇到过且定位过的现象原因解决办法屏幕提示PXE-E61: Media test failure, check cable网卡没插网线或 DHCP 服务器不可达检查网线、交换机端口确认服务器 dnsmasq 正常运行PXE-E51: No DHCP or proxyDHCP offers received客户端收不到 DHCP 响应检查 DHCP 服务是否监听正确网卡客户端和服务器是否在同一广播域PXE-E11: ARP timeout二层网络异常VLAN 隔离导致 ARP 不通检查交换机的端口隔离设置确保实验网段内设备能互相通信TFTP open timeoutTFTP 服务没启动或防火墙拦截 69 端口确认 dnsmasqenable-tftp或者关闭服务器防火墙出现Could not find kernel image: ubuntu/2004/vmlinuzTFTP 目录下找不到内核文件检查/srv/tftp/ubuntu/2004/下文件是否存在路径大小写是否正确出现Failed to load ldlinux.c32pxelinux.0 缺少依赖模块把ldlinux.c32等 syslinux 模块拷到 TFTP 根目录屏幕提示No configuration file found未找到 pxelinux.cfg 配置文件确认/srv/tftp/pxelinux.cfg/default存在启动后看到boot failed或者Reboot and Select proper Boot device客户端没有获取到引导文件名检查 dnsmasq 的dhcp-match分流是否生效尤其是 UEFI 机器其中最常见的还是 Realtek 网卡启动时的提示setup noticeefi pxe o for ipv4 (88-a4-c2-22-b5-97) boot failed would you...。这段英文看起来吓人实际就是网卡尝试 PXE 引导失败后询问你“要不要继续尝试”或者“直接进硬盘启动”。出现这个提示多数时候意味着 DHCP 和 TFTP 链路不通优先检查 dnsmasq 配置。诊断的时候几个命令特别有用。在服务器上# 查看 DHCP 是否分配了地址 journalctl -u dnsmasq -f # 查看 TFTP 请求是否进来 tcpdump -i eth0 port 69 or port 4011 # 查看 HTTP 请求 tail -f /var/log/nginx/access.log用tcpdump抓包是定位 PXE 问题最有效的办法能看到客户端网卡的 DHCP 请求、TFTP 下载过程到底卡在哪一步。很多人配置半天没效果一抓包就明白了。6.2 安装器启动后的故障速查过了 PXE 引导阶段机器开始跑内核和安装器这类问题通常跟内核参数和 autoinstall 配置有关。现象原因解决办法卡在unable to find a medium containing a live file system内核没找到安装介质通常是url参数不对或 HTTP 服务不可达手动访问一下url指向的地址确认 ISO 能下载检查内核参数cloud-init 数据源找不到进入交互安装dsnocloud-net;s...参数漏写或路径不对确认参数在---之前访问http://192.168.100.10/seed/meta-data确认 200安装器提示invalid autoinstall configuser-data YAML 语法错误用python3 -c import yaml; yaml.safe_load(open(user-data))检查语法用户/密码字段不生效20.04 部分版本用user而非identity根据 installer 版本调整字段名分区失败或找不到磁盘storage 配置有问题或磁盘有旧 RAID 信息检查磁盘是否被正确识别尝试layout: direct安装完成后反复进入 PXE 安装重启后启动顺序仍然是网卡优先BIOS 里调整启动顺序或装完后手动改 PXE 引导选项一次印象很深的翻车经历我配好dsnocloud-net;shttp://192.168.100.10/seed/后批量装了四台机器结果三台都进入交互安装界面而且交互界面里根本没有报错。最后查日志发现由于meta-data文件权限是 644但user-data权限错打成 666部分 cloud-init 版本对权限敏感会直接忽略配置。你也许不会遇到这个具体问题但这提醒我们权限、文件名、路径任何一个细节都不能想当然装完第一台机后一定要第一时间确认它是不是真的全自动跑完不要等地板上的机器都装上才发现配置有问题。6.3 如何快速重装和回滚批量装机过程中偶尔会有几台机器因为硬件问题或者配置原因装到一半挂掉。挂掉的机器重新启动又会自动进入安装流程这个其实是 PXE 的优点也是回滚方案的基础。我的做法是在/srv/www/seed/user-data里预留不同的配置分支比如测试配置和正式配置。如果想快速回滚到交互式安装就把内核参数里的autoinstall和ds...去掉只保留url...这样机器启动后会进入正常的图形化安装界面适合单台调试。如果配置改动后发现问题直接在服务器的 seed 目录里改文件然后让客户端重启重装即可。不用在客户端上做任何操作这种“服务端一处改动全局生效”的体验就是 PXE 最大的价值。7. 后续扩展从一个机房延伸到更多场景搭好这一套 PXE 环境你其实不只是搞定了一个机房。稍微改规划能扩展出不少实用场景。比如你可以把 Ubuntu 桌面版的 ISO 也放到 ISO 目录下通过修改 GRUB 菜单提供“Ubuntu 20.04 Server 安装”和“Ubuntu Desktop 安装”两个选项。桌面版的内核和 initrd 也在 ISO 的casper目录下参数结构几乎一样。这样一套服务器Linux 的各种发行版都能管。再比如给 PXE 菜单里加一个内存系统工具比如 GParted Live 或者 SystemRescue平时修机器、做磁盘维护也能通过网络启动不必常备一堆启动 U 盘。在我实际管理的机房环境里PXE 已经成为装系统的默认方式U 盘只用于应急光驱基本可以退役。你可能会发现一旦熟练掌握了这套流程三四十台机器的系统部署时间可以从一整天压缩到两三个小时剩下的大量时间更多的是花在 BIOS 设置和个别硬件兼容性调试上。最后再分享一个实操中的小经验所有 PXE 相关配置和脚本我建议放到一个 Git 仓库里管理。机房机器的规模会变、Ubuntu 版本会升级、seed 文件的软件包清单会变没有版本管理的配置出了改动都不知道是哪次引起的。每次改完配置在虚拟机上先验证一遍再推送到生产环境批量装机这件事就会变成一个稳定、省心、可复现的标准化流程。