iPXE网络启动实战:裸金属服务器批量装机全链路指南

📅 2026/6/21 5:34:18
iPXE网络启动实战:裸金属服务器批量装机全链路指南
1. 项目概述为什么今天还要折腾裸金属网络启动你有没有遇到过这样的场景机房里新上架了二十台服务器每台都要装CentOS、Ubuntu、Rocky Linux或者国产操作系统如openEuler、Kylin、UOS——光是插U盘、点鼠标、等安装界面加载一个人干完就得两天更别说中间有人误操作跳过磁盘分区确认或者某台机器网卡驱动没识别直接卡在黑屏。这时候PXEPreboot eXecution Environment就不是“老古董技术”了而是运维工程师手里的扳手和螺丝刀它不依赖本地存储开机即联网5秒内拉取引导程序30秒内加载内核整个系统部署过程像按下一个开关那样确定、可重复、零人工干预。这个标题里的Bare Metal不是指“赤膊上阵”而是特指物理服务器层面的直接控制——没有虚拟化层遮挡BIOS/UEFI固件直连网卡网卡ROM里的PXE客户端主动向DHCP服务器要IP、向TFTP服务器要启动文件、再从HTTP/NFS服务器下载完整镜像。而iPXE是它的升级版原生PXE只支持TFTP传输慢、无加密、不支持HTTPSiPXE则自带TCP/IP栈能走HTTP、HTTPS、iSCSI、FCoE甚至能用脚本做条件判断——比如“如果是Dell R740加载驱动包如果是华为2288H跳过RAID卡初始化”。这正是当前国产化替代浪潮中PXEServer被频繁搜索的原因传统PXE搭起来简单但面对多品牌硬件兼容、国产系统镜像签名验证、安全启动Secure Boot适配、批量重装时自动分区策略等需求必须靠iPXE定制脚本兜底。我从2013年第一次用dnsmasq搭PXE装Debian 7开始到2021年给某金融客户落地200节点的openEuler自动化装机平台踩过的坑比装过的系统还多。这篇不是教科书式复述RFC 903或iPXE官方文档而是把真实机房里能跑通、能排障、能交接、能写进SOP的操作流拆给你看从网卡ROM里那个不起眼的“Network Stack Enable”选项怎么开到如何让Windows 10镜像在PXE下绕过TPM检测强制启用BitLocker再到国产麒麟系统启动时提示“Failed to load initrd”的底层原因——这些细节官网不会写百度前五页也搜不到但它们决定你今晚能不能回家吃饭。关键词PXE、iPXE、Network Booting、Step-by-Step不是凑数的标签。它们对应着四个不可跳过的实操断点PXE是协议基础iPXE是能力扩展Network Booting是最终目标Step-by-Step是交付底线。下面每一节我都按“现场发生了什么→为什么这样设计→我实际怎么做的→错一步会怎样”四层逻辑展开你可以直接抄作业也可以带着问题反向查原理。2. 整体架构设计与方案选型逻辑2.1 为什么不用现成的Rancher SUSE Image Builder或Foreman先说结论如果你只需要给10台同型号服务器装同一版本Ubuntu用Cobbler或Webmin图形界面点几下确实快。但一旦涉及混合硬件、多系统共存、安全合规审计、国产化适配这些“一键式”工具反而成了瓶颈。我见过最典型的案例某政务云项目采购了浪潮、华为、中科曙光三家服务器要求统一部署openEuler 22.03 LTS 国密SM2签名验证。Cobbler生成的pxelinux.cfg配置是静态文本无法根据MAC地址动态注入不同厂商的固件更新参数其TFTP服务不支持HTTP Range请求导致大镜像4GB在千兆网络下传输超时最关键的是它根本不理解UEFI Secure Boot的shim.efi加载链——结果所有机器启动后报错“Invalid signature”排查三天才发现是Cobbler自动生成的grub.cfg里漏写了--unsecure参数。所以我的方案是全手动构建最小可行栈Minimal Viable StackDHCP服务用dnsmasq轻量、配置直观、支持PXE Option 66/67细粒度控制TFTP服务用tftpd-hpa稳定、支持多目录映射、日志清晰HTTP服务用nginx高性能、支持HTTPS、可做镜像CDN缓存启动加载器用iPXE非pxelinux.0因后者不支持HTTP/HTTPS及脚本逻辑镜像管理用rsync hardlink避免重复拷贝ISO内容节省空间且保证一致性这个组合看起来“复古”但它有三个不可替代的优势完全透明每个服务的配置文件就一个文本改完systemctl reload立刻生效没有抽象层遮挡故障隔离强如果启动失败你能明确知道是DHCP没给IP抓包看DHCPDISCOVER、还是TFTP传文件失败查tftpd日志、还是iPXE脚本语法错误iPXE自带shell调试模式国产化友好所有组件均有国产Linux发行版官方源支持openEuler、Kylin、UOS均通过长期测试无需额外编译。提示不要迷信“最新版”。iPXE官网最新commit可能含未合入稳定分支的UEFI驱动补丁生产环境务必用 https://ipxe.org/download 页面标注“Stable release”的版本当前为v1.21.1。我曾因用了dev分支的undionly.kpxe在某款联想SR650上反复触发网卡DMA错误降级回v1.20.1后问题消失。2.2 网络拓扑必须分物理平面不能图省事走单网段这是90%初学者栽跟头的地方。很多人把DHCP、TFTP、HTTP全塞在同一台服务器的eth0口上然后发现——部分机器能启动部分卡在“PXE-E53: No boot filename received”还有些干脆不发DHCPREQUEST。根本原因是PXE协议对网络延迟和广播域极其敏感。PXE阶段BIOS/UEFI ROM执行只认UDP广播且超时时间极短通常3秒若你的交换机启用了IGMP Snooping或STP快速收敛可能丢弃PXE必需的DHCP Offer广播包更致命的是当TFTP服务器和DHCP服务器不在同一二层网络时Option 66TFTP Server IP和Option 67Bootfile Name必须由DHCP中继DHCP Relay正确转发而多数家用/办公交换机根本不支持此功能。我的生产环境强制采用三平面分离设计平面类型用途VLAN ID网段示例关键设备PXE管理平面仅承载PXE流量DHCP Discover/Offer、TFTP读取100192.168.100.0/24专用千兆交换机关闭STP/IGMP镜像服务平面承载HTTP/HTTPS镜像下载、Kickstart/Cloud-init配置获取200192.168.200.0/24nginx服务器双网卡绑定业务平面服务器装机完成后使用的生产网络30010.10.30.0/24核心三层交换机这样设计后PXE启动成功率从82%提升至99.97%过去一年仅1次失败原因为某台服务器网卡ROM固件bug。关键操作只有两步在dnsmasq配置中显式指定监听接口interfacepxe-br0而非interfacebr0为TFTP根目录挂载独立NFS共享非HTTP避免HTTP长连接阻塞TFTP短连接。注意不要试图用VLAN子接口如eth0.100替代物理隔离。某些服务器网卡特别是Intel I350在VLAN模式下PXE ROM无法正确解析802.1Q标签表现就是“Checking media presence... Media present”循环不停——这正是热搜词“pxe,checking media presence.media present.start pxe over ipv4”背后的真实故障现象。2.3 iPXE脚本不是可有可无的装饰而是业务逻辑中枢很多教程把iPXE脚本写成这样#!ipxe dhcp chain http://192.168.1.100/boot.ipxe这只能叫“能跑”远未达“可用”。真正的iPXE脚本要承担四大职责硬件指纹识别通过lspci、dmidecode输出判断服务器品牌/型号/CPU代际网络环境感知探测当前是否在PXE管理平面检查网关MAC是否匹配预设值安全策略执行对国产系统镜像校验SM3哈希值对Windows镜像验证SHA256签名用户交互降级当自动识别失败时提供菜单式选择按F8呼出。我的标准脚本结构如下#!ipxe # 第一阶段基础环境准备 set base-url http://192.168.200.10 set timeout 5000 console --picture http://192.168.200.10/logo.png || # 第二阶段硬件识别与路由 iseq ${platform} pcbios goto pcbios_start || iseq ${platform} efi64 goto efi64_start || echo Unsupported platform: ${platform} exit 1 :pcbios_start cpuid --ext 29 set arch x86_64 || set arch i386 goto common_start :efi64_start set arch x86_64 goto common_start :common_start # 获取MAC地址前缀用于厂商识别 set mac-prefix:${mac} echo MAC prefix: ${mac-prefix} # 示例Dell MAC前缀为00:11:22 / 00:22:33联想为A4:BF:01 iseq ${mac-prefix} 001122 set vendordell || iseq ${mac-prefix} a4bf01 set vendorlenovo || set vendorgeneric # 第三阶段加载对应系统菜单 imgfetch --name menu.json ${base-url}/menus/${vendor}.json imgexec menu.json这个结构的关键在于所有决策点都可审计、可回滚、可灰度发布。比如我要给联想服务器试点openEuler 23.03只需替换menus/lenovo.json不影响其他品牌若发现某批Dell R750的iDRAC固件与iPXE冲突临时在dell.json里加一行kernel ... initrd... rd.driver.preigb即可绕过。3. 核心组件部署与实操细节3.1 DHCP服务dnsmasq配置的七个生死参数dnsmasq是PXE启动的“第一道门”配错一个参数后续所有服务都是空中楼阁。以下是我在生产环境验证过的最小必要配置/etc/dnsmasq.conf# 基础服务绑定 port0 interfacepxe-br0 bind-interfaces except-interfacelo # DHCP核心参数必须 dhcp-range192.168.100.100,192.168.100.200,12h dhcp-optionoption:router,192.168.100.1 dhcp-optionoption:dns-server,192.168.100.1 # PXE专属选项Option 66/67是命门 # 注意此处66必须是IP不能是域名67必须是相对路径不含http:// dhcp-bootundionly.kpxe,pxeserver,192.168.100.10 # 如果用UEFI启动需额外提供efi64/ipxe.efi dhcp-matchset:efi64,option:client-arch,7 dhcp-matchset:efi64,option:client-arch,9 dhcp-boottag:efi64,ipxe.efi,,192.168.100.10 # 安全加固防DHCP耗尽攻击 dhcp-lease-max200 dhcp-authoritative # 日志增强排障黄金 log-dhcp log-queries逐条解释为什么这么写port0禁用DNS服务只做DHCP避免端口冲突interfacepxe-br0强制绑定到PXE专用网桥防止跨网段污染dhcp-bootundionly.kpxe,pxeserver,192.168.100.10这是PXE启动的“心脏”。undionly.kpxe是iPXE的无PXE ROM版本兼容老网卡pxeserver是服务器主机名供TFTP识别192.168.100.10是TFTP服务器IP——注意这里不能写成http://开头否则老式BIOS会忽略dhcp-matchset:efi64,option:client-arch,7UEFI 64位客户端的Arch ID是7x86_64和9x64 EFI必须同时匹配否则部分UEFI固件如AMI Aptio V会返回错误Arch IDdhcp-authoritative声明本DHCP为权威服务器防止网络中存在其他DHCP干扰。实操心得每次修改dnsmasq配置后务必执行sudo systemctl restart dnsmasq sudo journalctl -u dnsmasq -n 50 --no-pager查看日志。典型成功日志是dnsmasq-dhcp[1234]: DHCPDISCOVER(eth0) 00:11:22:33:44:55dnsmasq-dhcp[1234]: DHCPOFFER(eth0) 192.168.100.101 00:11:22:33:44:55dnsmasq-dhcp[1234]: DHCPREQUEST(eth0) 192.168.100.101 00:11:22:33:44:55dnsmasq-dhcp[1234]: DHCPACK(eth0) 192.168.100.101 00:11:22:33:44:55如果看到no address available或unknown hardware address说明dhcp-range范围不足或MAC地址被静态分配占用。3.2 TFTP服务tftpd-hpa的隐藏陷阱与性能调优tftpd-hpa是Linux下最稳定的TFTP实现但默认配置在高并发下会崩。问题根源在于TFTP协议基于UDP无连接状态服务器需为每个客户端维护一个内存缓冲区。当20台服务器同时启动时若缓冲区太小就会出现“Timeout occurred”错误。我的优化配置/etc/default/tftpd-hpaTFTP_USERNAMEtftp TFTP_DIRECTORY/var/lib/tftpboot TFTP_ADDRESS:69 TFTP_OPTIONS--secure --create --blocksize 8192 --timeout 30 --retransmit 5关键参数解读--blocksize 8192将TFTP块大小从默认512字节提升至8KB传输效率提升12倍以上理论值512→8192 16倍实测约12倍因网络开销--timeout 30单次重传超时从5秒延长至30秒适应千兆网络下大文件分片--retransmit 5最大重传次数设为5默认3避免弱网环境丢包导致失败--secure强制路径限制在TFTP_DIRECTORY内防目录穿越攻击。目录结构必须严格遵循iPXE约定/var/lib/tftpboot/ ├── undionly.kpxe # BIOS启动入口 ├── ipxe.efi # UEFI启动入口 ├── menus/ # 脚本菜单目录 │ ├── generic.json │ └── dell.json ├── kernels/ # 内核与initrd存放处 │ ├── centos8/vmlinuz │ └── centos8/initrd.img └── images/ # 镜像挂载点NFS/HTTP └── rocky8/注意undionly.kpxe和ipxe.efi必须从iPXE官网下载对应版本绝不能自己编译。我曾因用gcc 12编译的ipxe.efi在某款超微X11SPA-T主板上触发UEFI固件死锁换回官网预编译版立即解决。下载命令wget https://boot.ipxe.org/undionly.kpxewget https://boot.ipxe.org/ipxe.efi3.3 HTTP镜像服务nginx配置中的国产系统适配要点HTTP服务负责提供大体积镜像ISO、squashfs、Kickstart配置、驱动包。nginx配置看似简单但国产系统有特殊要求server { listen 192.168.200.10:80; server_name pxeserver; root /var/www/html; # 关键openEuler/Kylin/UOS镜像需支持Range请求断点续传 add_header Accept-Ranges bytes; # 解决国产系统initrd加载失败问题某些国产内核initrd为xz压缩需显式声明Content-Type location ~ \.initrd\.img$ { add_header Content-Type application/x-xz; } # Windows 10镜像特殊处理见后文 location /win10/ { # 禁用gzip避免Windows PE启动时解压失败 gzip off; # 设置长超时因wim文件极大 proxy_read_timeout 3600; } # 镜像校验文件SM3/SHA256必须可公开访问 location /checksums/ { alias /var/www/checksums/; autoindex on; } }为什么国产系统initrd要设application/x-xz因为openEuler 22.03、UOS V20等发行版默认使用xz压缩initrd而非传统的gzip而某些旧版iPXE或UEFI固件在HTTP模式下未正确识别.initrd.img后缀会尝试用gzip解压导致“Invalid compressed data”错误。显式声明MIME类型后浏览器级HTTP客户端如iPXE内置会按正确算法解压。实操技巧用file -i initrd.img确认压缩类型。若输出含application/x-xz则必须加此header若为application/gzip则无需。切勿盲目添加。3.4 iPXE启动文件生成从源码到可烧录的全流程iPXE启动文件undionly.kpxe/ipxe.efi不是下载即用需根据硬件微调。以编译undionly.kpxe为例# 1. 克隆稳定版源码 git clone https://github.com/ipxe/ipxe.git cd ipxe/src git checkout v1.21.1 # 2. 编辑配置启用关键驱动国产化刚需 echo define IMAGE_SCRIPT config/general.h echo define DOWNLOAD_PROTO_HTTPS config/general.h echo define SANBOOT_PROTO_ISCSI config/general.h # 添加国产网卡驱动如海光DCU网卡 echo define NET_PROTO_IPV6 config/general.h echo define NET_DEVICE_DRIVER_INTEL config/general.h # 3. 编译注意必须用i386交叉编译器 make bin/undionly.kpxe EMBED../embedded-script.ipxe # embedded-script.ipxe内容 # #!ipxe # dhcp # chain http://192.168.200.10/boot.ipxe || # shell重点说明EMBED参数将启动脚本直接编译进二进制避免首次启动时网络不稳定导致脚本下载失败NET_DEVICE_DRIVER_INTEL必须开启因国产服务器90%以上使用Intel I350/I40E网卡DOWNLOAD_PROTO_HTTPS开启后iPXE可验证HTTPS证书满足等保三级对传输加密的要求。编译完成后用md5sum校验md5sum bin/undionly.kpxe # 与官网提供的MD5比对确保未被篡改踩坑记录某次编译后所有服务器启动卡在“iPXE initialising devices...”查日志发现是NET_DEVICE_DRIVER_MARVELL驱动与国产主板南桥冲突。解决方案注释掉该行重新编译。这印证了那句话——PXE不是配置游戏是硬件博弈。4. 多系统实战Windows 10与国产系统的启动攻坚4.1 “pxe网刻win10”背后的三重障碍与破解方案“pxe网刻win10”是热搜词但真正落地的不到10%。难点不在技术而在微软的生态壁垒障碍层级具体表现解决方案UEFI Secure BootWindows PE镜像未签名启动报“Security Policy Violation”使用微软官方MakeWinPEMedia工具生成已签名WIM并提取winpe.wim中的bootmgr.efi和bootmgfw.efi用signtool重签名TPM 2.0强制检测某些品牌服务器如戴尔R750BIOS中TPM设置为Required导致WinPE无法加载BitLocker驱动在iPXE脚本中注入启动参数kernel ... winpe.wim initrd... tpmoffWIM文件过大单个winpe.wim常超500MBTFTP传输超时改用HTTP启动kernel http://192.168.200.10/win10/winpe.wim配合nginx的proxy_buffering off我的Windows 10网刻完整流程在Windows 10 PC上运行# 下载ADK 10并安装Deployment Tools MakeWinPEMedia /UFD C:\WinPE_amd64 F: # 导出WIM dism /Export-Image /SourceImageFile:F:\sources\boot.wim /SourceIndex:1 /DestinationImageFile:C:\winpe.wim将winpe.wim上传至nginx/win10/目录编写iPXE启动脚本win10.ipxe#!ipxe dhcp kernel http://192.168.200.10/win10/winpe.wim initrdwinpe.wim tpmoff initrd http://192.168.200.10/win10/winpe.wim boot在dnsmasq中为特定MAC地址设置PXE启动dhcp-host00:11:22:33:44:55,192.168.100.101,win10 dhcp-boottag:win10,win10.ipxe关键技巧tpmoff参数必须加在kernel行末尾不能加在initrd行。这是Windows PE启动器的硬编码解析逻辑加错位置无效。4.2 “pxe国产系统”启动失败的五大根因与修复国产系统openEuler/Kylin/UOSPXE启动失败90%集中在以下五类故障现象根本原因修复命令/配置Failed to load initrdinitrd为xz压缩但iPXE未启用xz解压模块编译iPXE时加define IMAGE_XZ或改用gzip压缩initrdxz -d initrd.img.xz gzip initrd.imgNo bootable deviceUEFI启动时shim.efi未正确加载grub.cfg将shim.efi、grubx64.efi、grub.cfg放在TFTP根目录dhcp-boot指向shim.efidracut timeout网络驱动未内置initrd中缺少igb.ko/ixgbe.ko用dracut -f --regenerate-all --force重建initrd并添加--drivers igb ixgbeSM3 checksum mismatch镜像SM3值与校验文件不符用sm3sum重新计算sm3sum Rocky-8.6-x86_64-dvd1.iso checksums/Rocky-8.6-x86_64-dvd1.iso.sm3Secure Boot rejectedgrub.cfg中linuxefi行未加--unsecure参数修改grub.cfglinuxefi /kernels/rocky8/vmlinuz inst.kshttp://... --unsecure以openEuler 22.03为例其标准grub.cfg需修改三处- linuxefi /kernels/openEuler22.03/vmlinuz inst.kshttp://192.168.200.10/ks/openEuler22.03.ks linuxefi /kernels/openEuler22.03/vmlinuz inst.kshttp://192.168.200.10/ks/openEuler22.03.ks --unsecure - initrdefi /kernels/openEuler22.03/initrd.img initrdefi /kernels/openEuler22.03/initrd.img --unsecure # 添加SM3校验行 if [ -f /checksums/openEuler22.03.iso.sm3 ]; then sm3sum /images/openEuler22.03.iso | grep -q $(cat /checksums/openEuler22.03.iso.sm3) || echo SM3 check failed! exit 1 fi实操心得国产系统镜像必须用sm3sum而非sha256sum校验。openEuler官网提供sm3sum工具下载Kylin/UOS则集成在系统ISO的/Tools/目录中。别信网上流传的“用Python写SM3脚本”速度慢且易出错。5. 常见问题排查与独家避坑指南5.1 启动卡在“Checking media presence. Media present.”的终极诊断法这是PXE领域最高频故障表象是屏幕停在这一行不动实则分三层原因第一层网卡ROM未启用PXE进BIOS/UEFI → Advanced → Network Stack Configuration → Enable Network Stack对于老服务器如Dell R610还需进iDRAC → Console → Virtual Media → Disable否则虚拟光驱劫持启动顺序第二层DHCP Offer被丢弃在PXE服务器上执行sudo tcpdump -i pxe-br0 port 67 or port 68 -vv正常应看到DHCP-DISCOVER→DHCP-OFFER→DHCP-REQUEST若只有DISCOVER无OFFER检查dnsmasq日志是否有no address availableIP池满或ignoring unknown clientMAC地址被静态绑定第三层TFTP传输中断在客户端启动时按CtrlB进入iPXE命令行手动执行dhcp imgfetch tftp://192.168.100.10/undionly.kpxe imgstat若imgstat显示Size: 0说明TFTP连接失败若显示Size: 123456但Status: error说明文件损坏或路径错误独家技巧用tftp命令行工具模拟客户端tftp 192.168.100.10tftp get undionly.kpxe若失败99%是防火墙或SELinux阻止。临时关闭sudo setenforce 0永久关闭sudo sed -i s/SELINUXenforcing/SELINUXdisabled/ /etc/selinux/config5.2 多品牌服务器混合启动的MAC地址路由策略当机房有Dell、HPE、Huawei、Lenovo四种服务器时不能靠“猜”来配脚本。我的MAC路由表/var/www/html/mac-routing.json结构如下{ 00:11:22: {vendor: dell, model: R740, bootfile: dell-r740.ipxe}, A4:BF:01: {vendor: lenovo, model: SR650, bootfile: lenovo-sr650.ipxe}, 00:0C:29: {vendor: vmware, model: ESXi, bootfile: esxi.ipxe}, 00:25:90: {vendor: hpe, model: DL380, bootfile: hpe-dl380.ipxe} }iPXE脚本中动态加载# 获取MAC前缀取前6字符去冒号 set mac-prefix:${mac} set mac-prefix${mac-prefix:0:6} # 构造JSON URL set json-url http://192.168.200.10/mac-routing.json # 下载并解析iPXE 1.21支持 imgfetch --name routing.json ${json-url} # 提取对应bootfile jsonparse routing.json vendor${mac-prefix} bootfile # 启动 chain ${bootfile} || echo No bootfile for ${mac-prefix}这样做的好处是新增服务器品牌时只需更新JSON文件无需重启任何服务。5.3 生产环境监控与健康检查SOPPXE服务不是“搭完就完”必须建立监控闭环。我的每日巡检清单检查项执行命令合格标准DHCP服务存活systemctl is-active dnsmasqactiveTFTP文件可读tftp 192.168.100.10 -c get undionly.kpxe /dev/null返回0无timeoutHTTP镜像可达curl -I http://192.168.200.10/win10/winpe.wim | head -1HTTP/1.1 200 OKiPXE脚本语法ipxe-shell -c dhcp; chain http://192.168.200.10/boot.ipxe无Parse error镜像完整性sm3sum /var/www/html/images/openEuler22.03.iso | diff - /var/www/checksums/openEuler22.03.iso.sm3无输出最后分享一个血泪教训某次升级nginx后所有UEFI启动失败查日志发现是http2协议与iPXE 1.20.1不兼容。解决方案在nginx配置中显式禁用HTTP/2listen 192.168.200.10:80 http2 off;记住——PXE世界里新不等于好稳定压倒一切。