☰
PXE批量装机从原理到实战:DHCP+TFTP+HTTP+kickstart无人值守部署
2026/10/16 8:12:39 网站建设 项目流程

做运维的人,迟早会遇到批量装机这件事。一天一两台机器,手工插U盘还能忍,可一旦面对几十上百台的物理机或虚拟机,一个人通宵装系统,装到后面手指头都是机械动作,甚至还会因为某个镜像版本漏了更新,把整批机器装成旧版本,第二天又要推倒重来。我的解决办法是搭一套PXE批量装机环境,让客户端开机时从网卡引导,自动完成系统安装。这篇文章就从原理、部署、配置到踩坑,完整拆一遍PXE批量装机,适合正在做Linux运维、网络管理,或者负责机房/实验室环境交付的工程师。

1. 为什么需要PXE批量装机

1.1 传统装机方式的痛点

手工装机的方式看着简单,实际上一旦规模上来,问题非常多。

拿U盘安装来说,你需要先准备一个安装盘,一台一台插上去,选择启动项,等待复制文件,然后手工分区、设置密码、配置网络。如果是同样的系统装十台,重复劳动就非常明显。更难受的是,机器数量一多,很容易搞混哪台装了哪个版本、哪台配了哪组网段。我见过有同事在新一批机器上,因为U盘镜像版本不一致,装出来的系统底层驱动都不一样,最后排查环境问题时浪费了大半天时间。

光盘装机更不用提,还得一台台换盘,光驱故障率也不低,盘片损坏、读取变慢都是实际会遇到的事。远程机房场景下尤其麻烦,不可能为了重新装一台机器专门跑一趟现场,哪怕有远程管理卡,能不能挂载ISO还要看硬件环境。

PXE批量装机解决的正是这类问题:客户端只要支持网络启动(现在主流服务器和多数虚拟化平台都支持),开机后就能从网络自动获取引导文件,走完安装流程,全程不需要人工干预。整个过程中,人的工作被集中到“准备服务端”这一步,之后只要批量开机就行。

1.2 PXE的工作流程

PXE全称是Preboot eXecution Environment,本质是Intel定义的一套网络引导标准。客户端在BIOS/UEFI阶段,如果配置了网卡启动,它会向网络发DHCP请求,拿到IP之后还会拿到两个关键参数:一个是TFTP服务器的地址,另一个是要下载的引导文件名称。

整个流程拆开看是这样:

  1. 客户端开机,网卡固件发出DHCP广播。
  2. DHCP服务器分配IP,并同时返回next-server和filename字段。
  3. 客户端从TFTP服务器下载PXE引导程序(传统BIOS下通常是pxelinux.0,UEFI下是grubx64.efi之类)。
  4. 引导程序读取TFTP根目录下的配置文件(如pxelinux.cfg/default),里面写明了要加载哪个内核、initrd以及启动参数。
  5. 内核和initrd下载完成后,内核启动,挂载HTTP/NFS服务器上的系统镜像源。
  6. 安装程序(以Linux为例是Anaconda)开始工作,如果配置了kickstart文件,就能全自动安装,否则会进入手动安装界面。

理解了这条链路,后面的配置就有方向了。PXE不是一个独立服务,而是DHCP、TFTP、HTTP/NFS、引导程序、安装镜像这几个组件互相配合的结果。

1.3 适用场景判断

PXE不是所有场景都适合。我的经验是,以下情况收益最大:

  • 同一型号或同一批硬件规格的机器数量较多,系统版本要求一致。
  • 无人值守场景,比如机房巡检后需要批量重装,或者实验环境需要快速恢复。
  • 多台机器需要同时安装不同系统版本,可以通过启动菜单选择,仍然比插盘高效。
  • 远程机房,物理接触困难,但网卡启动和服务器电源管理可用。

如果只是单台机器急需重装,或者网络环境极不稳定、交换机端口有安全限制,那就老老实实用U盘/ISO,没必要为了单台机器搭一套PXE。另外,PXE依赖广播和DHCP,如果网络里存在严格的端口隔离或DHCP Snooping策略,需要先协调好网络配置,否则会出现各种“找不到启动服务”的问题。

