深夜,机房还有七台配置完全一样的服务器等着装系统。按老办法一台台来,每台都得盯着屏幕选语言、划分区、设密码,平均一台三十分钟,七台就是小半天,人还寸步不能离。后来我花了点时间把PXE加Kickstart这套无人值守安装流程在CentOS 6.4环境下彻底跑通,从那以后交付服务器变成了“开机、等、完事”三个步骤。这篇就把整个环境的搭建过程、配置细节和我在实测中踩过的一堆坑完整记录下来。
对于还在用CentOS 6.x维护老环境的朋友,或者刚接触网络安装、想理解PXE和Kickstart配合原理的运维新人,这篇文章可以直接照着操作。即便你现在的生产环境已经换到7、8或者衍生版,这套架构思路也依然成立,只是个别软件包名和内核参数略有差异。
1. 为什么服务器批量交付必须靠PXE+Kickstart
先聊聊这套方案到底解决了什么问题。
手动安装的最大痛点不是“慢”,而是“人不能离开”。每台机器在安装过程中都有几个必须人工干预的节点:选择安装界面语言、确认磁盘布局、设置root密码、选择软件包组。一旦中间某个节点没人点一下,安装进程就卡在那,直到超时或报错。更难受的是,这些操作完全重复,没有任何技术含量,但又不能交给不懂的人去点,因为误操作会直接导致分区错误甚至数据丢失。
PXE的技术本质并不复杂。它是Intel定义的一套网络引导标准,在网卡固件层面实现了“从网络启动”的能力。机器开机后,网卡主动发送广播请求,从网络中的DHCP服务器获取IP地址,同时拿到引导文件的位置,再从TFTP服务器下载引导程序,最终加载内核和初始化内存盘,进入系统安装流程。
Kickstart则是Anaconda安装器的应答机制。它本质上是一个文本文件,预先把安装过程中所有需要人工回答的问题都写好:磁盘怎么分区、时区选哪个、root密码是什么、要装哪些软件包、装完后执行什么脚本。Anaconda启动后检测到ks文件,就不再询问任何问题,全程按脚本自动执行。
PXE和Kickstart的关系可以这样理解:PXE解决的是“怎么把安装程序拉起来”的问题,Kickstart解决的是“安装程序起来之后每一步干什么”的问题。一个管引导,一个管执行,两者串起来就是完整的无人值守链路。
这套方案适合的场景很明确:同配置机器批量交付、测试环境需要反复重建系统、机房新到一批服务器需要统一初始化。另外还有一个容易被忽略的价值——一致性。手动安装靠人点,不同的人点出来的系统可能有细微差别,比如分区大小手一抖差个几G,而Kickstart让每一台机器的系统完全一致,后续运维省掉不少差异化排查的功夫。
2. 整体架构与前置准备:谁在管什么
在动手配置之前,先花两分钟把架构理清楚。这一步跳过,后面配置的时候会到处“差一根线”。
整套环境需要三类网络服务,可以全部装在同一台部署服务器上,也可以拆开。我建议前期实验阶段全装在一台机器上,减少变量。它们的分工如下:
- DHCP服务:给客户端分配IP地址,同时通过
next-server和filename两个字段,告诉客户端“你去这个IP找TFTP服务器,取这个引导文件”。这是整个链路的第一步,也是很多人配置出错的地方。 - TFTP服务:一个极简的文件传输协议,只负责传小文件。它传的就是引导程序
pxelinux.0、内核vmlinuz和初始化内存盘initrd.img。不要拿它传安装源,会慢到怀疑人生。 - HTTP服务:负责传大头——Kickstart应答文件和系统安装源。选择HTTP而不是FTP或NFS,原因就一个:配置最简单,穿透防火墙最省事,而且支持大文件并发传输。生产环境里HTTP也是主流。
客户端的启动流程是这样的:开机后网卡发DHCP广播,拿到IP和引导信息;接着从TFTP下载pxelinux.0;这个引导程序读取TFTP上pxelinux.cfg/default配置文件,根据配置下载vmlinuz和initrd.img,并附带内核启动参数;内核启动Anaconda后,通过参数里的ks地址从HTTP拉取Kickstart文件;最后按Kickstart的配置从HTTP安装源拉取软件包,完成安装。
<pre-arch:从准备清单来看,建议准备以下环境:一台部署服务器(物理机或虚拟机都可以,内存不低于2G,磁盘剩余空间不低于20G),若干台待安装的客户端,一台傻瓜交换机。所有机器放在同一个二层广播域内,部署服务器配置固定IP。操作系统镜像使用CentOS 6.4的DVD ISO,这个镜像里已经包含了你需要的全套服务端软件和引导文件。>
还有两个前置条件必须确认。第一,客户端网卡要支持PXE引导,2010年以后的主流服务器和虚拟机默认都支持,但有些机器需要在BIOS里把网卡启动选项打开,或者在启动时按快捷键选择从网络启动。第二,客户端引导模式必须是传统BIOS而非UEFI,pxelinux.0这套方案只适用于传统BIOS引导。如果是纯UEFI环境,需要换用grub2-efi或ipxe方案,那是另一套配置思路,这里不展开。
3. 三个核心服务的安装与配置细节
下面进入实际操作阶段。部署服务器用CentOS 6.4最小化安装,配好固定IP后先把三个服务逐个装起来。
3.1 DHCP服务:客户端的第一个“向导”
DHCP在这里的角色不只是分配IP,更重要的是它在分配IP的同时把引导信息“塞”给了客户端。安装和配置过程如下:
yum install -y dhcp默认安装完成后,主配置文件/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; filename "pxelinux.0"; }这里有几个字段必须解释清楚。
next-server后面跟的是TFTP服务器的IP地址。客户端拿到这个地址之后,就知道该去向谁要引导文件。filename指定的是要下载的引导文件名,这里写pxelinux.0,这是Syslinux提供的PXE引导程序。
option routers和option domain-name-servers可以根据实际网络填,如果客户端在安装过程中需要访问外网(比如从外网镜像拉包),这里的网关和DNS就必须正确。如果纯内网安装,填一个内网地址即可,但字段不能删,否则客户端在安装早期阶段可能因为网络初始化失败而卡住。
配置完成后启动服务并设为开机自启:
service dhcpd start chkconfig dhcpd on同时确认防火墙放行了UDP 67端口:
iptables -I INPUT -p udp --dport 67 -j ACCEPT service iptables save注意:DHCP服务对配置文件的语法极其敏感,任何一个分号、括号写错都会导致服务启动失败。写完配置后可以用
dhcpd -t命令测试语法,这个习惯我一直保留着。
3.2 TFTP服务:轻量引导文件的搬运工
TFTP服务的安装方式在CentOS 6.x上比较特殊,它由xinetd超级守护进程托管。
yum install -y tftp-server xinetd安装后需要修改/etc/xinetd.d/tftp文件,核心是把disable从yes改为no:
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 }server_args里的-s /var/lib/tftpboot指定了TFTP服务的根目录为/var/lib/tftpboot。客户端下载文件时,路径都是相对于这个根目录的。如果你把引导文件放在其他目录,记得同步修改这里,否则客户端会一直报“TFTP open timeout”。
启动服务:
service xinetd start chkconfig xinetd on放行UDP 69端口:
iptables -I INPUT -p udp --dport 69 -j ACCEPT service iptables saveTFTP本身极简,没有用户认证、没有目录列表,但也正因如此,它的定位就是“传完即走”。如果传输过程中出现超时、卡顿,优先检查防火墙和SELinux,后面我会专门讲排查过程。
3.3 HTTP服务:安装源与应答文件的宿主机
HTTP服务负责两件事:一是提供Kickstart应答文件的访问,二是提供整个安装源(repodata目录、软件包等)。安装和配置非常简单:
yum install -y httpd service httpd start chkconfig httpd on然后把CentOS 6.4 DVD镜像挂载到HTTP服务的根目录下。我习惯建一个专门目录:
mkdir -p /var/www/html/centos6 mount -o loop /path/to/CentOS-6.4-x86_64-bin-DVD1.iso /var/www/html/centos6为了让重启之后挂载不丢,把挂载信息写入/etc/fstab:
/path/to/CentOS-6.4-x86_64-bin-DVD1.iso /var/www/html/centos6 iso9660 loop,defaults 0 0放行TCP 80端口:
iptables -I INPUT -p tcp --dport 80 -j ACCEPT service iptables save到这里,三个服务已经就绪。建议你现在就做一次联通性验证,不要急着往下配置。在浏览器里访问http://部署服务器IP/centos6/,能看到目录列表就说明HTTP正常。用下面的命令测试TFTP:
tftp 部署服务器IP -c get pxelinux.0这条命令虽然现在pxelinux.0还没放到TFTP目录下,会提示文件不存在,但只要连接没有被拒绝,就说明TFTP服务和防火墙状态是正常的。先把这条链路确认通,后面排查问题就能少一半的变量。
4. Kickstart应答文件:从模板到一份能上生产的配置
Kickstart文件是整个无人值守流程里最有含金量的部分。它决定的不是“能不能装上”,而是“装出来的系统什么样”。
生成Kickstart文件有三种路径,你可以根据习惯选择:
| 生成方式 | 优点 | 缺点 |
|---|---|---|
| 手写 | 完全可控,熟悉每条指令 | 有语法风险,调试成本高 |
图形工具system-config-kickstart | 可视化,适合新手入门 | 生成的配置较保守,部分高级功能不支持界面配置 |
基于参考机anaconda-ks.cfg修改 | 最贴合实际需求,参考机怎么分区、装了什么一目了然 | 需要先手动装好一台“完美样板机” |
我最常用的是第三种:手动装一台机器,装的过程中记录所有选择,装完后去/root/anaconda-ks.cfg拿成品,再按需修改。这份文件是Anaconda在整个安装过程中实际使用的应答记录,真实可靠。
下面给出一份可供参考的Kickstart文件,我逐段说明关键点:
# 全新安装 install # 安装源地址 url --url=http://192.168.100.10/centos6 # 语言、键盘与时区 lang en_US.UTF-8 keyboard us timezone Asia/Shanghai # root密码,这里用到的是加密后的hash rootpw --iscrypted $6$k3AJf3mR$9yEU2qvoO6G9gY0Zfya9lC # 网络配置:DHCP获取 network --bootproto=dhcp --device=eth0 --onboot=yes # 认证方式 authconfig --enableshadow --passalgo=sha512 # 关闭防火墙和SELinux,实验环境优先保证安装成功率 firewall --disabled selinux --disabled # 引导程序配置,写进MBR bootloader --location=mbr # 磁盘分区:清空磁盘并创建自定义分区布局 zerombr clearpart --all --initlabel part /boot --fstype=ext4 --size=500 part / --fstype=ext4 --size=20480 part /data --fstype=ext4 --size=1 --grow # 软件包选择:最小化+常用工具 %packages @base @development vim lrzsz %end # 安装后脚本:系统初始化操作 %post # 删除网卡持久化规则,避免克隆后eth0变eth1 rm -f /etc/udev/rules.d/70-persistent-net.rules # 清空SSH主机密钥,保证每台机器密钥唯一 rm -f /etc/ssh/ssh_host_* # 设置默认运行级别为命令行 sed -i 's/id:5:initdefault:/id:3:initdefault:/' /etc/inittab # 将本机主机名写入配置 sed -i 's/HOSTNAME=.*/HOSTNAME=node01.example.com/' /etc/sysconfig/network %end逐段解读几个容易踩坑的细节。
url --url=http://192.168.100.10/centos6这行指定了安装源。注意这里必须指向镜像解压后包含repodata目录的那一层,不是挂载点的上级目录。如果这个地址写错,安装过程会在“设置软件仓库”阶段报错,界面直接卡死或者退出。
rootpw这行特别强调一下,生产环境一定要用--iscrypted参数加上加密后的密码,千万不要直接写明文rootpw 123456。明文密码会留在pxelinux配置和网络传输中。生成加密串的命令是:
grub-crypt --sha-512分区策略上,我习惯给/留足20G以上,/data分区用--grow参数吃掉剩余空间。如果你的部署场景对分区有严格要求,可以去图形工具里对着划,原则是服务器通用场景下尽量简化分区层级,减少后续运维的理解成本。
%post段是整个文件的精华。直接复用参考机的系统会有两个隐蔽问题:一是网卡持久化规则文件记录了原机器的MAC地址,克隆之后新机器网卡无法正确识别为eth0;二是SSH主机密钥如果全部一样,后续用SSH连接时会引发密钥冲突告警,存在安全风险。所以在%post里删除这些文件、让系统首次启动时自动重新生成,是批量交付中必须处理的细节。
Kickstart文件写好后,放到HTTP服务的目录下,确保能通过浏览器访问:
cp kickstart/ks.cfg /var/www/html/ks/验证一下URL可以访问:http://192.168.100.10/ks/ks.cfg。这一步千万不能省,我见过太多人写完ks文件直接去装机器,结果在分区步骤前卡住,回头一查是ks文件的URL拼错了。
5. PXE引导配置:把整个安装流程串起来
服务端三个服务和Kickstart文件都就绪后,最后一步是把PXE引导程序的目录结构搭起来。
首先从CentOS 6.4安装镜像里准备三个关键文件。DVD镜像的isolinux目录下就能找到vmlinuz和initrd.img,这两个分别是安装内核和初始化内存盘。pxelinux.0这个引导程序通常在/usr/share/syslinux/下,但如果部署服务器是最小化安装没有装Syslinux包,可以直接从镜像的isolinux目录里找,CentOS 6.x的镜像内自带一份。把它们都拷贝到TFTP根目录:
cp /mnt/isolinux/vmlinuz /var/lib/tftpboot/ cp /mnt/isolinux/initrd.img /var/lib/tftpboot/ cp /mnt/isolinux/pxelinux.0 /var/lib/tftpboot/接着创建pxelinux.cfg目录并写入默认引导配置:
mkdir /var/lib/tftpboot/pxelinux.cfg/var/lib/tftpboot/pxelinux.cfg/default文件内容如下:
default menu prompt 0 timeout 60 label linux menu label ^Install CentOS 6.4 x86_64 kernel vmlinuz append initrd=initrd.img ks=http://192.168.100.10/ks/ks.cfg逐一解释配置项的作用。
prompt 0表示开机后不询问用户,直接执行默认label对应的操作。如果是实验环境想看到引导菜单再做选择,把prompt改为1,或者给它一个超时时间让用户有操作窗口。
label linux是引导条目名称,menu label是显示在菜单上的文字。^符号表示快捷键,图上会有一个下划线修饰的字符,比如这里按L键即可选中此条。
最关键的是append这一行。initrd=initrd.img指定初始化内存盘,ks=http://192.168.100.10/ks/ks.cfg指定Kickstart文件的网络地址。这一行就是整个PXE引导和Kickstart自动应答之间的桥梁。如果这条参数缺失或写错,Anaconda启动后会进入图形交互式安装界面,无人值守就变成有人值守了。
你还可以在同一个default文件里配置多个label,对应不同的安装场景。比如一个label走最小化安装的ks,另一个label走带图形桌面环境的ks,再配一个label用于内存检测。菜单选择的功能让同一套PXE环境同时服务多种装机需求:
label minimal menu label ^Minimal Install kernel vmlinuz append initrd=initrd.img ks=http://192.168.100.10/ks/ks_minimal.cfg label desktop menu label ^Desktop Install kernel vmlinuz append initrd=initrd.img ks=http://192.168.100.10/ks/ks_desktop.cfg到这一步,整套PXE+HTTP+TFTP+DHCP环境就已经全部串起来了。把客户端的启动顺序调整为“网络启动优先”,开机后你应该会看到引导菜单,选择对应条目后自动进入Kickstart安装流程。
6. 实测中踩过的坑:完整排查链路
理论配置全部完成,不代表能一次性跑通。我在这个环境上做过多次重复安装测试,下面这五个坑是出现频率最高、也最让人抓狂的,每个都附上我从现象反推根因的完整排查链路。
6.1 坑一:客户端拿到了“别人家”的IP地址
现象:客户端开机进入PXE引导后,在DHCP阶段卡了很久,然后跳出了奇怪的IP信息,后续无法从TFTP下载引导文件。
排查过程:我先在部署服务器上确认dhcpd服务运行正常,然后去客户端捕获的PXE日志里看到它拿到的IP根本不是部署服务器分配的192.168.100.x网段。回头检查虚拟化平台的网络配置,发现问题出在虚拟机的默认NAT网络自带了DHCP服务,这个服务在同一个广播域里“抢答”了客户端的DHCP请求。
修复方式:把部署服务器和待安装客户端放进VMware Workstation的“仅主机模式”网络里,并在虚拟网络编辑器中关闭该网络的DHCP服务,只保留一个静态子网。物理机环境则要确认交换机上只有部署服务器这一台DHCP服务器,不存在多个DHCP服务互相抢答的情况。
经验:PXE环境里的DHCP必须唯一。当客户端广播请求时,如果网络中存在第二个DHCP服务,谁能更快响应就会抢到这个机会,PXE引导信息也只能从响应的那台DHCP服务返回。这不是配置错误,是网络环境层面的“插队”。
6.2 坑二:PXE引导成功了,但安装进入图形界面而不是自动执行
现象:客户端成功从TFTP下载了引导文件并启动内核,但进入的是Anaconda图形安装界面,和手动安装没有任何区别,无人值守直接失效。
排查过程:这个现象说明引导链路是通的,问题集中在Kickstart地址没传对。我去TFTP根目录检查了pxelinux.cfg/default文件,发现里面有ks=http://192.168.100.10/ks/ks.cfg这个参数,但仔细一看IP末尾多了个斜杠拼写错误。客户端在加载内核时没有收到合法的ks地址,Anaconda只能退回交互模式。
修复方式:修正default文件里的ks参数,确保URL从部署服务器上可以完整访问。以后每次改完default文件,我都会在浏览器里先试一遍Kickstart地址,确认能打开文件内容再去做装机测试。这个习惯帮我节省了至少十次重启客户端的时间。
6.3 坑三:TFTP下载文件极慢,卡在加载initrd阶段
现象:客户端能拿到引导程序pxelinux.0,但在下载initrd.img时速度极慢,左等右等最后超时失败。
排查过程:TFTP传输很慢的典型原因有三个:网络链路问题、文件过大、UDP被限速。我在部署服务器上用tftp命令手动下载同一个文件,发现也慢。用tcpdump抓包看TFTP流量,确认UDP 69端口数据往返正常,服务端每次ACK都及时,唯一的问题是客户端在TFTP默认的块大小下反复等待确认应答,传输效率极低。这是TFTP协议本身的特性,每个数据块都要等待ACK确认,延迟高时效率下降明显。
修复方式:首先确认防火墙没有限制UDP端口的传输速率,再检查是否多个客户端同时从一台TFTP下载导致拥堵。对于大文件,我更建议在TFTP配置里显式调大块大小参数,把server_args加上--blocksize 1468,CentOS 6.x的tftp-server支持这个选项,能从根上缓解慢的问题。
6.4 坑四:安装到一半提示找不到网卡
现象:Anaconda启动后进入安装流程,但到网络配置阶段报错,提示找不到可用的网络设备,安装无法继续。
排查过程:这个问题发生在较新的网卡硬件上,比如Intel I219-V这类型号。CentOS 6.4的发行内核较早,驱动列表里没有包含这些新硬件的驱动模块。PXE引导本身没有问题,vmlinuz能加载但内核缺少对应的网卡驱动,自然无法初始化网络。
修复方式:两个方向。一是加载驱动程序初始化盘,将厂商提供的驱动做成dd镜像挂进initrd里,在append后面追加dd=http://192.168.100.10/drivers/。二是把内核和驱动同步升级到较新的维护版,比如CentOS 6.10的内核驱动覆盖面远好于6.4。作为经验,正式环境批量交付前先用一台待交付型号做测试机,可以提前发现这类硬件兼容性问题。
6.5 坑五:系统装完了,但IP地址没有生效
现象:Kickstart安装全程顺利,重启后进入系统,但ifconfig显示网卡没有IP,网络不通。
排查过程:我在%post脚本里执行了删除网卡持久化规则的操作,理论上重启后系统会重新生成规则并匹配当前MAC地址。但实测发现,虚拟化平台上的网卡MAC会在多次克隆后变化,而network服务在启动时读取了旧的/etc/sysconfig/network-scripts/ifcfg-eth0配置,设备名对不上,网络自然起不来。
修复方式:在Kickstart文件里把网络配置改为network --bootproto=dhcp --device=ethX --onboot=yes,并在%post里用脚本动态修正接口名与配置文件名的对应关系。更稳妥的做法是让%post直接重写/etc/udev/rules.d/下的持久化规则,并确保配置文件里的DEVICE=与当前接口名一致。
这五个坑基本覆盖了PXE+Kickstart环境的绝大多数故障类型。核心排查思路是逐层断开:先确认DHCP通不通,再确认TFTP通不通,再确认HTTP通不通,最后才去检查Kickstart文件内容本身。每次出问题都从链路最前端重新拉起,不要跳着猜。
7. 从能用到好用:批量交付场景的进阶扩展
当整套PXE+Kickstart环境跑通之后,你已经解决了“能不能自动装”的问题。接下来就是锦上添花的优化了,这些配置不影响核心功能,但会让日常维护舒服很多。
针对不同硬件的多个分组,你可以为每个分组配置不同的Kickstart文件。比如数据库服务器和Web服务器的分区策略、软件包组合完全不同。PXE引导菜单天然支持多label,你要做的只是维护好多个ks文件,在菜单条目上分别指向它们。这样同一套PXE环境就能一次性交付不同规格的服务器。
对于需要固定IP的交付场景,DHCP支持基于MAC地址的静态绑定:
host node01 { hardware ethernet 00:0C:29:XX:XX:01; fixed-address 192.168.100.21; next-server 192.168.100.10; filename "pxelinux.0"; }配上绑定之后,这台机器无论什么时候重装,拿到的都是同一个IP。这个功能在管理严格的生产机房非常实用。
Kickstart文件里的%packages段只控制了安装阶段能装什么。系统装完了,后续还要装中间件、调配置怎么办?我习惯在%post里直接把内网Yum仓库源配置好,一次性解决后续所有软件安装依赖内网源的问题:
cat > /etc/yum.repos.d/internal.repo <<'EOF' [internal] name=Internal Repository baseurl=http://192.168.100.10/yum/ enabled=1 gpgcheck=0 EOF这样装出来的系统从第一天起就自带可用的软件源,不用浪费人工去一台台配。
最后提一个方向性的建议:如果你管理的机器数量上了规模,纯手工维护PXE加一堆ks文件会开始变得痛苦。这时候可以了解下Cobbler这类PXE包装管理工具,它在底层还是同样的一套PXE和Kickstart逻辑,但把dhcp配置、tftp文件组织、ks模板管理、镜像导入统一成了一体化管理界面。理解了原生PXE的原理之后再去用那些工具,会顺理成章得多。
第一次跑通无人值守装机的时候,看着屏幕上安装进度条自己走完、系统自动重启、然后弹出登录提示符,那种感觉确实很爽。后来每次给一批新机器做初始化,我都觉得当初花在折腾这套环境上的时间是这几年最值得的一笔投入。如果你现在正好有实验环境在手,不要只看不练,拿两台机器反复装几次,把这些坑都趟一遍,比看十篇文档都有用。