1. 项目概述:PXE批量安装系统
在服务器机房或者运维中心,最头疼的场景之一就是面对几十上百台裸机需要安装操作系统。一台台插U盘、挂光驱?效率低到令人发指,而且容易出错。PXE(Preboot eXecution Environment)技术就是为了解决这个痛点而生的。简单来说,它允许计算机通过网络从远端服务器下载镜像,并启动安装程序,整个过程无需本地存储介质。对于需要大规模部署Linux或Windows服务器的企业、教育机构、云计算服务商而言,掌握PXE批量安装是运维自动化的基本功。
这个项目的核心,就是搭建一套完整的PXE服务环境,实现客户机开机后自动从网络获取引导文件、内核、镜像,并完成无人值守的自动化安装。它不仅仅是运行几个命令,更涉及到DHCP、TFTP、HTTP/NFS等多种服务的协同,以及自动化应答文件的精细配置。下面,我将结合自己多次从零搭建和排错的经验,拆解整个流程,让你不仅能照着做出来,更能理解每一步背后的原理,遇到问题知道从何下手。
2. 核心组件与工作原理拆解
在动手之前,必须搞清楚PXE启动的“接力赛”是怎么跑的。这能让你在配置时思路清晰,排错时有的放矢。
2.1 PXE启动流程详解
当你给一台支持PXE的客户机通电,并设置从网络启动后,会发生以下一连串事件:
- DHCP Discover:客户机的网卡PXE芯片广播一个DHCP请求。这个请求比较特殊,它里面包含了客户机自己是PXE客户端的信息。
- DHCP Offer (带PXE扩展):网络中的DHCP服务器收到请求后,不仅分配一个IP地址给客户机,还会在回复报文中附加两个关键选项:
- Next-Server:告诉客户机,TFTP服务器的IP地址是什么。
- Bootfile-Name:告诉客户机,要从TFTP服务器下载的第一个引导文件的名字(通常是
pxelinux.0或grubx64.efi)。
- TFTP获取引导文件:客户机根据DHCP提供的信息,向指定的TFTP服务器请求并下载
Bootfile-Name指定的文件。这个文件是一个网络引导程序。 - 引导程序执行与配置加载:引导程序(如PXELINUX或GRUB2)被加载到客户机内存并执行。它接着会通过TFTP协议,从服务器下载自己的配置文件(如
pxelinux.cfg/default)以及可能需要的模块(如ldlinux.c32)。 - 内核与初始文件系统下载:根据配置文件中的指令,引导程序继续通过TFTP(或更高效的HTTP、NFS)下载操作系统的内核(
vmlinuz)和初始内存盘(initrd.img)。 - 启动安装程序:内核被加载,并利用
initrd中的工具初始化环境,最后启动真正的系统安装程序(如Anaconda)。 - 获取安装源与应答文件:安装程序会按照预设,通过HTTP、FTP或NFS协议从服务器获取完整的系统安装包(Repository),并读取自动化安装的应答文件(如Kickstart的
.cfg文件)。 - 无人值守安装:根据应答文件的配置,自动完成磁盘分区、软件包选择、用户设置等所有步骤,直至安装结束重启。
整个流程环环相扣,任何一个环节的配置错误都可能导致启动失败。其中,DHCP负责指路,TFTP负责传递最初的“火种”(引导文件),而HTTP/NFS则负责搬运“建筑材料”(系统镜像)。
2.2 服务角色与选型考量
基于上述流程,我们需要部署以下服务:
- DHCP 服务:为PXE客户机分配IP并指明引导路径。可以选择
isc-dhcp-server(Linux)或Windows Server DHCP角色。在简单实验环境,甚至可以用路由器自带的DHCP,但需要其支持设置Option 66(Next-Server) 和Option 67(Bootfile-Name)。生产环境建议使用独立、可控的DHCP服务器。 - TFTP 服务:用于传输小体积的引导文件。协议简单,无需认证。常用
tftp-hpa。注意:TFTP默认使用UDP 69端口,防火墙需放行。 - 文件共享服务:用于存放体积庞大的系统镜像和安装包。TFTP效率太低,不适合传大文件。通常选择:
- HTTP:最通用,兼容性最好。可以用Apache、Nginx。推荐Nginx,轻量高效。
- NFS:在Linux对Linux的场景下性能很好,但Windows客户机支持需要额外配置。
- FTP:较老的方式,现在用得少了。
- 引导程序:
- PXELINUX (Syslinux项目):传统BIOS启动的经典选择,配置简单直观。
- GRUB2:支持BIOS和UEFI,功能更强大,是目前的趋势,特别是UEFI启动必须用它。
- 自动化应答文件:
- Kickstart:Red Hat系(RHEL, CentOS, Fedora)的无人值守安装配置文件。
- Preseed:Debian/Ubuntu系的无人值守安装配置文件。
- Autounattend.xml:Windows系统的无人值守应答文件。
实操心得:对于新手,我建议从CentOS/RHEL 系统 + HTTP(Nginx) + PXELINUX/GRUB2 + Kickstart这个组合开始。资料最多,社区最活跃,踩坑了也容易找到解决方案。等这套流程跑通了,再迁移到其他发行版或Windows,会轻松很多。
3. 服务端环境搭建与配置实战
我们以一台CentOS 7/8 Stream作为PXE服务器为例,IP为192.168.1.10。目标是部署一个可以批量安装CentOS 7和CentOS 8的PXE环境。
3.1 基础环境准备
首先,确保服务器有固定的IP地址,关闭SELinux和防火墙(或配置正确的放行规则),并更新系统。
# 设置静态IP (根据你的网络环境修改) # 编辑 /etc/sysconfig/network-scripts/ifcfg-ens33 (网卡名可能不同) BOOTPROTO=static ONBOOT=yes IPADDR=192.168.1.10 NETMASK=255.255.255.0 GATEWAY=192.168.1.1 DNS1=8.8.8.8 # 关闭并禁用防火墙(实验环境,生产环境需配置规则) systemctl stop firewalld systemctl disable firewalld # 临时关闭SELinux,或设置为permissive模式 setenforce 0 # 永久关闭需修改 /etc/selinux/config,将 SELINUX=enforcing 改为 SELINUX=disabled # 更新系统 yum update -y3.2 安装并配置DHCP服务
安装ISC DHCP服务器:
yum install dhcp -y编辑DHCP主配置文件/etc/dhcp/dhcpd.conf。一个最简化的、针对PXE的配置示例如下:
# /etc/dhcp/dhcpd.conf authoritative; # 声明此服务器为权威DHCP服务器 subnet 192.168.1.0 netmask 255.255.255.0 { range 192.168.1.100 192.168.1.200; # 分配的IP地址池 option routers 192.168.1.1; # 客户机的默认网关 option subnet-mask 255.255.255.0; option domain-name-servers 8.8.8.8; # DNS服务器 next-server 192.168.1.10; # 关键!指向TFTP服务器的IP filename "grubx64.efi"; # 关键!为UEFI客户机指定的引导文件 # 如果还需要支持传统BIOS,可以添加一个class和if判断,但更常见的做法是统一用GRUB2处理 }注意:
next-server和filename是PXE的核心。filename的值取决于你准备的引导文件。这里我们先以UEFI模式的grubx64.efi为例。传统BIOS模式下,文件名可能是pxelinux.0。
启动并设置开机自启:
systemctl start dhcpd systemctl enable dhcpd检查服务状态和端口监听:
systemctl status dhcpd netstat -ulnp | grep :67 # DHCP服务监听UDP 67端口3.3 安装并配置TFTP服务
安装TFTP服务器和客户端(用于测试):
yum install tftp-server tftp -yTFTP服务由xinetd超级守护进程管理。编辑其配置文件/etc/xinetd.d/tftp:
service tftp { socket_type = dgram protocol = udp wait = yes user = root server = /usr/sbin/in.tftpd server_args = -s /var/lib/tftpboot -v # -s 指定根目录,-v 启用详细日志(排错用) disable = no # 关键!将yes改为no,启用服务 per_source = 11 cps = 100 2 flags = IPv4 }这里指定了TFTP的根目录为/var/lib/tftpboot,所有引导文件都将放在这里。
启动xinetd服务:
systemctl start xinetd systemctl enable xinetd验证TFTP服务是否正常:
# 在服务器本机测试 echo "test" > /var/lib/tftpboot/test.txt tftp localhost -c get test.txt cat test.txt # 应该能看到“test”3.4 准备引导程序(GRUB2)与启动菜单
我们使用GRUB2来同时支持BIOS和UEFI。首先安装GRUB2相关包和syslinux(提供pxelinux.0等文件,GRUB2的grub2-pc模块会用到):
yum install grub2-efi-x64-modules grub2-pc grub2-pc-modules grub2-tools syslinux -y创建TFTP根目录结构,并复制必要的引导文件:
mkdir -p /var/lib/tftpboot/{grub,centos7,centos8} # 复制BIOS PXE引导文件 (由syslinux提供) cp /usr/share/syslinux/pxelinux.0 /var/lib/tftpboot/ cp /usr/share/syslinux/menu.c32 /var/lib/tftpboot/ # 提供菜单支持 cp /usr/share/syslinux/ldlinux.c32 /var/lib/tftpboot/ # 提供库支持 cp /usr/share/syslinux/libutil.c32 /var/lib/tftpboot/ # 复制UEFI PXE引导文件 (由grub2-efi提供) cp /boot/efi/EFI/centos/grubx64.efi /var/lib/tftpboot/grub/ # 注意路径可能因系统而异 # 或者使用: cp /usr/lib/grub/x86_64-efi/monolithic/grubx64.efi /var/lib/tftpboot/grub/接下来,创建GRUB2的配置文件。对于PXE,GRUB2会从TFTP根目录下的grub/grub.cfg读取配置。
编辑/var/lib/tftpboot/grub/grub.cfg:
set timeout=10 set default=0 menuentry 'Install CentOS 7 - Minimal' { set root=(tftp,192.168.1.10) linux /centos7/vmlinuz inst.repo=http://192.168.1.10/centos7 inst.ks=http://192.168.1.10/ks/centos7-ks.cfg ip=dhcp initrd /centos7/initrd.img } menuentry 'Install CentOS 8 Stream - Minimal' { set root=(tftp,192.168.1.10) linux /centos8/vmlinuz inst.repo=http://192.168.1.10/centos8 inst.ks=http://192.168.1.10/ks/centos8-ks.cfg ip=dhcp initrd /centos8/initrd.img } menuentry 'Boot from local disk' { exit }关键参数解释:
set root=(tftp,server_ip):指定根设备为TFTP,并给出服务器IP。linux /path/to/vmlinuz ...:指定内核路径和内核参数。inst.repo=:指定安装源(系统镜像)的URL,这里我们准备用HTTP服务提供。inst.ks=:指定Kickstart应答文件的URL,实现无人值守。ip=dhcp:告诉安装程序使用DHCP获取IP。
initrd /path/to/initrd.img:指定初始内存盘路径。
为了让传统BIOS也能通过pxelinux.0引导到GRUB2或直接引导,我们还需要配置pxelinux.cfg。创建目录和默认配置文件:
mkdir -p /var/lib/tftpboot/pxelinux.cfg cat > /var/lib/tftpboot/pxelinux.cfg/default << EOF default menu.c32 prompt 0 timeout 100 LABEL local MENU LABEL Boot from local drive LOCALBOOT 0 LABEL centos7-grub MENU LABEL Install CentOS 7 via GRUB2 KERNEL grub/grubx64.efi # 对于BIOS,可能需要 chain.c32 + grub2的core.0 等,这里简化,直接链式加载UEFI grub(如果BIOS支持) # 更标准的做法是为BIOS准备单独的grub2引导,这里不展开。 EOF实操心得:在实际生产环境中,BIOS和UEFI并存是常态。一个干净的策略是:让
pxelinux.0(BIOS) 和grubx64.efi(UEFI) 都去加载同一个grub.cfg配置文件。这需要为BIOS编译一个grub2-pc格式的core.0镜像,并配置pxelinux.cfg/default去加载它。为了简化,上述示例做了取舍。如果你的环境全是UEFI,可以只配置GRUB2;如果全是传统BIOS,可以只配置PXELINUX。
3.5 配置HTTP服务并放置系统镜像
我们使用Nginx提供HTTP服务。安装Nginx:
yum install nginx -y systemctl start nginx systemctl enable nginx挂载或下载系统ISO镜像。假设你已经下载了CentOS-7-x86_64-Minimal-2009.iso和CentOS-Stream-8-x86_64-latest-boot.iso(网络安装镜像更小)。
# 创建挂载点和镜像存放目录 mkdir -p /mnt/{cdrom7,cdrom8} mkdir -p /usr/share/nginx/html/{centos7,centos8} # 挂载CentOS 7镜像 mount -o loop /path/to/CentOS-7-x86_64-Minimal-2009.iso /mnt/cdrom7 # 复制全部文件到Nginx目录(或者只复制Packages和repodata,但复制全部最省事) cp -r /mnt/cdrom7/* /usr/share/nginx/html/centos7/ # 挂载CentOS 8 Stream镜像 mount -o loop /path/to/CentOS-Stream-8-x86_64-latest-boot.iso /mnt/cdrom8 cp -r /mnt/cdrom8/* /usr/share/nginx/html/centos8/ # 复制内核和initrd到TFTP目录,供引导程序加载 cp /usr/share/nginx/html/centos7/images/pxeboot/vmlinuz /var/lib/tftpboot/centos7/ cp /usr/share/nginx/html/centos7/images/pxeboot/initrd.img /var/lib/tftpboot/centos7/ cp /usr/share/nginx/html/centos8/images/pxeboot/vmlinuz /var/lib/tftpboot/centos8/ cp /usr/share/nginx/html/centos8/images/pxeboot/initrd.img /var/lib/tftpboot/centos8/现在,你的HTTP文件结构应该是:
/usr/share/nginx/html/ ├── centos7/ (包含CentOS 7 ISO全部内容) └── centos8/ (包含CentOS 8 ISO全部内容)确保Nginx有权限读取这些文件,并可以通过http://192.168.1.10/centos7/和http://192.168.1.10/centos8/访问。
3.6 创建Kickstart无人值守应答文件
Kickstart文件定义了安装的所有步骤。我们可以从系统安装后生成的/root/anaconda-ks.cfg作为起点修改,或者手动创建。
在Nginx目录下创建专门存放ks文件的目录:
mkdir -p /usr/share/nginx/html/ks编辑/usr/share/nginx/html/ks/centos7-ks.cfg:
#version=DEVEL # System authorization information auth --enableshadow --passalgo=sha512 # Use network installation url --url="http://192.168.1.10/centos7" # Use graphical install graphical # Run the Setup Agent on first boot firstboot --enable ignoredisk --only-use=sda # Keyboard layouts keyboard --vckeymap=us --xlayouts='us' # System language lang en_US.UTF-8 # Network information network --bootproto=dhcp --device=eth0 --onboot=on --ipv6=auto --no-activate network --hostname=localhost.localdomain # Root password (这里为了演示,密码是明文'password',生产环境务必使用加密密码!) rootpw --plaintext password # System services services --enabled="chronyd" # System timezone timezone Asia/Shanghai --isUtc # System bootloader configuration bootloader --location=mbr --boot-drive=sda autopart --type=lvm # Partition clearing information clearpart --all --initlabel --drives=sda %packages @^minimal @core chrony kexec-tools %end %addon com_redhat_kdump --enable --reserve-mb='auto' %end %post # 安装后脚本,可以在这里执行自定义命令,如注册系统、安装Agent等 echo "PXE Installation Completed on $(date)" >> /root/pxe-install.log %end rebootCentOS 8 Stream的ks文件类似,但软件包组名称可能不同(如@minimal)。你需要根据实际需求调整分区、软件包、网络配置等。
重要警告:示例中使用了明文root密码,这是极不安全的!生产环境中必须使用加密密码。可以使用
python3 -c 'import crypt; print(crypt.crypt("YourPassword", crypt.mksalt(crypt.METHOD_SHA512)))'生成加密密码,然后在ks文件中使用rootpw --iscrypted $6$...。
4. 客户端测试与全流程验证
服务端配置完成后,就可以进行客户端测试了。
- 准备一台测试客户机:在BIOS/UEFI设置中,开启网络引导(PXE Boot),并将其设置为第一启动项。
- 启动客户机:客户机开机后,应该会从DHCP服务器获取到IP,并显示
DHCP...,TFTP...等提示信息。 - 加载引导菜单:如果一切顺利,你会看到我们配置的GRUB2菜单(或PXELINUX菜单),列出“Install CentOS 7”、“Install CentOS 8”等选项。
- 选择安装项:选择“Install CentOS 7 - Minimal”,回车。
- 观察启动过程:客户机会开始通过TFTP加载内核 (
vmlinuz) 和initrd.img,然后通过HTTP获取安装源并读取Kickstart文件。 - 无人值守安装:之后的过程应该是全自动的,无需人工干预,直到安装完成自动重启。
5. 高级配置与优化技巧
基础流程跑通后,可以考虑以下优化,让系统更健壮、更灵活。
5.1 按MAC地址分配固定IP和主机名
在生产环境中,我们可能希望特定的服务器总是获得固定的IP和主机名。这可以在DHCP配置中通过host声明实现。
在/etc/dhcp/dhcpd.conf的subnet块内或外部添加:
host webserver01 { hardware ethernet 08:00:27:11:22:33; # 客户机的MAC地址 fixed-address 192.168.1.50; # 分配的固定IP option host-name "web01.example.com"; # 分配的主机名 next-server 192.168.1.10; filename "grubx64.efi"; }5.2 使用IP或MAC地址定制启动菜单
有时我们需要为不同的机器推送不同的安装配置。PXELINUX和GRUB2都支持根据客户机的IP或MAC地址来加载不同的配置文件。
PXELINUX:它会按特定顺序在
pxelinux.cfg目录下查找配置文件。例如,客户机IP是192.168.1.123,它会依次查找:01-08-00-27-11-22-33(MAC地址,去掉冒号,小写)C0A8017B(IP的16进制,192.168.1.123->C0 A8 01 7B)C0A8017(去掉最后一位)C0A801(再去掉一位)- ... 以此类推,直到
default你可以为特定机器创建对应的文件,实现个性化引导。
GRUB2:在
grub.cfg中可以使用if语句进行条件判断。但更常见的做法是,在grub.cfg中设置一个变量,然后去加载另一个根据该变量命名的配置文件。或者,写一个脚本在GRUB启动时动态生成菜单。
5.3 集成多个操作系统镜像
除了CentOS,你可能还需要安装Ubuntu、Windows等。思路是通用的:
- 将对应系统的ISO镜像内容解压到HTTP目录下(如
/usr/share/nginx/html/ubuntu2004)。 - 将其内核 (
vmlinuz) 和初始内存盘 (initrd) 复制到TFTP目录下。 - 在GRUB2菜单 (
grub.cfg) 或PXELINUX菜单 (pxelinux.cfg/default) 中添加新的启动项,指定正确的内核路径、initrd路径和安装源参数。 - 为该系统准备对应的无人值守应答文件(Ubuntu用Preseed,Windows用Autounattend.xml)。
5.4 使用Cobbler或Foreman进行自动化管理
当需要管理的操作系统版本、硬件类型、配置模板非常多时,手动维护PXE配置会变得非常繁琐。这时可以考虑使用像Cobbler或Foreman这样的自动化部署工具。
- Cobbler:一个轻量级的Linux安装服务器,它封装了PXE、DHCP、TFTP、HTTP、DNS、Kickstart等服务的配置,提供了Web界面和命令行工具来统一管理镜像、配置文件和系统模板。
- Foreman:一个更全面的生命周期管理工具,它内置了Cobbler的功能,并提供了主机配置、监控、报告等更多功能,是大型运维团队的理想选择。
使用这些工具,你可以通过图形界面轻松添加新镜像、定义安装模板、并将主机分组进行批量部署,极大提升了效率。
6. 故障排查与常见问题
PXE部署过程中难免会遇到问题,以下是一些常见故障及排查思路。
6.1 客户端无法获取IP地址(停留在PXE-E51: No DHCP or proxyDHCP offers were received)
- 检查网络物理连接:网线、交换机端口。
- 检查DHCP服务状态:
systemctl status dhcpd,查看日志journalctl -u dhcpd -f。 - 检查防火墙:确保服务器防火墙放行了UDP 67端口。
firewall-cmd --add-service=dhcp --permanent。 - 检查DHCP配置:
dhcpd配置语法检查dhcpd -t。确认subnet声明覆盖了客户机所在的网段。 - 网络中存在其他DHCP服务器:如路由器,可能会产生冲突。确保PXE服务器的DHCP响应更快或更优先。
6.2 客户端获取IP后,TFTP超时或失败(PXE-T01/T02/T03错误)
- 检查TFTP服务状态:
systemctl status xinetd,netstat -ulnp | grep :69。 - 检查防火墙:放行UDP 69端口。
firewall-cmd --add-service=tftp --permanent。 - 检查TFTP根目录权限:确保
/var/lib/tftpboot及其下的文件有读权限(至少o+r)。 - 检查引导文件路径和名称:确认
filename在DHCP配置中指定的文件名,在TFTP根目录下确实存在,且文件名大小写匹配。 - 使用tftp客户端本地测试:在服务器上
tftp localhost -c get grub/grubx64.efi,看能否下载。
6.3 加载引导菜单后,无法下载内核或initrd
- 检查文件路径:在GRUB2或PXELINUX配置中指定的
vmlinuz和initrd.img路径,相对于TFTP根目录是否正确。 - 检查文件是否存在:确认文件已正确复制到TFTP目录。
- 查看TFTP服务器日志:在
/var/log/messages或journalctl -u xinetd中查看TFTP传输日志,看是否有“File not found”错误。
6.4 内核启动后,无法找到安装源(Repository)
- 检查HTTP/NFS服务:确保HTTP服务(Nginx)正常运行,且防火墙放行了80端口。
- 检查安装源URL:确认
inst.repo=或url=指定的URL能通过客户机网络正常访问。可以在客户机启动到救援模式,用curl测试。 - 检查镜像文件完整性:ISO镜像可能损坏,重新下载或验证md5/sha256校验和。
- 检查SELinux:如果SELinux处于Enforcing模式,可能会阻止HTTPD或Nginx访问镜像文件目录。可以暂时设置为Permissive模式排查,或使用
chcon和semanage fcontext命令修正文件上下文。
6.5 Kickstart自动化安装失败
- 检查Kickstart文件语法:使用
ksvalidator工具检查.cfg文件是否有语法错误。yum install pykickstart -y。 - 检查Kickstart文件URL:确保
inst.ks=指定的URL可访问,且文件内容正确。 - 查看安装日志:在安装过程中,按
Ctrl+Alt+F2切换到第二个虚拟控制台,可以查看详细的安装日志,里面通常会有错误信息。安装失败后的/root/ks-post.log和/tmp/anaconda.log也包含重要信息。 - 分区错误:这是最常见的失败原因之一。确保Kickstart中的磁盘设备名(如
sda)与目标机器实际磁盘一致。对于多盘机器,使用ignoredisk --only-use=sda可以避免安装程序误操作其他磁盘。
6.6 客户端重启后无法进入系统,循环进入PXE
- 检查启动顺序:安装完成后,客户机BIOS/UEFI中的启动顺序没有改回从硬盘启动。进入BIOS设置调整。
- DHCP保留:如果DHCP服务器为这台客户机固定分配了IP并指定了
filename,即使安装后,它每次网络启动还是会收到PXE引导指令。可以在DHCP配置中为这台主机移除next-server和filename选项,或者安装完成后关闭客户机的PXE启动功能。
搭建PXE批量安装系统是一个典型的“先苦后甜”的过程。初期配置和排错可能会花费一些时间,但一旦体系搭建完成,后续的系统部署工作将变得无比轻松和高效。从几台到上百台服务器的安装,可能只是喝杯咖啡的功夫。这套体系也是现代数据中心自动化运维、CI/CD流水线中基础设施即代码(IaC)的重要基石。理解其原理,掌握其配置,是运维工程师向自动化、平台化进阶的必经之路。