2. 环境准备与组件选型

2.1 最小化组件清单

在动手之前,先把需要准备的东西列全。基于我实际搭建的最小体系,以下组件缺一不可:

组件作用常见实现
DHCP服务分配IP,同时告知引导文件位置dnsmasq、isc-dhcp-server
TFTP服务提供pxelinux.0、内核、initrd等小文件tftp-hpa、dnsmasq内置tftp
HTTP服务提供系统镜像和kickstart文件nginx、apache、lighttpd
引导程序负责读取菜单并加载内核syslinux(BIOS)、grub2-efi(UEFI)
系统镜像安装源,可以是ISO挂载目录,也可以解包后的树CentOS/Debian/Ubuntu的ISO

额外建议准备一台测试用的虚拟机或物理机,配置成“磁盘启动失败后自动回退到网络启动”,这样不影响已有系统,可以反复验证。

我比较推荐的组合是:DHCP用dnsmasq或isc-dhcp-server,TFTP用tftp-hpa,HTTP用nginx。如果你只是为了快速测试,也可以用dnsmasq同时承担DHCP和TFTP,进一步减少服务数量。不过正式环境我更倾向于拆开,便于日志排查和故障隔离,这个问题下面会详细说。

2.2 网络规划与IP分配策略

PXE环境里的网络规划需要提前想好,否则后面会非常痛苦。

我通常用一个独立的管理网段来跑PXE,比如模拟项目环境里用192.168.30.0/24这个网段。服务器IP固定为192.168.30.10,网关是192.168.30.1,DHCP地址池设为192.168.30.100到192.168.30.200,池子外面再预留一些IP给管理口、网络设备和其他固定主机。

地址池大小的估算逻辑是:如果单次批量装50台,池子最好至少能有2倍数量的地址,避免客户端因租约问题反复冲突。DHCP租约时间在PXE安装场景下可以缩短,比如600秒,因为安装完成后系统就不再用这个临时租约了。

如果你的环境是跨VLAN部署,需要在三层交换机上配置DHCP Relay,DHCP服务器还要能识别来自不同VLAN的请求,并且返回对应的TFTP服务器地址。这部分配置相对复杂,建议第一次搭PXE时先在同网段跑通,再考虑跨VLAN。

2.3 传输协议的选型思路

PXE引导阶段,小文件用的是TFTP,这点由PXE标准决定。但进入安装程序后,系统镜像源的访问协议是可以自由选择的,常见的有NFS、HTTP、FTP。

我更推荐用HTTP做安装源,理由有几个:

  • HTTP的端口固定是80/8080,防火墙策略简洁,不容易被中间设备拦截。
  • HTTP是基于TCP的,传输大文件时比NFS和TFTP更稳定,特别在并发客户端多的时候不会像TFTP那样频繁丢包重传。
  • 权限配置简单,只要nginx或apache目录可读即可,不需要考虑NFS的exports、SELinux布尔值、客户端挂载选项等一堆细节。

NFS也不是不能用,早期很多教程喜欢用NFS,因为它挂载后可以直接读取镜像目录。但实际用下来,NFS对网络抖动更敏感,且NFS服务端配置稍有不慎就会出现nobody权限问题,客户端挂载后看到目录但无法读取文件。HTTP则没有这个烦恼,你只需要确保目录索引可读,安装器直接从URL拉文件就行。

3. 核心服务部署:DHCP、TFTP、HTTP与PXE引导

3.1 DHCP地址池与引导参数配置

以isc-dhcp-server为例,核心配置写在/etc/dhcp/dhcpd.conf里。针对PXE,关键不是地址池,而是next-server和filename这两个参数,它们是客户端找到引导程序的钥匙。

subnet 192.168.30.0 netmask 255.255.255.0 { range 192.168.30.100 192.168.30.200; option routers 192.168.30.1; option domain-name-servers 192.168.30.1; default-lease-time 600; max-lease-time 7200; next-server 192.168.30.10; filename "pxelinux.0"; }

