ARTICLE · INTELLIGENCE

战地情报 · 详情页

来自尧图项目组的一线实战观察与深度解析

内网PXE批量装机实战:DHCP、TFTP与syslinux配置详解

内网PXE批量装机实战:DHCP、TFTP与syslinux配置详解

1. 为什么要在内网搭一套 PXE 装机环境

很多刚接触服务器运维的朋友会问:现在都什么年代了,还用得着自己搭 DHCP、TFTP 这套东西吗?云厂商一键开机器、镜像市场点两下不就完事了?这话对,也不对。在公有云上确实轮不到我们操心底层引导,可一旦进了企业内网、实验室机房、或者需要批量交付几十上百台物理机的场景,PXE 网络引导依然是绕不开的基本功。它解决的核心问题就一个:让一台裸机在没有任何本地存储介质的情况下,通过网络拿到引导程序、内核和安装源,自动完成系统部署。

这套东西的价值在于"批量"和"无人值守"。你想象一下,机房里堆着三十台刚拆箱的服务器,一台台插 U 盘装系统,光是插拔和等待就能耗掉一整天。而搭好 PXE 之后,你只需要改一下 BIOS 的启动顺序,剩下的交给网络,喝杯咖啡回来机器就装好了。CentOS 8 虽然已经进入维护周期的尾声,但大量存量内网环境仍在跑它,而且 CentOS 8 在引导链路上和 7 有细微差别,尤其是syslinux版本和grub的配合方式,踩坑的人不少。

这篇文章面向的是有一定 Linux 基础、需要在内网做批量部署的运维人员,也适合想搞明白"网络引导到底怎么跑起来"的爱好者。我会把 DHCP、TFTP、syslinux 三者的分工讲透,把每一步配置背后的原因说清楚,再把我自己在实操中遇到的坑和盘托出。你照着做,大概率能一次跑通;就算跑不通,排查思路我也给你铺好了。

需要提前说明的是,本文所有操作都在一个隔离的内网实验环境中进行,涉及的网段、主机名均为虚构示例,你实际部署时替换成自己的规划即可。整个方案不依赖任何外部网络,纯内网闭环,这也是它适合企业环境的根本原因。

2. 三件套的分工:DHCP 给地址、TFTP 递文件、syslinux 管引导

在动手敲命令之前,必须先把这三个组件的职责边界搞清楚。很多人配了半天不成功,根源就是没弄明白"谁在什么时候干了什么"。我用一个寄快递的类比来解释:DHCP 是那个告诉你"你家门牌号是多少"的物业,TFTP 是那个把包裹送到你家门口的快递员,而 syslinux 则是包裹里那份"怎么组装家具"的说明书。三者缺一不可,顺序也不能乱。

2.1 DHCP 不只是发 IP,它还负责"指路"

大多数人印象里的 DHCP 就是自动分配 IP 地址,但在 PXE 场景下,它承担了一个更关键的职责:告诉客户端"去哪里找引导文件"。这是通过 DHCP 报文里的next-server和filename两个选项实现的。next-server指向 TFTP 服务器的地址,filename则指明要下载的引导文件名,比如pxelinux.0。

这里有个容易被忽略的点:标准的 DHCP 服务(比如dhcpd)默认只处理普通地址分配,要支持 PXE,必须在配置里显式声明next-server和filename,而且这两个选项通常要写在subnet或者host段里。如果你的网络里已经有了一台在跑的 DHCP 服务器,那就得考虑是改造它还是新起一台——同一网段里跑两个 DHCP 会打架,这个后面细说。

2.2 TFTP 的"简陋"恰恰是它的优势

TFTP 全称是简单文件传输协议,基于 UDP 的 69 端口,没有认证、没有目录列表、没有复杂的握手。听起来很"原始",但正因为足够简单,它才能被固化在网卡的 PXE 固件里。你想想,网卡 ROM 里那点存储空间,根本塞不下一个完整的 FTP 或 HTTP 客户端,而 TFTP 客户端实现起来可能就几百字节。

TFTP 服务端我们一般用tftp-server这个包,它的根目录默认在/var/lib/tftpboot。所有需要被客户端下载的文件——引导程序、内核、initrd——都得放在这个目录下,而且权限要放开,否则客户端读不到。这里有个经典坑:SELinux 会拦截 TFTP 读取非标准目录的文件,很多人文件明明放对了位置却下载失败,就是被 SELinux 挡了。

2.3 syslinux 是引导链的"总调度"

