网络启动核心组件:DHCP服务器、TFTP服务器、NFS/HTTP服务器、启动加载器
网络启动这件事,说白了就是让一台裸机通过网络把操作系统拉起来。你想想看,没有硬盘、没有光驱,机器怎么活?靠的就是几个核心组件协同工作。这一章我把它们拆开来讲,每个组件负责什么、怎么配、坑在哪,咱们一个一个过。
一句话总结:DHCP 给客户端发地址和启动文件路径,TFTP 或 HTTP 传小文件(启动加载器),NFS 或 HTTP 挂载根文件系统,启动加载器负责加载内核和 initrd。四者缺一不可。
2.1 DHCP 服务器:网络启动的“引路人”
DHCP 不只是发 IP 地址。在 PXE 场景里,它还要告诉客户端:“你的启动文件在哪,去哪个服务器拿。” 我刚开始接触 PXE 时,以为 DHCP 配个地址池就行,结果客户端死活不启动。后来才发现,少配了 next-server 和 filename 这两个选项。
DHCP 的核心配置项如下:
| 配置项 | 作用 | 示例值 |
|---|---|---|
subnet |
定义客户端所在的子网 | 192.168.1.0 255.255.255.0 |
range |
可分配的 IP 地址池 | 192.168.1.100 192.168.1.200 |
next-server |
TFTP/HTTP 服务器的 IP 地址 | 192.168.1.10 |
filename |
启动加载器的文件名 | pxelinux.0 或 bootx64.efi |
option bootfile-name |
UEFI 环境下的启动文件路径 | efi/grubx64.efi |
我个人习惯用 ISC DHCP Server,因为它稳定、文档全。下面是一个典型的 PXE 配置片段:
subnet 192.168.1.0 netmask 255.255.255.0 {
range 192.168.1.100 192.168.1.200;
option routers 192.168.1.1;
option domain-name-servers 8.8.8.8;
# PXE 专用选项
next-server 192.168.1.10;
filename "pxelinux.0";
# UEFI 客户端走不同文件
class "pxeclients" {
match if substring (option vendor-class-identifier, 0, 9) = "PXEClient";
filename "pxelinux.0";
}
class "eficlients" {
match if substring (option vendor-class-identifier, 0, 9) = "EFI Client";
filename "efi/grubx64.efi";
}
}
注意:如果 DHCP 和 PXE 服务器不在同一台机器,必须确保 DHCP 中继(ip helper)能正确转发 PXE 请求。我曾经在一个跨 VLAN 的环境里折腾了两天,最后发现是中继没开 DHCP Option 66 和 67。
2.2 TFTP 服务器:小文件传输的“老黄牛”
TFTP 协议很简单,基于 UDP 69 端口,没有认证、没有加密,就是传文件。你可能会问:“为什么不用 FTP 或 SCP?” 原因很简单——PXE 客户端在启动阶段,网卡固件只内置了 TFTP 和 HTTP 客户端,没有别的选择。
TFTP 的典型用途:
- 传输启动加载器(pxelinux.0、grubx64.efi)
- 传输配置文件(pxelinux.cfg/default、grub.cfg)
- 传输内核和 initrd(vmlinuz、initrd.img)
我推荐用 tftp-hpa 或 dnsmasq 自带的 TFTP 模块。配置起来很简单:
# 安装 tftp-hpa
yum install tftp-server -y
# 编辑 /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
disable = no
per_source = 11
cps = 100 2
flags = IPv4
}
# 重启服务
systemctl restart xinetd
小技巧:TFTP 默认传输块大小是 512 字节,传输大文件(比如内核)会很慢。可以在 server_args 里加 -b 1468 调整块大小,能明显提速。我在部署 500 台机器时,这个参数让启动时间从 3 分钟降到了 40 秒。
2.3 NFS/HTTP 服务器:根文件系统的“大后方”
启动加载器把内核和 initrd 拉下来之后,内核需要挂载根文件系统。这时候有两种主流方案:NFS 和 HTTP。
| 方案 | 协议 | 端口 | 适用场景 | 性能 |
|---|---|---|---|---|
| NFS | NFSv3/v4 | 2049 | 传统 PXE、无盘工作站 | 中等,依赖网络延迟 |
| HTTP | HTTP/HTTPS | 80/443 | 现代 PXE、大规模部署 | 高,支持并发和缓存 |
NFS 配置示例:
# 安装 NFS 服务器
yum install nfs-utils -y
# 编辑 /etc/exports
/var/nfsroot 192.168.1.0/24(rw,no_root_squash,sync,no_subtree_check)
# 启动服务
systemctl enable nfs-server
systemctl start nfs-server
HTTP 方案更现代,配合 nginx 或 apache 就能用。内核启动参数里加 root=/dev/nfs nfsroot=192.168.1.10:/var/nfsroot 或者 root=live:http://192.168.1.10/rootfs.squashfs。
我的建议:如果是新项目,优先用 HTTP。NFS 在并发高时容易出锁问题,HTTP 配合 squashfs 或 ext4 镜像更稳定。我在一个教育机房项目里,用 HTTP 方案同时启动 200 台终端,没出过问题。
2.4 启动加载器:承上启下的“指挥官”
启动加载器是网络启动的“大脑”。它从 TFTP/HTTP 下载配置文件,根据配置找到内核和 initrd,然后加载并启动系统。主流的有两种:
- pxelinux.0:传统 BIOS 下的选择,基于 SYSLINUX 项目,配置文件在
pxelinux.cfg/目录下。 - grubx64.efi:UEFI 下的选择,基于 GRUB2,配置文件是
grub.cfg。
pxelinux 的配置文件示例:
# /var/lib/tftpboot/pxelinux.cfg/default
default linux
prompt 1
timeout 100
label linux
kernel vmlinuz
append initrd=initrd.img root=/dev/nfs nfsroot=192.168.1.10:/var/nfsroot rw
GRUB2 的配置文件示例:
# /var/lib/tftpboot/efi/grub.cfg
set default=0
set timeout=10
menuentry "Network Boot - CentOS 7" {
linuxefi vmlinuz root=/dev/nfs nfsroot=192.168.1.10:/var/nfsroot rw
initrdefi initrd.img
}
避坑指南:我曾经遇到过一个问题——pxelinux 配置文件里写对了路径,但客户端就是找不到文件。后来发现是文件名大小写问题。PXE 客户端对大小写敏感,而 TFTP 服务器默认是大小写不敏感的。解决方案:统一用小写文件名,或者在配置里严格匹配。
2.5 核心组件协作流程图
下面这张图展示了客户端从加电到启动完成的完整流程,以及每个组件在其中的位置:
2.6 组件选型与版本兼容性
选型时要注意版本匹配。我见过有人用 ISC DHCP 4.x 配旧版 pxelinux,结果 Option 67 解析失败。下面是我整理的兼容性对照表:
| 组件 | 推荐版本 | 兼容性说明 |
|---|---|---|
| ISC DHCP | 4.3+ | 支持 Option 66/67,兼容 UEFI HTTP Boot |
| dnsmasq | 2.80+ | 内置 DHCP + TFTP + DNS,适合小规模环境 |
| tftp-hpa | 5.2+ | 稳定,支持块大小调整 |
| pxelinux.0 | 6.03+ | 支持 BIOS 和 UEFI(通过 syslinux.efi) |
| GRUB2 | 2.04+ | 支持 UEFI HTTP Boot,支持加密启动 |
| NFS | nfs-utils 2.3+ | 建议用 NFSv4,减少端口协商问题 |
| nginx | 1.20+ | 支持大文件并发,适合 HTTP 启动方案 |
个人经验:如果你在 UEFI 环境下用 GRUB2,记得把 grubx64.efi 和 grub.cfg 放在 TFTP 根目录的 efi/ 子目录下。DHCP 的 filename 要写成 efi/grubx64.efi,否则客户端会报找不到文件。这个坑我踩过两次,一次是手误写成了 EFI/grubx64.efi(大写),一次是忘了加子目录路径。