
做运维的人尤其是管机房的一定体会过这种场景十几台、几十台机器堆在那儿每台都要插U盘、选镜像、等安装、再拔U盘。装一台20分钟十台就是三四个小时中间再遇上镜像版本不对、硬盘没识别、U盘启动兼容性出问题一整天基本就交代过去了。后来我改用PXE批量网络装机这套流程被彻底改掉了——一台机器从加电到进入系统几分钟内完成几十台甚至上百台机器可以同时装而且最终装出来的系统状态完全一致排查问题的时间也几乎归零。这篇文章就是把我实际搭建PXE网络装机环境的过程、踩过的坑、以及摸索出的经验完整记录下来。重点会放在为什么要用PXE而不是其他方案、整个链条里DHCP/TFTP/安装源各自扮演什么角色、一次完整的搭建步骤是什么样、以及最常见的故障怎么排查。无论你是第一次接触PXE还是已经在用但经常被各种细节卡住这篇文章都能给你一套可以直接照着操作的路径。我会尽量用从业者之间交流的方式来讲该给配置就给配置该说坑就说坑不绕弯子。PXE高效批量网络装机1. 整体设计与思路拆解1.1 批量装机到底解决什么问题先说实话批量装机不是让你省掉一次U盘拷贝那么简单。它的核心问题是三个第一是规模。一台机器你爱怎么折腾都行但数量一上来人工操作的错误率就跟着上来了。插错U盘、选错镜像、分区没看仔细、格式化了下错盘这些问题在单台安装时不太明显批量操作时几乎必然发生。PXE把安装流程从“人对机器”变成“机器对服务器”人为干预的环节被压缩到最小。第二是一致性。你可能有过这种经历同一批机器分批装完结果A同学今天装的和B同学明天装的系统软件包版本、内核参数、分区大小全都不一样后面维护的时候只能挨个自查。PXE配合应答文件可以让每一台机器拿到完全相同的系统模板连装完之后的初始化脚本都一致这对后续做配置管理来说是极好的基础。第三是效率。注意这里的效率不只是“装得快”而是“人力的效率”。机器加电之后自动开始装你不用站在旁边等可以同时准备下一批机器。如果搭配IPMI带外管理或电源控制你甚至可以从办公室远程触发所有机器开机睡一觉起来系统全部就绪。这种体验用过一次就回不去了。1.2 PXE和克隆镜像方案我为什么这么选很多人会问既然批量装机用Ghost或者DiskGenius做硬盘克隆是不是更简单确实克隆方案在硬件配置完全一致、系统已经预装好的场景下非常快几分钟一台这点PXE比不了。但克隆有几个让我很难接受的问题硬件驱动残留。克隆的镜像里带着源机器的驱动程序换到另一台机器上尤其是芯片组、网卡、显卡不同的机器装完经常出现蓝屏、网卡不识别、磁盘控制器找不到的情况。虽然能通过注入驱动解决但那个工作量和踩坑概率并不低。镜像体积太大。一个Windows系统盘加上常用软件轻轻松松几十GB批量分发的网络压力不小U盘拷贝也很慢。而PXE安装使用的是发行版提供的基本安装镜像加上网络源和应答文件体积通常几百MB到几个GB对千兆网络来说压力非常小。可定制性差。克隆出来的系统是固化的你很难在克隆过程中动态改变主机名、IP地址、分区大小。而PXE配合应答文件可以在安装时按需配置这些参数做到“镜像一个模板适配多种角色”。当然PXE也不是万能的。如果机器硬件非常异构又没有统一服务器那PXE的优势会被削弱。我自己在实际中是按场景混用全新的、需要规范化系统用PXE装一台旧机器要快速恢复就扒个克隆盘。但在大规模、标准化交付的场景里PXE是我的首选。1.3 网络装机整体链路一次请求的生命周期在动手配置之前你必须先对整个流程有个画面感。PXE安装不是一个软件搞定一切而是好几个服务串起来的一次接力客户端网卡加电固件里启用了PXE预启动执行环境的话它会以广播的方式在局域网里寻找DHCP服务器。DHCP服务器除了分配IP地址还会回传两个关键信息引导文件的位置和下一跳服务器的地址。简单理解就是告诉客户端“你该找谁去拿什么文件”。客户端拿到信息后通过TFTP协议去那台服务器上下载引导程序比如pxelinux.0再根据引导配置去下载内核镜像vmlinuz和initrd内存盘。内核在内存中启动挂载initrd这个微型文件系统然后启动真实的安装程序。安装程序根据引导参数里给的安装源地址和应答文件地址去HTTP或者NFS服务器上拉取软件包和配置完成无人值守安装。整个过程里DHCP像门卫TFTP像一个小窗口专门把钥匙递给你HTTP或NFS才是真正的仓库把系统的具体内容交给你。你如果对其中任何一个角色理解不透彻后面排查故障时就会觉得非常玄幻——明明配置了可就是起不来。2. 核心细节解析与实操要点2.1 DHCP不只分配IP它还在指路很多人以为PXE就是搭个TFTP服务器放个引导文件结果发现客户端根本没有任何反应。这里最关键的是DHCP的PXE扩展字段。普通DHCP只给IPPXE请求时DHCP需要额外返回两个选项next-server也就是下一跳服务器地址和filename引导文件路径。用dnsmasq做这个特别方便因为它的配置非常集中。我习惯用dnsmasq同时管DHCP和TFTP一个服务搞定两个角色减少故障点。下面是一个最小可用的dnsmasq配置示例# /etc/dnsmasq.d/pxe.conf interfaceeth0 dhcp-range192.168.10.100,192.168.10.200,12h enable-tftp tftp-root/srv/tftpboot dhcp-bootpxelinux.0,pxeserver,192.168.10.10重点解释一下最后一行dhcp-boot这个参数分别指定了引导文件名、服务器主机名和服务器IP。客户端拿到这个信息后会直接去192.168.10.10找TFTP服务下载pxelinux.0。如果用标准DHCP服务比如isc-dhcp-server对应的写法是设置next-server和filename选项效果是一样的。其实就是同一个协议概念只是不同软件的表述不同。这里有个容易踩的坑如果局域网里原本就有别的DHCP服务器或者路由器默认开启了DHCP那么你的PXE请求有可能被另一台DHCP抢答客户端会拿到一个错误的引导地址然后卡死在启动画面。所以搭建PXE环境时尽量让客户端网络处于一个专门的广播域或者确保只有一台DHCP服务器在应答。这个细节我在真实环境里被坑过很多次明明PXE配置没问题就是随机性的部分机器能引导、部分不能最后定位到是办公网里的无线路由器在捣乱。2.2 TFTP小而专但别让它成为瓶颈TFTP本身是个非常简单的文件传输协议跑在UDP 69端口上没有复杂的认证和目录浏览功能。它存在的意义是在客户端还没有完整操作系统的时候只需要一种“最低门槛”的协议去下载一个很小的引导文件。你不需要HTTP不需要SSH只需要把引导程序安全地拿过来。但TFTP有一个显著的限制早期版本对单个文件大小有上限通常为32MB而UEFI格式的引导文件尤其是某些发行版的shim.efi、grubx64.efi体积很容易逼近这个限制。再加上TFTP协议本身没有拥塞控制在千兆网络中传输大文件时性能很差。解决办法有两种一种是把引导文件放在HTTP目录里通过HTTP启动UEFI引导。pxelinux.0本身支持从HTTP加载后续文件这样既能规避TFTP大小限制速度也更快。另一种是采用支持大文件的TFTP实现比如dnsmasq内置的TFTP默认不限制文件大小但你需要确保网络稳定不然UDP丢包会导致传输失败。我自己的实践是BIOS启动的机器用TFTP就够UEFI启动的机器尽量把内核和initrd放到HTTP目录里然后引导菜单通过HTTP去拉取。这样既保留了PXE的自动化能力又规避了TFTP传输大文件的各种问题。另外TFTP目录的权限要特别注意。很多发行版默认tftp-root设置在/srv/tftpboot这个目录如果权限不对客户端会请求文件超时。我用的是chmod -R 755加合理的属主权限确保dnsmasq进程能读到文件。排查时可以通过tcpdump -i eth0 port 69来抓包看客户端是否真的发来了TFTP请求以及服务端是否正常回应。2.3 安装源HTTP比NFS更适合大多数场景安装源是实际存放系统软件包的地方。你在PXE引导时指定的内核启动参数里有一项是安装源地址。客户端在内存中启动安装程序后会根据这个地址去抓取软件包。我推荐用HTTP服务做安装源。原因是速度快、穿透性好、调试方便。NFS也可以而且有些老教程喜欢用NFS但NFS对内核启动阶段和安装程序阶段都要求网络文件系统rpcbind等组件正常工作防火墙和安全策略一旦没配好就各种连接失败。以CentOS/Rocky Linux为例把ISO镜像挂载到HTTP目录下配置如下mkdir -p /srv/www/linux/rocky9 mount -o loop /path/to/Rocky-9.4-x86_64-dvd.iso /srv/www/linux/rocky9Nginx或者Apache里把这个目录发布出去。需要确认防火墙放行80或443端口。Ubuntu/Debian的思路相同只是源的结构和安装程序略有不同Ubuntu用的是debian-installer引导参数里要指定url或preseed/url。有一个细节值得注意如果你使用的是比较新的发行版安装源可能还需要包含提交到安装程序的其他组件比如仓库元数据。用完整DVD镜像是最稳妥的因为所有软件包都在里面不会出现装到一半提示找不到包的情况。如果用网络最小源则要确保安装环境能访问外网或内网软件源。2.4 应答文件无人值守的灵魂PXE全自动化的关键不在引导而在应答文件。所谓应答文件就是把安装过程中每一步的答案提前写在一个文件里安装程序会按这个文件的内容自动完成交互。CentOS/Rocky Linux用的是Kickstart文件通过ks参数指定地址Ubuntu用的是Preseed文件通过preseed/url参数指定地址。内容大同小异核心就几块语言与时区、键盘布局、磁盘分区、软件包选择、网络配置、以及安装后执行的脚本。一个常见误区是以为应答文件写好后就不用管了结果批量部署时每台机器的主机名都一样、IP都一样造成混乱。所以应答文件里应当使用变量或通过安装后脚本动态设置。比如Kickstart里可以用%include引入外部配置或让内核引导参数传入一个hostname变量脚本读取后写入系统配置。Kickstart示例片段如下%post HOST$(curl -s http://192.168.10.10/hostname/$(ip a | grep -oP ether \K[0-9A-F:]{17} | head -1)) hostnamectl set-hostname $HOST %end这里我用网卡的MAC地址去服务器查询对应主机名可以做到每台机器自动获得唯一标识而无需手动编辑任何文件。这个思路在批量部署时极其实用。3. 实操过程与核心环节实现3.1 环境规划先想清楚再动手搭建之前先把网络环境摸清楚。我习惯的规划方式PXE服务器固定IP192.168.10.10客户端网段192.168.10.0/24DHCP分配范围192.168.10.100到192.168.10.200HTTP安装源目录/srv/www/linux/TFTP根目录/srv/tftpboot/交换机端口确保客户端网络和服务器在同一VLAN或者交换机不做端口隔离这里特别提一句如果客户端开启了UEFI安全启动Secure Boot引导流程会不太一样。有些主板即便PXE里选的是网卡启动也可能因为签名校验失败导致无法引导。此时要么关闭Secure Boot要么准备UEFI版的shim引导文件。批量装机场景下我通常建议统一BIOS设置关闭Secure Boot省掉一大类兼容性问题。3.2 安装软件包dnsmasq和HTTP服务以Rocky Linux 9为例准备三个核心软件dnsmasq、nginx或httpd、syslinux。其中syslinux会提供pxelinux.0引导文件。dnf install -y dnsmasq nginx syslinuxsyslinux安装后pxelinux.0在/usr/share/syslinux/pxelinux.0还有一堆c32模块也在同目录。这些c32模块是菜单画图用的比如menu.c32、vesamenu.c32、ldlinux.c32。如果文件名对不上引导菜单会显示不了或引导失败。3.3 部署TFTP目录和引导文件这一步就是把引导程序复制到TFTP根目录并创建PXE配置目录。mkdir -p /srv/tftpboot/pxelinux.cfg mkdir -p /srv/tftpboot/images/rocky9 cp /usr/share/syslinux/pxelinux.0 /srv/tftpboot/ cp /usr/share/syslinux/vesamenu.c32 /srv/tftpboot/ cp /usr/share/syslinux/ldlinux.c32 /srv/tftpboot/把ISO里的内核文件也复制过去mount -o loop /path/to/Rocky-9.4-x86_64-dvd.iso /mnt/iso cp /mnt/iso/images/pxeboot/vmlinuz /srv/tftpboot/images/rocky9/ cp /mnt/iso/images/pxeboot/initrd.img /srv/tftpboot/images/rocky9/这里有两个常见问题。第一ldlinux.c32是BIOS模式引导必需的动态加载模块缺了它pxelinux.0会报无法找到ldlinux.c32。第二不同发行版的内核文件名可能不一样比如Rocky在/images/pxeboot/vmlinuzUbuntu在/install/netboot/ubuntu-installer/amd64/linux。先看看镜像目录结构别按经验硬套。然后创建PXE默认菜单文件/srv/tftpboot/pxelinux.cfg/defaultdefault vesamenu.c32 prompt 0 timeout 100 MENU TITLE PXE Installation Menu LABEL linux MENU LABEL Install Rocky Linux 9.4 (Auto) KERNEL images/rocky9/vmlinuz INITRD images/rocky9/initrd.img APPEND inst.repohttp://192.168.10.10/linux/rocky9 inst.kshttp://192.168.10.10/ks/rocky9.ks注意KERNEL和INITRD的路径是相对于TFTP根目录的。APPEND里的参数会被传给内核inst.repo指定安装源inst.ks指定应答文件。如果你没有应答文件把inst.ks去掉安装程序就会走交互模式——但那样PXE批量部署的意义就少了一半。UEFI模式下引导文件结构和菜单位置会不一样通常需要在TFTP根目录下准备EFI/BOOT/grubx64.efi并用grub菜单配置。如果目标是兼容BIOS和UEFI两种机器我建议单独建两个服务或目录用DHCP的dhcp-boot参数按客户端架构区分引导文件。3.4 发布HTTP安装源把挂载好的ISO目录发布出去。Nginx配置最小示例server { listen 80; server_name pxeserver.local; root /srv/www; autoindex on; }确保/srv/www/linux/rocky9下有repodata目录有它才能被安装程序识别为有效软件源。验证方法很简单curl -I http://192.168.10.10/linux/rocky9/ curl -I http://192.168.10.10/linux/rocky9/repodata/repomd.xml如果返回200安装源基本没问题。如果返回403多半是目录权限或SELinux的问题。SELinux这里是一个大坑HTTP服务默认只能读它认可的目录你手工创建在/srv/www的目录可能没有正确的SELinux类型。可以用chcon -R -t httpd_sys_content_t /srv/www来恢复标签或者临时setenforce 0做验证但生产环境千万别为了省事直接关SELinux最好搞清楚策略。3.5 编写无人值守应答文件应答文件的语法在不同发行版略有不同。以Rocky的Kickstart为例一份足够基础但可用于生产的配置大约是这个样子# /srv/www/ks/rocky9.ks langen_US.UTF-8 keyboard --xlayoutsus timezone Asia/Shanghai --isUtc rootpw --iscrypted $6$.... # 这里放加密后的密码哈希 user --nameadmin --groupswheel --iscrypted --password$6$.... zerombr clearpart --all --initlabel autopart --typelvm network --bootprotodhcp selinux --enforcing firewall --enabled --servicessh services --enabledsshd %packages core %end %post curl -s http://192.168.10.10/script/init.sh | bash %end rebootzerombr和clearpart --all会清空客户端硬盘所以执行前务必确认目标机器上没有需要保留的数据。autopart --typelvm自动完成逻辑卷分区适配大多数场景。%packages里可以用分组名称需要什么加什么。%post部分做初始化工作包括设置主机名、修改SSH配置、部署Agent等。对Ubuntu/Debian场景你基本只需要把Kickstart换成Preseed语法不一样但思路一样。还有一个小技巧Kickstart里可以直接%include一段共享模板或者用curl在安装前拉取一段动态生成的应答文件。这样模板维护只需要改一份机器多的时候优势特别明显。3.6 验证整条链路先手动再批量当你把所有服务都配置好后千万别一上来就同时开50台机器。我会先用一台测试机手动走一遍流程。给测试机插上网线设置BIOS优先从网卡启动。观察屏幕输出它应该先DHCP获取到IP然后TFTP下载引导文件显示菜单自动开始安装。安装过程中在服务端看日志journalctl -u dnsmasq -f和Nginx访问日志/var/log/nginx/access.log确认客户端确实向安装源拉取数据。整个安装结束后登录系统检查分区、网络、主机名、包列表。确认无误后再批量加机器。批量时我会建议分几批先一批5台看整体表现再全部上。如果你有带外管理比如服务器的BMC/IPMI这里的用词要小心避免编造真实实体统称带外管理可以远程触发开关机配合PXE能做到完全无人工值守。这个验证阶段最忌讳“着急”。很多人配置完直接批量跑结果一批50台全部失败反而更难排查是配置问题还是机器兼容性问题。一台机器验证通过后续只是复制成功经验顶多遇到个别硬件差异解决起来容易很多。4. 常见问题与排查技巧实录4.1 PXE引导阶段起不来这是最容易出问题、也最好定位的一段。现象可能原因与排查方向解决办法客户端卡在DHCP阶段反复获取不到IP网线没插好DHCP服务未启动端口被交换机隔离在服务端抓包看是否有DHCP DISCOVER用dhclient测试服务端分配是否正常客户端拿到IP但TFTP下载超时dnsmasq的tftp-root路径不对防火墙拦UDP 69检查systemctl status dnsmasq和tcpdump port 69确保防火墙放行69端口TFTP下载文件时提示PXE-E32或类似错误引导文件不存在文件名大小写不对路径错误核对dhcp-boot的filename与TFTP根目录下的实际文件名是否一致引导文件加载后卡在“no default or UI configuration found”pxelinux.cfg目录里没有default文件或者default找不到确认/srv/tftpboot/pxelinux.cfg/default存在且路径拼写正确UEFI机器引导失败或无响应缺少UEFI引导文件Secure Boot未关NBP文件过大准备EFI/BOOT/grubx64.efi关闭Secure Boot优先通过HTTP加载内核与initrd我把这条经验特别强调一下排查PXE问题时抓包永远是最高效的手段。一条命令tcpdump -i eth0 port 67 or port 69 -w /tmp/pxe.pcap然后另一台机器启动PXE几分钟后CtrlC结束抓包用Wireshark打开就能看到完整的四次握手DHCP Discover、DHCP Offer、DHCP Request、DHCP Ack。如果看不到TFTP请求说明前一步DHCP应答就没包含正确参数如果看到TFTP RRQ但一直没响应基本就是服务侧的文件路径或权限问题。4.2 系统安装到一半挂了引导阶段过了不等于万事大吉。安装中途挂掉往往是安装源或应答文件的问题。最典型的两个场景第一个是客户端能从PXE引导也能进入安装界面但报“无法找到安装源”或“repo metadata not found”。这种基本是HTTP安装源路径写错或者Nginx没把目录发布出去。先手动curl验证源地址再检查Nginx日志。有时是ISO挂载位置没同步比如重启后挂载丢失服务端目录是空的。我建议把挂载写入fstab或者用systemd挂载单元避免重启后掉挂。第二个是安装过了大半才报错可能是特定的软件包拉不到。如果使用网络最小源而非完整DVD镜像源不全就会这样。最省心的办法还是优先用完整DVD镜像做源。如果你确实只能用最小源至少确保镜像仓库的连通性测试提前通过。还有一个容易被忽略的点客户端内存大小。PXE启动时整个内核和initrd都要放进内存如果客户端配置很低内存小于2GB有些图形化安装程序会加载不了。可以换用VNC模式或文本安装模式减少内存压力。这个在老旧硬件批量部署时很常见。4.3 Kickstart应答文件不生效安装了但是走了一堆交互界面——说明应答文件没有生效。可能原因有几个inst.ks没传对。确认引导参数里拼写正确Kickstart的URL能被客户端访问到。有些环境里客户端获取不到服务的IP导致应答文件拉取失败。应答文件本身语法有错。Kickstart对语法非常敏感一个关键字写错了它宁可放弃自动安装也不会提示“这里有问题”。我建议在服务器上提前用安装程序自带的工具做语法校验或者找一台测试机跑一遍确认无误再批量。权限问题。如果应答文件通过HTTP访问注意目录权限和Nginx用户属主别把文件放在容别人写的位置也不要让Nginx没权限读。另外如果你的Kickstart里分区策略对某些机型不兼容比如机器只有一块小硬盘但分区配置里要求过大安装程序会直接停在分区步骤等你手工确认。批量部署前务必用目标机型的实际硬件做验证。4.4 软件源里没网卡驱动或磁盘驱动这是异构硬件环境里必须面对的问题。PXE启动时用的内核是发行版自带的通用内核如果你的机器网卡太新或太冷门内核里没有对应驱动DHCP都过不去更谈不上装系统。处理思路大概有三种第一种选择较新版本的发行版或内核新内核通常覆盖更多驱动。第二种通过自定义initrd比如用dracut往里面注入驱动模块。第三种在安装启动参数里直接指定驱动包路径比如inst.ddhttp://server/rdriver.iso。我自己的建议是做批量装机之前先确认目标机器的硬件型号如果网卡不在常见列表里就先查一下内核是否支持再决定要不要额外准备驱动。临时拿一台机器做验证的意义就在这里一次验证能避免后面几十台机器的返工。4.5 批量部署时IP和主机名冲突如果你用Kickstart里静态配置IP那批量部署绝对会乱套。每台机器都写同样的IP装完根本没法用。所以批量场景下网络配置必须要动态化。方案一网络部分用--bootprotodhcp让路由器或DHCP做地址管理之后通过%post脚本根据MAC查询主机名和IP再写入系统配置。方案二引导阶段通过内核参数传入唯一标识例如hostnamenode-01由安装脚本读取并应用。方案三如果具备带外管理能力可以先把每台机器的MAC地址和主机名对应关系登记到管理系统的数据库里PXE启动时查询一下动态生成对应每台机器的应答文件。这个做法更彻底一台服务器就能管理几百台机器的部署和重装但前期要搭一个小型管理系统。我常用的是方案一加一个简单的API接口装好后系统自动调用一次注册接口把自己的MAC、IP、主机名上报完成自动入库。这套流程在自动化运维里几乎成了标配。4.6 安全防护和实际环境里的副作用PXE服务端暴露在网络上本身是一个安全敏感点。我自己有几点建议DHCP服务不要轻易在办公网直接开启避免干扰正常办公设备的地址分配。如果你确实需要跨网段部署需要配置DHCP中继而不是简单扩大DHCP范围。应答文件里如果有root密码不管是不是加密过的都要保证HTTP服务不会泄露给不相关的人。最好限制访问只允许安装网段的客户端访问该路径或者用防火墙规则限定来源。%post脚本如果是从HTTP下载那一台机器被入侵后可能对整个批量部署流程造成影响。生产环境建议对所有内部地址走内部DNS和HTTPS或者至少用签名校验。另外要注意PXE部署对网络带宽的影响。几十台机器同时从HTTP源拉包如果源服务器的磁盘IO和带宽不够会出现部分机器等待超时或下载缓慢。千兆内网一般够用但如果同时并发特别多建议把安装源放到多块磁盘或SSD上或者提前把一些已经验证的系统做成模板用分层思路减少瞬时压力。5. 踩过几次坑之后才明白的事写到这里我总结一下现阶段我搭建PXE批量网络装机的几个核心体会也算是对后面接手的人的一些提醒。第一PXE不是某一个软件的配置而是一个链路。你缺的往往不是某个服务没装而是链路中某一环的错误。所以遇到问题的第一反应该是顺着链路查DHCP给没给指路TFTP能不能下载HTTP源能不能访问应答文件语法对不对。用抓包工具把链路捋通问题基本就浮出水面。第二尽量追求全程无人值守。我刚接触PXE时应答文件里只写了基础系统配置其余交互还是靠人点。后来发现批量部署根本不可能让你一台台点于是把Kickstart覆盖到分区、软件包、网络、后置脚本再配合带外管理的远程开机整套流程才真正跑通。自动化程度越高交付越稳定。第三把PXE环境当作基础设施去维护。PXE服务器不是搭完就完事了内核版本更新、发行版升级、新增机型驱动都会影响后续部署。我会定期更新TFTP目录里的内核和initrd保持HTTP源里ISO版本与最新补丁同步。这些看似和“装机”无关的维护工作恰恰决定了批量部署的长期可靠性。第四文档一定要及时写。别高估自己的记忆力半年后再接手这套PXE环境你很可能想不起当初某个奇怪的参数为什么那么配。我在服务器上保留了一份搭建说明和故障速查表每次改动都顺手更新。虽然写文档这件事很没成就感但它在关键时刻能救命。最后一句话送给准备上手的朋友PXE本身不难难的是理解它背后网络交互的逻辑。先把链路想清楚再动手配你会少走很多弯路。我现在每次接到批量装机的需求心里都有底气不是因为我配得有多花哨而是因为我踩过的坑足够多知道问题来了该往哪儿看。