
机房里几十台裸金属服务器等着安装系统如果还靠插U盘、挂光驱一台台手动点整个人都会被机械劳动淹没。PXE预启动执行环境就是为了解决这类批量装机而生的目标服务器只要支持网卡引导就能通过网络自动获取IP、引导文件、安装介质和应答脚本从头到尾不需要人到现场按任何键。这篇文章从实际搭建过的角度把PXE自动化安装裸金属服务器的完整链路、关键配置和排错心得拆开讲清楚适合准备做批量装机的新手运维也适合自动化平台建设人员参考。1. 为什么服务器安装还专门搞一套PXE1.1 手工装机的四个瓶颈先说最传统的装机方式。拿到一台新拆箱的裸金属服务器运维一般要干这些事准备一个U盘或挂载ISO镜像、进入BIOS改启动顺序、选择安装介质、手动分区、设置主机名、设置密码、选择软件包然后等安装流程跑完再重启。单台机器顺利的话四十分钟到一个小时总是要的前提还是不遇到驱动缺失、分区选错这类问题。第一个瓶颈就是时间。一次给二十台、五十台扩容一台台操作下来一天基本就没了。而且这种活儿没有任何技术含量纯靠人肉反复点击团队里最熟练的老手也快不了多少。第二个瓶颈是状态不可控。不同批次机器可能用了不同镜像版本有人手动改了分区方案有人忘了做某种配置装完之后系统状态千奇百怪。等到后面出问题谁都不知道哪台机器当初是怎么装的。这种“隐性的环境差异”在集群故障排查时非常致命。第三个瓶颈是人工操作容易出错。BIOS里启动顺序看走眼把系统盘选错、分区时把原有的数据盘抹掉、软件包少勾了导致服务跑不起来——这些我都见过。手动操作越多出错的概率就越大。第四个瓶颈是远程场景根本没法进行。机房不在身边、或者只有带外管理卡人过不去就插不了U盘只能干瞪眼。这几个痛点叠加在一起使得网络引导几乎成了批量化交付的必选项。1.2 PXE把安装流程变成了什么PXE在这里面做的事可以理解成把“U盘里的安装程序”通过网络递送给服务器。服务器开机后会主动进入PXE流程先通过DHCP获取IP地址和引导服务器位置再用TFTP拉取一小段引导程序引导程序加载内核和initrd最后交给安装器去访问完整的安装仓库。配合自动应答文件分区、网络、软件包、时区和后置脚本全部自动完成。实际的用户体验就是把服务器开机的启动顺序调整为网络优先插上网线按下电源键然后等它自己装完最后SSH能连上就是一个成功交付的系统。整个过程中人工参与的只有物理接电和开机这一件事。所以PXE本质上是把安装介质、网络服务和配置策略三者分离。安装介质放仓库网络服务负责下发引导策略文件决定这台机器该装什么版本、怎么分区、初始化哪些组件。这套结构看起来很重但一旦跑起来后续扩容就只是“加机器、开机”两个动作。1.3 什么时候可以不用PXE不是所有场景都必须上PXE。单台机器且人就在现场直接U盘安装反而更快搭一套网络引导环境还需要维护多个服务不太划算。纯虚拟机场景用云平台的镜像模板克隆也更高效。还有一类基于克隆分发的环境只要模板做得干净批量复制的速度远超逐台安装。但裸金属服务器不一样它通常有固定的硬件配置、多样的机型、复杂的存储方案底层系统必须干净地从安装介质构建。这种场景下PXE仍然是最稳、最通用的基础手段。我的建议是如果团队刚到三台以上需要频繁重装或批量交付的裸金属布置一套PXE环境的时间成本绝对值回票价。2. 核心组件与协议拆解从DHCP到PXE菜单2.1 DHCP给裸机分配地址并指明引导方向裸机开机时完全不知道服务器在哪里整个PXE链条的起点就是DHCP探测。客户端先广播一个DHCP DISCOVERDHCP服务器在回应OFFER时除了给IP地址还会捎带两个关键的引导信息next-server下一跳服务器地址和boot file要下载的引导文件名。客户端拿到这两个信息才知道该去谁的TFTP目录里取什么文件。这里有个容易混淆的点。很多网卡固件在PXE阶段会发送特殊的DHCP选项请求比如选项66和选项67。标准DHCP配置文件里可以分别设置next-server和filename来回应而dnsmasq则用一行dhcp-boot简化处理。两种写法含义一样只是工具语法不同。在我现在用的环境里dnsmasq更顺手因为它的DHCP和TFTP是同一个进程在管少装一个服务排错链路也更短。还有一条生产经验DHCP分配出去的地址范围最好单独划给装机网段不要和业务网混在一起。PXE客户的启动行为相对“野蛮”如果这台机器配置错误或者有奇怪固件可能会对业务网络产生干扰。单独管理网段无论是抓包还是后续隔离都方便很多。2.2 TFTP第一公里的轻量文件传输DHCP告诉客户端前往哪台机器取文件之后客户端就会发起TFTP请求。TFTP是个非常古老的协议基于UDP 69端口没有复杂的确认机制也没有安全认证简单到网卡固件就能实现。正因为它简单它在整体流程里只负责传输那些“轻量级”的引导文件pxelinux.0、grub启动器、内核vmlinuz和initrd、菜单配置文件。很多人第一次搭PXE时会犯一个错误试图通过TFTP把整个ISO镜像传过去。这是一个很糟糕的主意。TFTP的块大小默认很小在局域网里传一个几百MB的文件会奇慢无比而且中断后没有续传机制任何一个丢包都会拖垮整个安装。正确做法是TFTP只传引导所需的小文件真正的大体量安装源交给HTTP或NFS。在我的习惯里TFTP根目录尽量保持精简。一个典型目录可能只有几个文件引导器、内核、initrd、一个pxelinux.cfg目录。这样不管是拷贝还是排查一眼能看明白。2.3 pxelinux.cfg配置文件查找顺序是排错突破口加载pxelinux.0以后它并不会自动知道要装什么系统而是会去TFTP服务器的pxelinux.cfg目录里查找菜单配置。这里的设计非常巧妙PXE会根据请求者的特征按顺序查找文件名以客户端MAC地址命名的文件格式是01-aa-bb-cc-dd-ee-ff前面的01表示以太网类型以客户端IP地址十六进制形式命名的文件比如10.0.0.101会变成0A000065最后兜底的文件default这个查找顺序是PXE排错的关键。想对某一台特定MAC的机器定制安装菜单只要创建对应的MAC文件就行想让一个网段走默认流程就只放default文件。我在维护多环境装机目录时经常靠这一机制实现“不同MAC走到不同安装参数”比改DHCP配置更直观。默认菜单文件里写的是SYSLINUX的语法主要包含label和append行。label是菜单里显示的名字append后面接着内核参数。内核参数会一路传给下一步加载的安装器所以inst.repo、ks这些关键信息都写在这里。2.4 安装仓库与自动应答文件真正开始读“安装光盘”引导器把内核和initrd下载到内存之后目标机就进入安装程序阶段。这时安装器会通过参数里的inst.repo去访问真正的软件仓库也就是安装介质的解压目录。RHEL系安装器会去读repodata目录下的元数据然后按软件包列表拉取包。仓库协议的选择早期环境里NFS用得很多但现在我强烈建议用HTTP。NFS对网络稳定性要求高安装过程中如果网络闪断常见root挂载会超时安装直接中断HTTP在这种场景下表现好得多而且nginx可以轻松撑起多台机器同时并发安装。另一个好处是系统装完以后这个HTTP地址还能继续当软件源用后续装补丁也方便。自动应答部分的接入简单直接。在内核参数行里加一句kshttp://10.0.0.10/ks/install.ks安装器会去拉取这个kickstart文件并根据里面的分区、包组、脚本指令执行安装。如果答案是yes安装过程基本不需要人工干预。这一步是整个自动化安装中“自动化”三个字的真正核心。2.5 固件差异Legacy BIOS、UEFI和iPXE不同固件对PXE的支持方式不太一样。老式Legacy BIOS环境下引导文件通常是pxelinux.0UEFI环境则更倾向于使用grubx64.efi或者ipxe.efi。UEFI的PXE网络堆栈和Secure Boot也会影响引导流程如果配置不对机器可能卡在PXE-E11这类错误或者直接跳过网络引导进了本地磁盘。这里给一个经验判断方法如果你看到PXE启动报错再跳到硬盘八成是引导文件名不对或PXE服务和固件不匹配。可以先在UEFI设置里把Secure Boot关掉再试试UEFI模式下专用的引导器。如果固件对PXE支持较差也可以用iPXE链来完成二次引导但这会稍微增加配置复杂度新手阶段不必立刻上。3. 实操搭建从零拉起一台能用的PXE安装环境3.1 环境清单与网络规划开始动手前先明确角色和IP规划。我习惯用一个独立的管理网段做装机避免影响其他业务。下面是一个典型的规划示例角色说明PXE安装服务器同时承担DHCP、TFTP、HTTP服务IP地址10.0.0.10安装目标机网卡接入管理网段假设MAC为aa:bb:cc:dd:ee:11操作系统介质以RHEL系ISO为例客户端IP池10.0.0.100到10.0.0.200服务器本身配两块网卡也不奇怪一块连接稳定业务网络用于管理另一块专用于装机网络。多网卡情况下dnsmasq监听接口必须写对否则客户端发的广播包根本到不了DHCP服务。镜像文件建议提前解压或者挂载到仓库目录。如果只想快速验证直接挂载ISO也行但生产环境我更推荐把ISO解压到独立目录这样后面不管是更新补丁包还是做定制化都更灵活。3.2 基于dnsmasq的DHCPTFTP配置我先把核心的dnsmasq配置贴出来然后逐行解释# /etc/dnsmasq.conf interfaceeth1 bind-interfaces dhcp-range10.0.0.100,10.0.0.200,255.255.255.0,12h dhcp-option3,10.0.0.1 dhcp-option6,10.0.0.10 dhcp-bootpxelinux.0,pxeserver,10.0.0.10 enable-tftp tftp-root/var/lib/tftpbootinterfaceeth1严格控制服务只跑在装机网卡上。bind-interfaces在部分多网卡机器上是必须的但也要注意如果地址被其他服务占用dnsmasq会直接启动失败。dhcp-range给出客户端地址池租期12小时足够一次完整安装。dhcp-option3指定网关dhcp-option6指定DNS这两项会让安装后的系统网络配置更干净。dhcp-boot里的三个参数分别是引导文件名、服务器名、服务器IP我这里为了兼容性直接写了IP。最后打开内置TFTP并设置根目录。启动之后可以检查一下进程状态和端口监听systemctl restart dnsmasq ss -ulnp | grep -E :53|:67|:69如果看到DNS和DHCP都在监听说明服务已经就绪。这里有个容易踩的坑dnsmasq默认同时管理DNS缓存如果你不想让它接管DNS记得在配置里写port0或者单独关闭DNS功能。3.3 准备引导文件与内核initrdDHCP和TFTP跑起来后接下来准备TFTP根目录里的内容。以RHEL系为例mkdir -p /var/lib/tftpboot/pxelinux.cfg cp /usr/share/syslinux/pxelinux.0 /var/lib/tftpboot/ mount -o loop rhel-9.iso /mnt/ cp /mnt/images/pxeboot/vmlinuz /var/lib/tftpboot/ cp /mnt/images/pxeboot/initrd.img /var/lib/tftpboot/Syslinux的引导器一般随发行版安装包提供也可以从ISO的isolinux目录里提取。这里要注意文件权限默认配置下TFTP服务以特定用户运行如果文件权限不足会导致客户端下载失败。接着写默认菜单/var/lib/tftpboot/pxelinux.cfg/defaultdefault linux label linux kernel vmlinuz append initrdinitrd.img inst.repohttp://10.0.0.10/repo/rhel9 kshttp://10.0.0.10/ks/install.ksappend行里的inst.repo不能省否则安装器最后会在“选择安装源”这里卡住。ks指向应答文件如果这一项没写安装器会进入交互式提问流程自动化就算白搭了。如果网络里有UEFI的机器还需要另外准备grub引导器并在DHCP配置里根据架构返回不同文件名。这里的判断逻辑略微复杂但做生产系统时必须要覆盖到。3.4 Nginx发布安装源和应答文件仓库服务和应答文件服务可以放在同一个nginx里。直接看配置server { listen 80; server_name 10.0.0.10; root /data/pxe; autoindex on; location /ks/ { alias /data/pxe/ks/; } }然后把ISO内容拷贝到仓库目录mkdir -p /data/pxe/repo/rhel9 cp -a /mnt/* /data/pxe/repo/rhel9/ mkdir -p /data/pxe/ks cp /data/ks/install.ks /data/pxe/ks/install.ks chmod -R 644 /data/pxe/ks/* chmod 755 /data/pxe /data/pxe/ks /data/pxe/repo权限设置是这里的隐形坑。目录如果没有执行权限nginx会返回403安装器访问仓库时报错信息又不够直观容易让人绕进死胡同。调试时可以直接在另一台机器用curl验证curl -I http://10.0.0.10/repo/rhel9/ curl -I http://10.0.0.10/ks/install.ks两个请求都返回200说明HTTP侧已经就绪。3.5 编写一份可复用的KickstartKickstart文件是自动安装的核心策略。下面给一份最小可用版本并解释关键命令install url --urlhttp://10.0.0.10/repo/rhel9 lang en_US.UTF-8 keyboard us rootpw --iscrypted $6$xxxxxx timezone Asia/Shanghai network --bootprotodhcp --devicelink --activate zerombr clearpart --all --initlabel autopart --typelvm bootloader --locationmbr services --enabledNetworkManager reboot %packages core %end %post --log/root/install.log echo 基础装机完成 /root/install.log %end逐项说一下url指定安装源rootpw必须是加密哈希不要明文写密码network --devicelink是关键建议不要绑死eth0因为不同服务器网卡命名可能不同用link参数让安装器选择有链路的那个网卡clearpart --all会清空磁盘所有分区如果你对数据盘有要求这里的写法要更谨慎autopart会自动采用LVM分区适合快速验证生产环境还是建议手动写清分区逻辑。%packages段定义了要装的软件包组core相当于最小系统的核心包组。生产环境一般在这基础上增加一些必备工具。%post段用于装完系统后执行脚本比如注册监控、下发基础配置、执行初始化脚本等。这个文件在实际使用中一定会补充很多业务项但核心骨架就是上面这些。3.6 客户端引导与端到端验证一切配置就绪后把目标服务器网络启动设为第一启动项接上装机网线开机。如果你用的是Legacy BIOS应该能在屏幕上看到SYSLINUX菜单如果走UEFI则可能是GRUB菜单。菜单出现后选择对应的label回车紧接着能看到内核启动日志。想确认网络请求走得对不对在PXE服务器上抓包最直观tcpdump -i eth1 port 69 or port 80 -nn正常流程应该依次出现DHCP交互、TFTP的RRQ请求、HTTP GET仓库和ks文件的记录。根据这些请求的落点基本能判断出故障是出在引导阶段还是仓库阶段。我在第一次完整跑通时从按下电源键到SSH能连上大概花了十几分钟大部分时间都在等软件包安装。这个速度对于批量装机来说是非常可接受的。4. 常见问题与排查技巧实录4.1 高频故障对照表把PXE搭建中常见的问题整理成了一张表按“现象、原因、处理”三条来列故障现象常见原因处理方法开机提示PXE-E61 Media test failure网线没插好或PXE服务器不可达先检查链路再确认DHCP服务所在网段客户端拿到IP但反复请求TFTPfilename不对或TFTP根目录缺文件核对dhcp-boot里的文件路径检查TFTP目录权限内核加载后卡在安装源界面inst.repo地址不可达或仓库权限不对用curl验证仓库路径检查nginx日志提示Kickstart文件未找到ks参数写错或HTTP返回403单独访问ks文件确认目录执行权限UEFI机型反复重启或黑屏Secure Boot拦截引导先临时关闭Secure Boot或换用签名引导器安装完成后重启进不了系统bootloader参数与磁盘类型不匹配检查安装日志确认磁盘是sda还是nvme0n1这张表覆盖面很广基本涵盖了从零搭建时可能碰到的大多数问题。遇到问题时先对照这张表定位大致方向再结合日志做进一步排查。4.2 一次真实踩坑TFTP反复超时某次批量扩容DHCP分配IP正常客户端也能拿到地址但TFTP下载一直超时。我检查了dnsmasq日志和tftp根目录都没发现问题。后来仔细看网络拓扑才发现客户端和PXE服务器中间隔着三层交换机交换机上的DHCP Snooping功能没有放行UDP 69端口导致TFTP包被静默丢弃。这个案例让我养成了一个习惯遇到协议层面异常先不要死盯服务器配置先想想中间网络设备有没有做干扰过滤。用tcpdump在服务器上看不到TFTP请求到达基本就能判断问题出在链路中间而不是服务本身。4.3 多网卡与设备命名不一致的处理裸金属服务器通常有多个网卡管理网口不一定是厂商默认的第一张卡。很多人会把系统和PXE引导用的网卡搞混导致开机后PXE请求根本发不到管理网段。处理办法有三个方向。第一步在BIOS里确认PXE接口对应的MAC地址把它记录下来。第二步在dnsmasq里给这个MAC设置固定租约例如dhcp-hostaa:bb:cc:dd:ee:11,10.0.0.101这样每回重启安装都能拿到同一个IP后续排查日志会很省事。第三步在pxelinux.cfg里用MAC命名的配置文件来固定安装参数保证这台机器无论从哪个版本菜单进去最终走的都是预期流程。4.4 在目标机上快速收集安装日志安装过程出现问题PXE服务器上的日志只能帮你定位到文件传输阶段更深层的安装器错误还得看目标机。RHEL系的anaconda安装器支持从终端切换控制台按CtrlAltF1可以看到详细日志。如果无法物理接触服务器可以在kickstart或内核参数里配置远程日志服务。另外安装器崩溃时往往会在屏幕最后保留一段错误堆栈拍照记录比口头描述靠谱得多。我处理远程装机问题时通常会让机房同事把屏幕照片发过来再配合nginx访问日志判断卡在哪个步骤效率比自己盲猜高得多。5. 让整套方案更进一步的一些个人经验5.1 用模板渲染来管理Kickstart静态Kickstart文件一旦多了维护就是灾难。我现在会把一个ks文件拆成公共头、软件包段、%post段再用模板方式渲染。比如用Shell和sed做轻量替换# build_ks.sh cp install.ks.template /tmp/install.ks sed -i s/__HOSTNAME__/${HOSTNAME}/g /tmp/install.ks sed -i s/__ROOTPW_HASH__/${ROOTPW_HASH}/g /tmp/install.ks这样做的好处是每次变更只改一个变量不用维护几十份只有主机名或密码不同的静态文件。再进一步还可以把模板接入前端页面让操作人员在网页上填一个表单点击后自动生成ks文件。团队协作时这样做的效率提升非常明显。5.2 利用DHCP租约与指纹区分装机路径同一台PXE服务器可能同时服务测试环境、开发环境、生产环境。怎么让不同机器自动走进对应菜单我的做法是用DHCP租约规则区分为不同MAC段分配不同的固定地址再按IP十六进制命名的pxelinux.cfg文件控制菜单。也有一些场景用vendor-class选项来区分固件架构把BIOS和UEFI机器分流到不同引导文件。在一个实际项目里我甚至通过接入交换机的circuit-id区分机柜位置再自动生成主机名和Ansible分组。机器开机自动装系统装完直接加入对应集群整个过程无需人工指定角色。这套机制虽然初期配置麻烦但一旦跑通后续扩缩容的自动化程度会非常高。5.3 在%post阶段注入初始化动作只把系统装完不算交付还要把初始化做完。%post段是这里的主战场。我通常会在%post里完成几件事设置Yum源、关闭不必要的服务、下发监控agent、执行基础加固脚本、拉取Ansible playbook并运行。%post --interpreter/bin/bash curl -s http://10.0.0.10/bootstrap/init.sh | bash %end使用%post时有几个细节。默认情况下%post会在chroot环境中执行如果你需要访问安装阶段生成的物理信息可能要加--nochroot。另外%post里的脚本要考虑到幂等性因为同一份脚本可能被重复执行如果每次都做“追加写配置”这类操作容易造成重复内容。5.4 安全边界设计PXE链路本身没有加密TFTP也是明文协议所以必须把它限制在可信网络内。我的原则是PXE服务只监听专用管理网段绝不与业务网共用DNS和IPv6相关的DHCP选项在做网络隔离时都要一起检查netfilter只放行TFTP和HTTP端口给指定子网。还有一个经常被忽略的点ks文件里不要写明文密码或敏感令牌。如果确实需要注入凭据建议在%post脚本里从一个受控的API动态获取而不是直接把秘密写死在应答文件里。整体安全设计做扎实之后这套装机系统就既能享受自动化效率又不会成为一个容易被人利用的通道。回看我搭这套环境的经历最有价值的可能不是某一个配置命令而是把整条链路串起来以后对服务器的启动、引导和安装流程建立了完整认知。建议你也找两台机器亲手试一次哪怕是最小的环境也一定会踩到文档里没写的问题。把这个过程走完后面做再复杂的自动化交付心里都有底。