PXE 网络启动原理:协议栈、交互流程与文件加载顺序
各位好,我是老张。今天咱们开始《网络启动场景参数调优》的第一章。说实话,PXE 这东西我入行头三年都没真正搞明白——直到有一次在数据中心部署 200 台裸机服务器,DHCP 死活给不出正确地址,我才被迫把整个协议栈啃了一遍。嗯,从那以后,我再也不敢轻视这个“看起来简单”的启动流程了。
1.1 PXE 协议栈:谁在跟谁说话?
PXE 全称是 Preboot eXecution Environment,说白了就是让一台还没装系统的机器,通过网络把操作系统内核拉下来。你想想看,一台裸机连硬盘都没有,它怎么上网?靠的就是网卡固件里内置的 PXE 客户端。
整个协议栈分三层:
- 底层:网卡驱动 + UDP/IP 协议栈(固化在网卡 ROM 或 UEFI 中)
- 中间层:DHCP 协议(获取 IP 和启动服务器地址)
- 上层:TFTP 协议(下载启动文件)
我习惯把 PXE 客户端比作一个“网络启动小管家”。它不依赖操作系统,只靠网卡自带的几 KB 代码就能跑起来。这个管家会依次做三件事:要地址、找服务器、拿文件。
关键点:PXE 客户端只支持 UDP 传输。TCP 协议栈太大,塞不进网卡固件。所以 TFTP 成了唯一选择——虽然它慢,但够轻量。
1.2 DHCP 与 TFTP 的交互流程
整个交互过程分四个阶段。我画了一张流程图,你一看就明白:
流程拆开来看,其实就四步:
- DHCP Discover(广播):PXE 客户端发广播,问“谁给我个 IP 和启动服务器地址?”
- DHCP Offer(含扩展字段):DHCP 服务器回应,除了 IP,还带上
next-server(TFTP 服务器 IP)和filename(启动文件名)。 - DHCP Request / Ack:客户端确认租约,服务器确认。
- TFTP 传输:客户端向 TFTP 服务器发起读请求,分块下载启动文件。
我的经验:DHCP 的 Offer 包里有几个关键选项——Option 66(next-server)和 Option 67(bootfile)。有些老旧 DHCP 服务器不支持这些扩展选项,你得手动配。我建议用 dnsmasq 做测试,它原生支持 PXE,省心很多。
1.3 启动文件加载顺序
文件下载下来之后,PXE 客户端怎么知道该执行哪个?这里有个优先级顺序。我整理了一张表:
| 优先级 | 文件来源 | 说明 |
|---|---|---|
| 1(最高) | DHCP Option 67(filename) | 服务器明确指定的启动文件,最优先 |
| 2 | UEFI 默认路径 | 如 efi/boot/bootx64.efi(仅 UEFI 模式) |
| 3 | BIOS 默认路径 | 如 pxelinux.0(传统 BIOS 模式) |
| 4(最低) | 网卡固件内置路径 | 极少用,部分网卡有硬编码路径 |
实际项目中,我几乎只用 Option 67 指定文件名。为什么?因为默认路径太容易出问题。举个例子:
- UEFI 模式下,如果 DHCP 没给 filename,客户端会尝试
efi/boot/bootx64.efi。但你的 TFTP 根目录下可能根本没有这个路径结构。 - BIOS 模式下,默认找
pxelinux.0。但如果你用的是 GRUB2 做启动器,文件名是grubx64.efi,那就对不上。
⚠️ 注意:我曾经在混合环境(部分 UEFI、部分 BIOS)里踩过坑。同一台 DHCP 服务器,给 UEFI 客户端返回 bootx64.efi,给 BIOS 客户端返回 pxelinux.0。怎么区分?靠 DHCP 的 Option 60(Vendor Class Identifier)。UEFI 客户端会发 "PXEClient:Arch:00007",BIOS 发 "PXEClient:Arch:00000"。DHCP 服务器可以根据这个做条件分发。
1.4 一个完整的 PXE 启动文件链
启动文件本身不是孤立的。它还会去加载配置文件、内核、initrd。典型的链式加载过程是这样的:
- 第一阶段加载器(如
pxelinux.0或bootx64.efi) - 配置文件(如
pxelinux.cfg/default或grub.cfg) - 内核(如
vmlinuz) - 初始内存盘(如
initrd.img)
每个环节都依赖 TFTP 传输。你想想看,如果 TFTP 的块大小(blksize)默认是 512 字节,一个 5MB 的内核要传 10000 多次——能不慢吗?这就是后面章节要讲的调优点了。
一句话总结:PXE 启动就是“广播要地址 → 拿配置 → TFTP 拉文件 → 加载执行”四步走。每一步都可能成为瓶颈,咱们后面会逐个拆解。