syslinux 其实是一整个引导器家族,针对不同介质有不同的变体:syslinux用于 FAT 文件系统,isolinux用于光盘,pxelinux用于网络引导。我们在 PXE 场景下用的就是pxelinux.0这个文件。它的作用是:被网卡下载并执行后,去读取一个配置文件(通常是pxelinux.cfg/default),根据配置决定加载哪个内核、传什么参数、显示什么菜单。

CentOS 8 里 syslinux 的版本和 7 有所不同,配置文件语法基本兼容,但一些路径和模块名有变化。比如ldlinux.c32这个模块,在较新版本里是必须的,缺了它pxelinux.0会报错找不到。这就是为什么很多人从 CentOS 7 迁移到 8 时,明明照搬了旧配置却起不来——模块依赖变了。

组件核心职责关键配置项常见坑点
DHCP分配 IP + 指明引导服务器和文件名next-server、filename与现有 DHCP 冲突、选项写错位置
TFTP传输引导文件、内核、initrd根目录、文件权限SELinux 拦截、防火墙挡 UDP 69
syslinux解析配置、加载内核、显示菜单pxelinux.0、pxelinux.cfg/default缺ldlinux.c32、配置路径错误

把这三者的关系理顺了,后面的配置就是按图索骥。我建议你在动手前,先在纸上画出数据流向:客户端广播 DHCP 请求 → DHCP 回应并告知 TFTP 地址和引导文件名 → 客户端向 TFTP 请求pxelinux.0→ 执行后请求配置文件 → 根据配置请求内核和 initrd → 启动安装程序。这条链路任何一环断了,现象都不一样,记住它,排查时能省一半时间。

3. 动手前的环境盘点与依赖安装

配置这种事,最怕的就是环境没摸清就上手。我见过太多人上来就yum install,结果发现网卡没配好、防火墙没关、SELinux 在捣乱,最后怀疑人生。所以这一章我们先做"体检",把地基打牢。

3.1 网络规划:把地址段和角色先定死

在隔离实验环境里,我习惯用192.168.100.0/24这个网段,网关和 DHCP 服务器都放在192.168.100.1上,TFTP 服务也跑在同一台机器。客户端则从192.168.100.100往后分配。为什么把服务端和网关放一起?因为这样next-server直接写本机地址就行,逻辑最简单,也最不容易出错。

你需要确认几件事:服务端网卡的静态 IP 配好了没有、这个网段里有没有别的 DHCP 在跑、客户端和服务端是不是在同一个二层网络里。最后这点特别重要——DHCP 广播默认不跨网段,如果你的客户端在另一个 VLAN,就得配 DHCP 中继,那是另一个话题了,本文不展开。

提示:如果你的内网里已经有一台 DHCP 服务器在给其他机器发地址,千万不要直接再起一台。正确做法是在原有 DHCP 配置里加上next-server和filename选项,让它兼职做 PXE 引导。两台 DHCP 抢着回应,会导致部分机器拿到错误配置,现象非常诡异。

3.2 安装三个核心软件包

CentOS 8 的软件源里,这三个包都是现成的,一条命令搞定:

dnf install -y dhcp-server tftp-server syslinux

注意包名是dhcp-server而不是dhcp,这是 CentOS 8 和 7 的一个差异点,7 里叫dhcp。tftp-server提供 TFTP 服务端,syslinux则提供了pxelinux.0和一堆.c32模块文件。装完之后,pxelinux.0通常在/usr/share/syslinux/目录下,你可以先ls一下确认。

装完别急着启动服务,先把防火墙和 SELinux 这两个"门神"处理好。实验环境里我一般直接关掉它们省事,但生产环境要按最小权限原则放行。TFTP 用的是 UDP 69,DHCP 用的是 UDP 67 和 68,这几个端口必须通。

# 实验环境图省事,直接停用 systemctl stop firewalld systemctl disable firewalld setenforce 0

如果你坚持要开 SELinux,那得给 TFTP 目录打上正确的上下文标签,还要放行相关端口,配置量不小。我个人的经验是:内网隔离环境里,先把功能跑通,再逐步收紧安全策略,比一上来就追求"完美安全"导致寸步难行要高效得多。

3.3 准备安装源文件

PXE 引导只是把机器"叫醒",真正装系统还得有安装源。最简单的方式是把 CentOS 8 的 ISO 镜像挂载到本地,或者解压到某个目录,然后通过 HTTP 或 NFS 共享出去。我这里用 HTTP 方式,因为配置最简单,客户端兼容性也最好。

