
1. 机房批量装机的痛点与PXEKickstart的破局思路第一次接触几十台裸机同时上架的场景很多人下意识会抱着一摞U盘挨个插。我早年也干过这种事一台机器从插盘、选启动项、分区、配网络到装完基础软件顺顺利利也要二十多分钟中间只要有一台卡在某个界面没往下走整排进度就得停下来等。几十台下来一整天就搭进去了而且每台机器的手工分区、主机名、IP配置还容易写错后期排查问题的时间比装机本身还长。PXEKickstart这套组合就是专门解决这个场景的。PXEPreboot Execution Environment负责让裸机在没有任何本地存储的情况下通过网卡从网络上拉取启动文件并把安装程序跑起来Kickstart 则是一份预先写好的应答文件把安装过程中所有需要人工点选的步骤——语言、键盘、分区、网络、软件包、root密码——全部提前固化下来。两者拼在一起机器通电、网卡启动、自动装完、自动重启全程不需要人守在旁边。这套方案适合谁我把它分成三类一是手里有十几台以上物理机或虚拟机需要统一装系统的运维二是实验室、教学机房这类需要频繁重装、要求环境一致的场景三是想搞明白“无人值守装机到底是怎么跑起来的”这件事本身的技术爱好者。哪怕你只有两台机器把这套流程搭一遍对理解网络启动、DHCP、TFTP、HTTP这些基础服务的协作方式也很有帮助。需要提前说清楚一点这套东西的门槛不在某一步特别难而在于环节多、依赖链长。DHCP给错一个参数、TFTP根目录权限不对、Kickstart文件里少个斜杠都会让整条链路在某个你看不见的地方断掉。所以下面我会把每个环节为什么这么配、参数怎么算、容易在哪翻车尽量讲透。2. 整体架构拆解一台机器是怎么被“喂”起来的2.1 四个核心服务各自的角色整套流程里其实有四个服务在接力理解它们的分工排查问题时才能快速定位是哪一环掉了链子。DHCP裸机开机后网卡发广播找“谁能告诉我我是谁、去哪拿启动文件”。DHCP负责分配IP同时通过next-server和filename两个字段告诉客户端“启动文件在哪个服务器、叫什么名字”。这是整条链路的入口配错了后面全免谈。TFTP客户端拿到启动文件名后通过TFTP协议把引导程序BIOS用pxelinux.0UEFI用grubx64.efi之类下载到内存里执行。TFTP是个很轻量的协议配置简单但对权限和路径敏感。HTTP或FTP/NFS引导程序跑起来后需要加载内核vmlinuz和初始化镜像initrd.img以及后续的安装源整个ISO解压出来的文件树。这部分数据量大用HTTP比TFTP快得多也更稳。Kickstart文件服务安装程序启动后会去指定位置拉取ks.cfg应答文件按里面的指令完成分区、装包、配置。这个文件通常也放在HTTP服务上。把这四个服务串起来看数据流向是这样的网卡广播 → DHCP应答 → TFTP传引导程序 → HTTP传内核和安装源 → 安装程序读Kickstart → 自动装完。2.2 为什么是这套组合而不是别的方案有人会问现在镜像部署工具那么多为什么还要折腾PXEKickstart我的判断依据是场景。如果是虚拟机集群用模板克隆确实更快。但物理裸机没有“模板”这个概念你没法把一台装好的机器的硬盘直接复制到另一台上——硬件差异、UUID、网卡命名都会出问题。PXE是物理机层面最通用的网络启动标准几乎所有带网卡的机器都支持不依赖特定厂商工具。另一个原因是可控性。Kickstart文件是纯文本你能精确控制每一个分区大小、每一个软件包、每一条安装后脚本。想改配置改文本就行不用重新做镜像。这种“基础设施即代码”的思路在需要版本管理和审计的环境里特别有价值。至于为什么不用Cobbler这类封装工具——它们底层其实还是PXEKickstart只是加了管理层。如果你只是想搞懂原理或者环境不复杂直接手搭反而更透明出问题知道去哪找。Cobbler适合机器数量上百、需要集中管理多版本多架构的场景那是另一个话题了。2.3 网络环境的硬性前提搭这套东西之前有几个网络前提必须先确认否则后面全是坑。第一客户端和服务器必须在同一广播域或者说DHCP请求能到达你的DHCP服务器。跨网段不是不行但需要DHCP中继DHCP Relay配合复杂度上一个台阶。新手建议先在同网段里跑通。第二网卡必须支持PXE启动。这个绝大多数板载网卡都支持但要在BIOS/UEFI里确认启动顺序里网络启动是开着的。有些机器默认关闭或者被安全启动Secure Boot挡住。第三服务器最好有固定IP。DHCP、TFTP、HTTP都跑在这台上IP一变客户端全找不到。我一般直接配静态IP不依赖DHCP。第四关闭可能干扰的DHCP服务。如果网段里已经有别的DHCP服务器在发地址会和你的PXE DHCP打架客户端可能拿到错误的网关或启动文件路径。测试环境里最好隔离出一个干净网段。3. 服务端环境搭建从零把四个服务立起来3.1 系统准备与基础依赖我习惯用一台干净的Linux服务器做这件事发行版选和要部署的目标系统同系的会省心一些——比如要给一批机器装某个RHEL系发行版服务端也用同系软件包路径和依赖关系最顺。下面以常见的RHEL系为例Debian系的朋友把包管理命令换一下即可思路完全一样。先关掉防火墙和SELinux做联调跑通之后再按需放开。这一步不是偷懒是减少变量。等整套流程验证通过了再回头一条条加规则比一上来就被防火墙挡得莫名其妙要高效得多。# 临时关闭防火墙和SELinux生产环境请按需配置规则 systemctl stop firewalld setenforce 0接着装齐四个服务对应的软件包yum install -y dhcp tftp-server httpd syslinux xinetd这里解释一下每个包的作用。dhcp提供DHCP服务tftp-server提供TFTPhttpd是HTTP服务syslinux里带着pxelinux.0这个BIOS引导程序以及配套的菜单模块xinetd是老版本管理TFTP的方式新版本systemd直接管装不装看发行版。3.2 DHCP配置整条链路的入口DHCP配置是整套方案里最容易出错的地方我见过太多人卡在这里。核心就两个字段next-server告诉客户端TFTP服务器在哪filename告诉客户端下载哪个引导文件。# /etc/dhcp/dhcpd.conf 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; option domain-name-servers 192.168.100.1; next-server 192.168.100.10; # TFTP服务器IP filename pxelinux.0; # BIOS引导文件 default-lease-time 600; max-lease-time 7200; }几个关键点必须说清楚。next-server填的是TFTP服务器的地址如果TFTP和DHCP在同一台机器上就填这台机器的IP。filename对于传统BIOS客户端是pxelinux.0对于UEFI客户端则是grubx64.efi或shimx64.efi两者不能混用。如果你的环境里BIOS和UEFI机器都有就得用条件判断来区分这个后面单独讲。注意filename字段里的路径是相对于TFTP根目录的不要写成绝对路径。写/var/lib/tftpboot/pxelinux.0是错的直接写pxelinux.0才对。配完启动DHCPsystemctl enable --now dhcpd3.3 TFTP配置把引导程序递出去TFTP的根目录通常在/var/lib/tftpboot。需要把syslinux提供的引导程序复制进去并建立好目录结构。mkdir -p /var/lib/tftpboot/pxelinux.cfg 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/pxelinux.0是主引导程序menu.c32用来显示启动菜单ldlinux.c32是pxelinux运行时的依赖模块少一个菜单就出不来。这几个文件很多人只复制第一个结果引导到一半黑屏就是缺依赖。TFTP服务本身配置很简单确认它是启用的systemctl enable --now tftp.socket提示TFTP默认根目录和权限要确认。如果客户端能拿到IP但下载引导文件超时八成是TFTP根目录权限或SELinux的问题。临时setenforce 0能排除SELinux干扰。3.4 HTTP配置扛起安装源的大流量内核、initrd、整个安装源文件树都走HTTP。把安装ISO挂载或解压到HTTP根目录下mkdir -p /var/www/html/iso mount -o loop /path/to/install.iso /var/www/html/iso systemctl enable --now httpd用mount -o loop挂载ISO是最省空间的做法不用解压。挂载后/var/www/html/iso里就是完整的安装源里面有images/pxeboot/vmlinuz和images/pxeboot/initrd.img这两个文件后面引导菜单要用到。如果服务器重启后挂载会丢记得写进/etc/fstab或者干脆把ISO内容复制出来。生产环境我倾向于复制出来避免挂载点出问题导致整个装机流程瘫痪。3.5 引导菜单让客户端知道去哪拿内核在/var/lib/tftpboot/pxelinux.cfg/下创建default文件这是默认引导菜单default menu.c32 prompt 0 timeout 300 menu title PXE Boot Menu label auto-install menu label ^Auto Install System kernel http://192.168.100.10/iso/images/pxeboot/vmlinuz append initrdhttp://192.168.100.10/iso/images/pxeboot/initrd.img kshttp://192.168.100.10/ks/ks.cfgtimeout 300是30秒自动选择prompt 0表示不等待手动输入直接走默认项。kernel和append里的initrd都指向HTTP上的内核和镜像ks参数指向Kickstart文件的位置。这三个URL任何一个写错安装程序都起不来或者卡在找不到应答文件。注意ks后面跟的路径必须是安装程序能访问到的。如果Kickstart文件放在HTTP根目录的ks子目录下URL就是http://服务器IP/ks/ks.cfg别漏了协议头。4. Kickstart应答文件无人值守的灵魂4.1 文件结构分区解析Kickstart文件看着长其实就四大块系统标识与安装源、磁盘分区、网络配置、软件包与脚本。我习惯按这个顺序写逻辑清晰改起来也好找。先看开头部分#versionRHEL8 text lang en_US.UTF-8 keyboard us timezone Asia/Shanghai --isUtc rootpw --iscrypted $6$xxxxxxxxxxxxtext表示用文本模式安装比图形模式快且省资源。rootpw --iscrypted后面跟的是加密后的密码用openssl passwd -6或python -c import crypt; print(crypt.crypt(你的密码))生成。直接写明文密码虽然也能用但明文躺在文件里不安全也不专业。安装源部分url --urlhttp://192.168.100.10/iso这个URL指向HTTP上的安装源根目录安装程序会从这里找软件包。注意是根目录不是images/pxeboot那层。4.2 磁盘分区clearpart与part的配合分区是Kickstart里最需要想清楚的部分因为一旦写错装完的机器可能没法启动或者空间分配不合理。zerombr clearpart --all --initlabel part /boot --fstypexfs --size1024 part / --fstypexfs --size20480 --grow part swap --size4096zerombr清除磁盘上的无效分区表clearpart --all --initlabel表示清空所有分区并初始化磁盘标签。这两条是“推平重来”的组合适合全新装机。如果机器上有需要保留的数据千万别用--all。part /boot给1GB现代系统内核和initramfs加起来通常几百MB1GB留足余量。part /给20GB起步并加--grow意思是把剩余空间全给它。swap给4GB这个大小看内存和用途一般物理内存的1到2倍内存很大的服务器给4到8GB就够。提示如果要做LVM把part换成part pv.01加volgroup和logvol的组合。LVM的好处是后期扩容方便代价是多一层抽象。批量装机场景我一般直接上LVM省得以后加盘麻烦。4.3 网络与主机名批量场景下的动态处理批量装机最头疼的是每台机器的主机名和IP不能一样。Kickstart文件是静态的怎么让每台机器拿到不同的配置有两个思路。思路一在Kickstart里用network --bootprotodhcp让机器先拿DHCP地址然后在%post脚本里根据MAC地址去查表设置静态IP和主机名。这个查表可以是一个HTTP接口也可以是一个文本文件。思路二直接在DHCP里根据MAC绑定固定IPKickstart里写network --bootprotodhcp机器拿到的就是预设好的地址。主机名同样在%post里根据IP反查设置。network --bootprotodhcp --devicelink --activate network --hostnamenode-default--devicelink表示用第一个有链路的网卡避免多网卡机器选错。主机名先给个默认值后面用脚本改。4.4 软件包选择与安装后脚本软件包部分用%packages块%packages ^minimal-environment standard vim net-tools curl %end^minimal-environment是最小化环境组standard是标准工具组。批量装机我倾向于最小化加必要工具装完再按角色用配置管理工具推软件而不是在Kickstart里塞一大堆。这样镜像干净出问题也好排查。%post脚本是安装完成后执行的这是做个性化配置的黄金位置%post --log/root/ks-post.log #!/bin/bash # 根据MAC设置主机名 MAC$(cat /sys/class/net/*/address | head -1) hostnamectl set-hostname node-${MAC//:/-} # 配置内部yum源 cat /etc/yum.repos.d/internal.repo EOF [internal] nameInternal Repo baseurlhttp://192.168.100.10/repo enabled1 gpgcheck0 EOF %end--log参数把脚本执行日志写到文件里装完机器如果配置不对先看这个日志。脚本里用MAC生成主机名是个简单可靠的办法保证唯一性。注意%post脚本默认在chroot环境里执行网络可能还没完全就绪。如果脚本里要联网下载东西加个等待或者重试逻辑别假设网络一定通。5. 实操全流程与关键环节验证5.1 从裸机到装完的完整时间线把前面所有配置都做好之后实际跑一遍是这样的裸机通电网卡PXE启动发DHCP请求。DHCP服务器应答分配IP告知TFTP地址和引导文件名。客户端通过TFTP下载pxelinux.0并执行。pxelinux读取default菜单30秒后自动选择安装项。通过HTTP下载vmlinuz和initrd.img启动安装程序。安装程序通过HTTP拉取ks.cfg按文件指令分区、装包。%post脚本执行做个性化配置。安装完成自动重启从硬盘启动进入新系统。整个过程一台机器大约5到10分钟取决于网络和软件包数量。几十台同时跑主要瓶颈在服务器带宽和磁盘IO。5.2 关键参数的计算与选择依据有几个参数值得单独算一下。DHCP地址池大小如果同时装50台地址池至少要有50个可用地址加上服务器自己和其他设备建议留一倍余量配100个。租约时间设短一点600秒装完释放得快。TFTP块大小默认512字节传输大文件慢。可以在TFTP配置里调大blksize但pxelinux对某些选项支持有限一般保持默认也能用因为引导文件本身不大。HTTP并发几十台同时拉安装源Apache默认配置可能扛不住。可以调MaxClients或换Nginx。实测50台以内默认配置基本够用上百台就要优化了。分区大小/boot1GB、/20GB起步、swap按内存定。如果是数据库或大数据节点/var或数据盘要单独规划别全塞根分区。5.3 验证清单每一步怎么确认没配错搭完之后别急着批量上先拿一台机器验证。我习惯按这个清单逐项确认检查项验证方法预期结果DHCP是否响应客户端看是否拿到IP拿到预设网段地址TFTP是否可达tftp 服务器IP后get pxelinux.0文件下载成功HTTP是否可达浏览器访问内核URL能下载vmlinuz引导菜单是否显示客户端启动看屏幕出现菜单并倒计时Kickstart是否被读取安装界面看是否自动进行无需人工干预%post是否执行装完看/root/ks-post.log日志有内容无报错这个清单我每次搭新环境都过一遍能省下大量瞎猜的时间。6. 踩坑实录与常见问题速查6.1 那些年我踩过的典型坑坑一UEFI机器用BIOS引导文件。现象是客户端拿到IP后卡在TFTP open timeout或者直接跳过网络启动。原因是UEFI固件不认pxelinux.0它要的是EFI格式的引导程序。解决办法是准备两套引导文件在DHCP里根据客户端架构option arch判断UEFI给shimx64.efiBIOS给pxelinux.0。坑二Kickstart文件路径写错。现象是安装程序起来了但停在“找不到ks.cfg”的界面。检查ks后面的URL协议头、IP、路径大小写都要对。Linux路径区分大小写KS.cfg和ks.cfg是两个文件。坑三%post脚本里网络不通。现象是装完了但主机名没改、yum源没配。原因是%post默认在安装环境的chroot里跑网络配置可能还没生效。加--nochroot让脚本在真实环境跑或者脚本里先sleep 10等网络就绪。坑四分区写太满导致装不下。现象是安装到一半报“空间不足”。检查part /的size和grow设置如果软件包多20GB可能不够。可以先算一下%packages里所有包解压后大概占多少留20%余量。坑五DHCP和现有DHCP冲突。现象是客户端有时能装有时不能IP乱跳。排查网段里有没有其他DHCP在跑测试环境最好物理隔离。6.2 常见问题速查表现象可能原因排查方向客户端拿不到IPDHCP未启动/网段不对查dhcpd状态和subnet配置拿到IP但下载引导超时TFTP未启动/权限问题手动tftp测试查SELinux引导菜单不显示缺menu.c32/ldlinux.c32补全syslinux模块文件内核加载后黑屏initrd路径错/内核不匹配核对vmlinuz和initrd版本安装程序找不到ks.cfgURL错误/HTTP未启动浏览器直接访问ks URL装完无法启动引导程序没装到磁盘检查Kickstart里bootloader配置主机名都一样%post脚本没执行查ks-post.log和网络6.3 独家避坑技巧几个文档里不常写但很实用的经验。第一先在一台虚拟机上跑通再上物理机。虚拟机改配置快、重启快把整条链路验证通了再碰物理机能省下大量等待硬件重启的时间。第二Kickstart文件用版本控制管起来。每次改动都提交出问题能回滚也能看到哪次改动引入了问题。这个习惯在多人协作环境里尤其重要。第三%post脚本里加错误处理。脚本里每条关键命令后面判断返回值失败就写日志。别让脚本静默失败装完一堆机器发现配置没生效回头查都不知道哪步断的。第四保留一份“最小可用”配置。把能跑通的最简配置存一份后面加功能时如果出问题可以退回到最小配置对比快速定位是新加的哪部分导致的。第五日志集中收集。批量装机时每台机器的ks-post.log分散在各处排查麻烦。可以在%post里把日志推到一台日志服务器或者装完后统一收集。7. 进阶扩展让这套方案更贴合真实生产7.1 多版本多架构的统一管理真实环境里往往不止一种系统版本可能还有x86和ARM混用。这时候引导菜单要做成多选项DHCP要根据架构分发不同引导文件Kickstart文件也要按版本准备多份。引导菜单里可以列多个label每个label对应一个版本的内核和ks文件。DHCP里用option arch判断客户端架构UEFI x64给shimx64.efiBIOS给pxelinux.0ARM给对应的EFI文件。这套配置稍微复杂但一次搭好后面加版本只是加菜单项和ks文件的事。7.2 与配置管理工具的衔接Kickstart负责把系统装到“能联网、能跑脚本”的状态剩下的精细化配置交给配置管理工具更合适。我通常的做法是%post里只装配置管理工具的客户端并注册具体的软件、配置、服务由配置管理工具统一推。这样Kickstart文件保持简洁配置变更不用改装机流程。7.3 装机后的自动化验证装完不等于装对。可以在%post最后触发一个验证脚本检查关键配置是否符合预期——分区大小、软件包、网络、服务状态。验证结果上报到一台汇总服务器批量装机时一眼就能看出哪台有问题不用一台台登上去看。这套PXEKickstart的流程我从最早手动敲每一行配置到后来整理成模板反复用最大的体会是前期把每个环节的原理搞清楚后期改任何东西都心里有底。它不像某些一键工具那样“黑盒”每个参数你都知道为什么在那出问题也知道去哪找。这种透明感在需要长期维护的批量环境里比省那点搭建时间值钱得多。