next-server告诉客户端“你去192.168.30.10下载引导文件”,filename告诉它“要下载的文件名是pxelinux.0”。这两个字段协同工作,缺一不可。

如果你的网络里已经有其他DHCP服务器,比如路由器或防火墙自带DHCP,一定要避免冲突。同一个广播域里出现多个DHCP服务器,客户端获得的IP可能随机来自其中任何一个,PXE引导也会变得不稳定。我的做法是:在DHCP服务器上配置ignore unknown-clients,或者直接把PXE专用DHCP独立部署在测试VLAN里,不让它和日常办公网络混在一起。

3.2 TFTP服务与pxelinux.0

TFTP的部署不复杂,但有几个坑需要注意。

先装好tftp-hpa和syslinux:

yum install -y tftp-server syslinux # 或是 apt install -y tftpd-hpa pxelinux syslinux-common

syslinux软件包里提供pxelinux.0引导文件。传统BIOS模式下,把它复制到TFTP根目录。TFTP根目录我习惯设置为/var/lib/tftpboot。

mkdir -p /var/lib/tftpboot/pxelinux.cfg cp /usr/share/syslinux/pxelinux.0 /var/lib/tftpboot/

这里有个容易踩的坑:systemd管理的tftp服务默认使用socket激活模式,也就是有请求时才启动,响应会有一点延迟。批量安装时几十台机器同时请求,socket模式很容易出现部分客户端连接超时。建议禁用tftp.socket,只启动tftp.service,让进程常驻:

systemctl disable tftp.socket systemctl enable tftp.service systemctl restart tftp.service

接下来是引导菜单文件/var/lib/tftpboot/pxelinux.cfg/default。一个最基础的菜单如下:

DEFAULT menu.c32 PROMPT 0 TIMEOUT 60 MENU TITLE PXE Boot Menu LABEL linux MENU LABEL Install CentOS 7 x86_64 KERNEL vmlinuz APPEND initrd=initrd.img inst.repo=http://192.168.30.10/ISO/CentOS7 ks=http://192.168.30.10/ks/ks.cfg

这里KERNEL指向的vmlinuz和APPEND里的initrd.img,都是从系统镜像的isolinux目录里拷贝出来的。注意它们的路径是相对TFTP根目录的,所以直接放在根目录即可。

menu.c32来自syslinux,它让菜单有基本的图形渲染效果。如果没有这个文件,可以只保留DEFAULT和APPEND配置,也能启动,只是界面是文本列表。

3.3 HTTP镜像源和内核启动参数

HTTP服务我选择nginx,配置也比较省心。把ISO解压到网站目录,或者直接挂载ISO到目录也完全可以。

mkdir -p /var/www/html/ISO/CentOS7 mount -o loop CentOS-7-x86_64-Minimal.iso /var/www/html/ISO/CentOS7

这时候客户端在启动参数里写inst.repo=http://192.168.30.10/ISO/CentOS7,安装程序就会从这个HTTP目录里读取安装包元数据和软件包。

这里有一个重要细节:Anaconda安装程序从内核启动参数获取repo源和kickstart源。如果只给repo不给ks,安装程序会进入交互界面询问你语言、键盘、磁盘等设置,顶多省去镜像介质步骤。要实现真正无人值守,必须用kickstart文件,也就是在上面的APPEND里同时指定ks参数。

另外,如果客户端是UEFI启动,pxelinux.0是不能用的。UEFI环境需要对应的EFI引导文件,比如grubx64.efi或者shimx64.efi,配置文件也变成grub.cfg。检测方法很简单:进入启动菜单如果报“文件找不到”,而你又确定pxelinux.0位置没问题,那就要确认机器是不是UEFI模式。现在新出的服务器和笔记本默认UEFI居多,所以我在搭建PXE时会同时准备BIOS和UEFI两套引导文件。

4. 自动化无人值守:kickstart配置解密

4.1 ks.cfg核心段