mkdir -p /var/www/html/centos8 mount -o loop /path/to/CentOS-8.iso /mnt cp -r /mnt/* /var/www/html/centos8/

把 ISO 里的内容全部拷到 web 目录下,这样客户端在安装阶段就能通过http://192.168.100.1/centos8访问到安装源。这一步很多人偷懒用mount --bind,但重启后就失效了,还是老老实实拷贝一份稳妥。拷贝完记得启动 HTTP 服务,dnf install -y httpd && systemctl enable --now httpd。

4. 逐个击破:DHCP、TFTP、syslinux 的配置实操

环境备齐了,现在进入正题。我会按数据流的顺序来配:先 DHCP,再 TFTP,最后 syslinux。每配完一个,我都会告诉你怎么单独验证它是否正常工作,这样出问题时能快速定位是哪一环的锅。

4.1 DHCP 配置:把 next-server 和 filename 写对位置

DHCP 的主配置文件在/etc/dhcp/dhcpd.conf,默认是个空壳,需要我们自己写。下面是我常用的一个最小可用配置:

# /etc/dhcp/dhcpd.conf option domain-name "lab.local"; option domain-name-servers 192.168.100.1; default-lease-time 600; max-lease-time 7200; authoritative; subnet 192.168.100.0 netmask 255.255.255.0 { range 192.168.100.100 192.168.100.200; option routers 192.168.100.1; next-server 192.168.100.1; filename "pxelinux.0"; }

这里的关键就是next-server和filename这两行。next-server告诉客户端 TFTP 服务器在哪,filename告诉它第一个要下载的文件叫啥。注意filename写的是相对路径,相对于 TFTP 的根目录。有些人写成绝对路径/var/lib/tftpboot/pxelinux.0,那是错的,客户端会找不到。

配完先别启动,用dhcpd -t -cf /etc/dhcp/dhcpd.conf检查语法。这个命令能提前发现拼写错误和格式问题,比启动失败后再翻日志高效得多。语法通过后,systemctl enable --now dhcpd启动服务。

验证 DHCP 是否正常,最直接的办法是拿另一台机器(或者虚拟机)设成 DHCP 获取,看能不能拿到192.168.100.x的地址。如果拿不到,先看服务端日志journalctl -u dhcpd -f,常见原因是网段写错、authoritative没加、或者防火墙挡了 UDP 67。

4.2 TFTP 配置:目录、权限、SELinux 三件事

TFTP 的配置相对简单,但坑一点不少。服务由tftp.socket这个 systemd 单元管理,配置文件在/etc/systemd/system/tftp.service.d/或者直接改/usr/lib/systemd/system/tftp.service。不过大多数情况下,默认配置就够用,根目录就是/var/lib/tftpboot。

systemctl enable --now tftp.socket

启动后,把 syslinux 的引导文件拷进去:

cp /usr/share/syslinux/pxelinux.0 /var/lib/tftpboot/ cp /usr/share/syslinux/ldlinux.c32 /var/lib/tftpboot/ cp /usr/share/syslinux/menu.c32 /var/lib/tftpboot/ cp /usr/share/syslinux/libutil.c32 /var/lib/tftpboot/

ldlinux.c32是必须的,前面提过,缺了它pxelinux.0直接罢工。menu.c32和libutil.c32是为了做图形化启动菜单,如果你不需要菜单可以不加,但加上体验更好。

验证 TFTP 是否工作,可以在服务端本机装个客户端测试:

dnf install -y tftp tftp 192.168.100.1 tftp> get pxelinux.0 tftp> quit

如果能下载成功,说明 TFTP 服务本身没问题。如果报 "Transfer timed out",八成是防火墙或 SELinux。实验环境关了防火墙和 SELinux 的话,基本不会遇到。生产环境记得放行 UDP 69 并给目录打标签。

注意:TFTP 根目录下的文件权限要保证tftp用户可读。默认pxelinux.0的权限是 644,没问题。但如果你自己放内核文件进去,别设成 600,否则客户端下载会失败,而且日志里不一定有明显报错,很容易卡在这里。

4.3 syslinux 引导菜单:pxelinux.cfg 目录的命名玄机

这是整个配置里最有意思的部分。pxelinux.0执行后,会按一套特定的规则去寻找配置文件,这个规则叫"配置文件搜索顺序"。它会依次尝试以下名字(在pxelinux.cfg目录下):

  1. 用客户端 MAC 地址命名的文件,格式是01-加上 MAC 地址,横杠分隔,比如01-52-54-00-12-34-56
  2. 用客户端 IP 的十六进制表示命名的文件,逐位缩短
  3. 最后兜底的是default文件

这套机制的设计意图是让你能给不同机器下发不同配置——比如给某台特定机器装特定版本。但绝大多数场景下,我们只需要一个default文件就够了。

mkdir -p /var/lib/tftpboot/pxelinux.cfg

然后创建default文件:

# /var/lib/tftpboot/pxelinux.cfg/default default menu.c32 prompt 0 timeout 300 label centos8 menu label ^Install CentOS 8 kernel vmlinuz append initrd=initrd.img inst.repo=http://192.168.100.1/centos8 inst.ks=http://192.168.100.1/ks.cfg

这里kernel和initrd指向的文件,需要你从 ISO 的images/pxeboot/目录里拷到 TFTP 根目录:

cp /var/www/html/centos8/images/pxeboot/vmlinuz /var/lib/tftpboot/ cp /var/www/html/centos8/images/pxeboot/initrd.img /var/lib/tftpboot/

append那行是精髓。inst.repo指定安装源地址,inst.ks指定 Kickstart 自动应答文件。如果你只想手动安装,把inst.ks去掉即可。Kickstart 文件放在 HTTP 目录下,客户端安装时会自动拉取,实现全自动无人值守。

配置文件的语法有个细节:label后面的名字是内部标识,menu label才是显示给用户看的。^符号表示快捷键,按I就能选中这一项。这些小细节能让你的启动菜单更专业。

5. 联调验证:从裸机到安装界面的完整链路

配置都写完了,现在是见证奇迹的时刻。但别急着开香槟,联调阶段才是真正暴露问题的地方。我会带你走一遍完整的验证流程,并告诉你每个环节该看什么现象。

5.1 客户端侧的现象解读

把一台裸机(或虚拟机)设成网络引导,开机后你应该看到这样的过程:网卡先是尝试 DHCP,屏幕上出现类似DHCP...或者PXE-E51之类的提示。如果拿到地址,会显示PXE-E53之后开始下载pxelinux.0。下载成功后,syslinux 启动,显示你配置的菜单。

这里有几个典型现象对应不同问题:

  • 卡在DHCP...不动:DHCP 没响应,检查服务端是否启动、网段是否匹配、防火墙是否放行
  • 报PXE-E32: TFTP open timeout:TFTP 连不上,检查next-server地址、TFTP 服务状态、UDP 69 端口
  • 报PXE-E35: TFTP read timeout:能连上但读不到文件,检查文件名拼写、文件是否存在、权限是否正确
  • 下载完pxelinux.0后黑屏或报No configuration file found:pxelinux.cfg/default路径或名字不对
  • 菜单出来了但选完报错:kernel或initrd文件缺失,或者append参数里的安装源地址不通

我建议你第一次联调时,把虚拟机内存设大一点(2G 以上),因为 CentOS 8 的安装程序对内存有一定要求,内存太小会在加载 initrd 阶段失败,现象是卡在Loading initrd.img不动,很容易误判成网络问题。

5.2 用 tcpdump 抓包定位问题

当现象不明确时,抓包是最可靠的手段。在服务端跑:

tcpdump -i any -n port 67 or port 68 or port 69

这条命令能同时看到 DHCP 和 TFTP 的交互。如果客户端发了 DHCP 请求但服务端没回,说明请求没到或者服务端没处理;如果服务端回了但客户端没继续请求 TFTP,说明next-server或filename没被客户端接受。抓包看到的东西比日志直观得多,尤其是排查"到底哪一步断了"的时候。

5.3 Kickstart 自动安装的收尾

如果你配了inst.ks,客户端会自动完成分区、装包、设密码等操作,全程无需干预。Kickstart 文件的内容这里不展开,但有个经验值得分享:ks.cfg里的url或repo地址必须和inst.repo一致,否则会报找不到安装源。另外,ks.cfg的权限要保证 HTTP 服务能读到,放在/var/www/html/下一般没问题。

自动安装完成后,机器会自动重启。记得在 BIOS 里把启动顺序改回硬盘优先,否则重启后又会进入 PXE 循环,白白浪费时间。这个坑我踩过不止一次,尤其是批量部署时,几十台机器同时循环引导,场面相当壮观。

6. 那些让我熬夜的坑:SELinux、防火墙与版本差异

前面讲的都是"顺利路径",但真实世界里,顺利是偶然,踩坑是常态。这一章我把几个最折磨人的坑单独拎出来,讲清楚它们的成因和排查方法。这些经验,是文档里不会写的。

6.1 SELinux 拦截 TFTP 的隐蔽性

SELinux 最坑的地方在于,它拦截时不一定给你明显的报错。客户端那边可能只是"下载超时",服务端日志里也可能只有一句含糊的拒绝。排查方法是看审计日志:

ausearch -m avc -ts recent

如果看到和tftp相关的denied记录,那就是 SELinux 在作祟。临时解决是setenforce 0,永久解决是给 TFTP 目录打上tftpdir_rw_t标签,或者用semanage放行。我个人的建议是:内网实验环境直接关掉 SELinux,把精力放在功能验证上;生产环境再花时间做精细化的策略配置。

6.2 防火墙的 UDP 陷阱

防火墙对 TCP 的处理大家都很熟悉,但 UDP 有个特点:它是无连接的,没有握手过程。这意味着如果 UDP 69 被挡,客户端不会收到"拒绝"信号,只会一直等,直到超时。现象就是"卡住",而不是"报错"。这种沉默的失败最让人抓狂。

排查时先用firewall-cmd --list-all看规则,确认tftp服务有没有被放行。CentOS 8 的 firewalld 内置了tftp服务定义,直接firewall-cmd --add-service=tftp --permanent就行。DHCP 同理,--add-service=dhcp。加完记得--reload。

6.3 CentOS 7 到 8 的引导文件差异

如果你是从 CentOS 7 环境迁移过来的,有几个差异必须注意。首先是包名,dhcp变成了dhcp-server。其次是 syslinux 的模块文件,CentOS 8 里ldlinux.c32是强依赖,7 里某些版本可能不需要。再就是pxelinux.0的默认路径,虽然都在/usr/share/syslinux/,但个别小版本会有出入,装完最好rpm -ql syslinux | grep pxelinux确认一下。

还有一个隐蔽的差异:CentOS 8 的安装程序对inst.repo的格式要求更严格,必须写完整的 URL,不能像 7 那样简写。这些差异单看都不大,但叠加在一起,就够你排查半天的。

坑点现象根因解决
SELinux 拦截TFTP 下载超时,日志含糊目录上下文标签不对关 SELinux 或打标签
防火墙挡 UDP客户端卡住无报错UDP 无连接,静默丢弃放行 tftp/dhcp 服务
缺 ldlinux.c32pxelinux.0 执行报错CentOS 8 强依赖该模块拷贝该文件到 TFTP 根目录
双 DHCP 冲突部分机器拿到错误配置同网段两个 DHCP 抢答合并到一台或做中继

7. 从能用到好用:几个提升效率的实践心得

功能跑通只是起点,真正让这套环境"好用",还得靠一些细节打磨。这些是我在多次部署中攒下来的经验,分享给你。

7.1 用 MAC 绑定给特定机器定制配置

前面提到pxelinux.cfg支持按 MAC 地址命名配置文件。这个特性在混合部署场景下特别有用。比如你有十台机器要装 CentOS 8,两台要装别的系统,就可以给那两台单独建一个以 MAC 命名的配置文件,其余走default。MAC 地址的写法要注意:全小写,用横杠分隔,前面加01-。比如 MAC 是52:54:00:12:34:56,文件名就是01-52-54-00-12-34-56。写错了不会报错,只会默默走default,所以配完一定要核对。

7.2 把常用内核参数固化进菜单

append那行可以塞很多有用的参数。比如console=ttyS0,115200可以把输出重定向到串口,方便在没有显示器的机架上调试;inst.text强制文本安装模式,省资源;ip=dhcp显式指定网络配置方式。把这些参数按场景做成不同的菜单项,用的时候直接选,比每次手敲高效得多。

7.3 日志是你的朋友,但要会看

DHCP 的日志在journalctl -u dhcpd,TFTP 的日志相对少,主要靠抓包。syslinux 阶段的报错则直接显示在客户端屏幕上。排查时养成"先看现象、再抓包、最后翻日志"的习惯,比盲目重启服务有效得多。我见过太多人一遇到问题就systemctl restart,结果把现场破坏了,反而更难定位。

7.4 备份你的配置

这套环境一旦配好,配置文件就那么几个:dhcpd.conf、pxelinux.cfg/default、ks.cfg。把它们纳入版本管理或者定期备份,下次迁移或重建时能省大量时间。尤其是ks.cfg,里面往往包含分区方案和软件包列表,是真正的"知识沉淀"。

最后分享一个我自己的习惯:每次部署完,我都会在一台虚拟机上完整走一遍流程,确认无误后再上物理机。虚拟机快照能让你大胆试错,而物理机的一次失败可能意味着半小时的等待。这个习惯帮我避开了无数次"配置看起来对但就是跑不通"的尴尬。整套 DHCP、TFTP、syslinux 的组合,说到底就是把"引导"这件事拆成三步走稳,每一步都验证到位,剩下的就是水到渠成。

RELATED READING

延伸阅读

更多一线实战笔记与深度复盘,助您持续精进