kickstart会自动弹出的安装界面翻译成一份配置文件,Anaconda读过之后按文件内容执行。它本质上就是一个文本文件,任何人拿到模板都能看懂。

一个最小可用的CentOS 7 ks.cfg大致是这样:

#version=DEVEL install url --url=http://192.168.30.10/ISO/CentOS7 lang en_US.UTF-8 keyboard us network --bootproto=dhcp rootpw --iscrypted $1$somehash... authconfig --enableshadow --passalgo=sha512 selinux --disabled firewall --disabled clearpart --all part /boot --fstype=xfs --size=1024 part / --fstype=xfs --size=1 --grow part swap --size=4096 bootloader --location=mbr %packages @core wget vim %end

各段的逻辑很清楚:url指定安装源,network指定网卡获取IP方式,clearpart和part负责分区,rootpw设置加密后的root密码,%packages里写需要安装的软件包组。

要注意rootpw字段里的加密hash不能直接放明文密码,Anaconda在生成ks时可以通过grub-md5-crypt或openssl生成。实际运维中,我习惯先把明文密码写在一个临时文件里,用openssl passwd -6一次性生成,再粘到ks中,这样内容不会泄露。

4.2 从手动到无人值守

有人可能觉得,既然有了ks文件,是不是所有情况都能无人值守了?并不是。ks配置里如果缺少某些必填项或者写了无效参数,Anaconda会弹回交互界面。比如network段如果同时写了多个网卡且没有指定哪块,安装器可能还是会问你网络配置。

我的建议是:第一次测试时不要把ks配置写得太复杂,先用最简模板跑通,再逐步增加软件包、分区、网络、自定义脚本。让问题减到最少,才方便定位是PXE链路的问题还是ks本身的问题。

在启动参数里加上ks=http://192.168.30.10/ks/ks.cfg后,客户端安装过程完全不需要键盘鼠标。如果你在一个物理机房间里同时开50台机器,只需要保证所有机器都从网卡启动,然后等待即可。安装完的系统会自动重启,到时候根据预设策略就能进入正式系统了。

4.3 批量场景中的参数化技巧

批量装机真正的难点不在“装完”,而在“每台机器拿到符合预期的配置”。如果50台机器都通过DHCP拿到临时IP,安装出来的系统也都用DHCP,看起来可以,但生产环境通常希望服务器分配固定IP,或者主机名按照一定规则生成。

一个很实用的技巧是用%pre脚本在系统安装前执行一段shell,然后动态生成一个包含网络配置的ks片段,再通过%include引入。

比如我在HTTP服务器上放一个mac_ip.txt文件,每行格式是“MAC地址 IP地址”,%pre脚本里用客户端自身的MAC匹配行,把IP写入临时文件/tmp/network.ks:

%pre MAC=$(cat /sys/class/net/$(ls /sys/class/net | grep -E '^e|^en' | head -1)/address) IP=$(curl -s http://192.168.30.10/ks/mac_ip.txt | grep "$MAC" | awk '{print $2}') echo "network --bootproto=static --ip=$IP --netmask=255.255.255.0 --gateway=192.168.30.1 --nameserver=192.168.30.1 --hostname=node-${IP##*.}" > /tmp/network.ks %end %include /tmp/network.ks

这样每台机器在开始分区前就已经确定了IP和主机名,后续安装完可以直接投入使用。如果一台机器临时换了网卡,MAC对不上,脚本会生成空文件,安装就会失败或退回交互界面,这反而会提醒我们“这台机器的资产信息要更新了”。

5. 完整安装流与故障排查手册

5.1 端到端启动流程演示

把前面所有配置串起来,完整的装机流程如下:

  1. 在PXE服务器上启动nginx、tftp、dhcp服务。
  2. 确保系统镜像目录可访问,在测试机浏览器或curl验证http://192.168.30.10/ISO/CentOS7/repodata/repomd.xml返回正常。
  3. 测试机开机,进入BIOS/UEFI启动菜单,选择网络启动(通常名字里有PXE或Network Boot字样)。
  4. 网卡从DHCP拿IP,再通过TFTP下载引导文件。
  5. 屏幕上出现PXE菜单,默认配置指向Linux安装项。
  6. 内核和initrd加载,Anaconda启动。
  7. 安装程序读取ks.cfg,自动分区、安装软件包、设置root密码。
  8. 安装完成后机器自动重启,此时要提前设置下一次启动从硬盘启动,避免再次进入PXE循环。

这里特别强调第八步:PXE装完重启后再进PXE的话,系统会重复安装。解决办法有三个:一是控制启动顺序,让硬盘启动优先于网络启动;二是在ks最后加一个reboot命令,并且把dhcp的租约时间设短,让客户端重启时已经拿不到原地址;三是用Cobbler这类系统自动处理。最推荐第一种,因为最可控。

5.2 五个高频问题速查表

这些年排查PXE问题,我总结了一些固定套路。下面这张表可以直接作为排查手册用:

现象常见原因处理方法
客户端提示PXE-E61: Media test failure网卡没有获取到DHCP地址,或网线/交换机端口问题确认DHCP服务运行、交换机端口UP、VLAN没配错
能获取IP但下载pxelinux.0超时TFTP服务没开或防火墙拦截检查tftp进程和防火墙,禁用tftp.socket,直接常驻服务
提示找不到配置文件或文件格式错误pxelinux.0路径不对,或pxelinux.cfg/default缺失核对TFTP根目录结构,并用tftp客户端在本机测试下载文件
引导菜单能显示但加载内核卡住vmlinuz/initrd.img文件缺失或路径错误确认文件在TFTP根目录,且文件名大小写一致
安装开始后报“找不到安装源”HTTP目录无法访问,或inst.repo参数写错用curl验证URL,检查nginx配置,核对镜像挂载路径
UEFI机器无法通过PXE启动BIOS菜单缺少EFI引导文件,或DHCPfilename指向pxelinux.0改用grubx64.efi引导,并为UEFI客户端准备grub.cfg

5.3 从PXE到更完整的批量装机系统

PXE只是批量装机的地基,真正生产级的环境往往需要在此基础上增加更多能力,比如资产登记、版本管理、装机任务编排、事后审计等。我见过不少团队在PXE上面再封装一层Web界面,让操作人员不用直接编辑DHCP和TFTP配置文件,而是通过界面提交装机任务,后端自动生成对应菜单项并记录MAC/IP的对应关系。

这个方向有两个收益:一是减少误操作,因为所有配置都从模板生成,不会再出现手误删掉一个参数导致整批失败的情况;二是装机状态可视化,每台机器处于“待装中、安装中、已完成、失败”的哪个状态,有没有进入安装界面,都能通过日志和API汇总。

如果你只是个人维护几十台机器,写几个shell脚本也能做到类似效果。核心把下面几个动作自动化起来就不会差:

  • 根据MAC地址自动生成IP和主机名。
  • 根据主机名自动选择对应软件包配置。
  • 每一次装机都打印完整日志,方便回看失败原因。

PXE不会替代所有装机方式,但它是批量运维体系里不可回避的基础能力。我自己的体会是,第一次完整跑通PXE链路后,再去接触更复杂的自动化运维系统,很多概念都会豁然开朗。因为那些系统再怎么封装,底层仍然是DHCP、TFTP、HTTP、引导文件和kickstart这些组件在协同工作。

如果看完这篇文章想动手验证,建议先用虚拟机做一套最小环境,把服务端和客户端放在同一个虚拟网络里,用snapshot随时回滚,试错成本几乎为零。等你在虚拟环境把流程走顺了,再找一台空闲物理机做真机验证,最后再考虑推广到批量场景。这个小项目最大的价值不是炫技,而是让你真正理解“网络引导装系统”这条链路的每一环,遇到问题时脑子里能直接浮现出对应的服务日志。

需要专业的网站建设服务?

联系我们获取免费的网站建设咨询和方案报价,让我们帮助您实现业务目标

立即咨询