半夜被叫起来处理PXE装机失败,应该是每个搞基础设施的人都经历过的噩梦。几十台机器同一时间卡在同一个报错上,屏幕上一片花花绿绿的内核日志,机房电话那头还在催“明天要上线”。Kickstart无人值守安装本来是解放人力的方案,可一旦报错,它会把你的工作量直接乘以机器台数。这篇东西把我这些年处理kickstart报错的经验整理成一份集锦,从网络引导、ks文件解析、安装源、磁盘分区、软件包安装到日志排查,按阶段把高频报错和对应排查手法讲清楚。内容面向整天和装机、批量交付打交道的运维、SRE和基础设施工程师,也适合刚接触PXE+Kickstart的新手用来建立完整的排错思路。
1. Kickstart报错不是随机事件:先懂链路再谈排错
1.1 一条完整的无人值守安装链路
Kickstart无人值守本质上是一条“接力跑”,每一棒都依赖上一棒的结果,任何一个环节出错,表现都可能类似——要么卡住不动,要么反复重启,要么安装到一半直接弹红屏报错。先把链路拉直,排错才有坐标。
第一棒是PXE网络引导。客户端网卡发出DHCP广播,DHCP服务器回包时不仅要给IP地址,还要通过option 66(next-server)告诉客户端TFTP服务器地址,通过option 67(bootfile)告诉它去取哪个引导文件。随后客户端通过TFTP下载pxelinux.0,再读取pxelinux.cfg目录下的配置文件,根据配置加载内核(vmlinuz)和初始内存盘(initrd.img)。
第二棒是内核启动。initrd中的dracut脚本会在安装环境下拉起网络,解析内核append参数里的ks=地址,先把kickstart配置文件拉下来,然后交给anaconda安装器解析执行。注意这里有个容易被忽略的点:安装环境里的网络初始化是独立于最终系统的一次“临时网络”,它的成败只受内核参数影响,和你ks里写的network命令并不完全是同一回事。
第三棒是anaconda按ks文件执行。它会先跑%pre脚本,然后做磁盘分区、挂载安装源、选择软件包组、执行软件包安装,最后执行%post脚本并写入引导程序。每一步都有独立的日志文件,后面会专门讲。
一棒接一棒的这个特性决定了:看到报错后,先定位“是哪一棒断了”,再去查具体原因。比如同样是“卡住不动”,第一棒是PXE引导文件没找到,第二棒是dracut连不上安装源,第三棒是分区脚本写错,症状几乎一样,但排查方向完全不同。
1.2 排错先分层:引导、资源、配置、安装
我在实际排障时习惯把报错分为五个层次,每一层有对应的典型报错形式和主要日志位置。
| 层级 | 典型报错形态 | 主要日志/观测点 | 常规排查手段 |
|---|---|---|---|
| 引导层 | PXE-E32、TFTP timeout、Kernel panic | 客户端屏幕、TFTP服务器日志 | tcpdump抓包、检查DHCP/TFTP配置 |
| 资源层 | dracut-initqueue timeout、挂载失败 | 内核日志、dracut输出 | 检查安装源可达性、IP配置 |
| 配置层 | ks解析报错、Unknown command | anaconda.log | ksvalidator预校验 |
| 安装层 | 分区失败、包安装依赖错误 | storage.log、program.log | 检查ks分区/包段落 |
| 脚本层 | %post返回非零、SELinux上下文错误 | program.log、系统日志 | 脚本加日志输出 |
每次有人拿着报错截图来问我,我第一句永远是三个问题:卡在哪一步了?日志在哪?最近一次改了什么?Kickstart报错里,90%以上都和“最近改动”直接相关——换了镜像版本、改了ks模板、动了DHCP地址池、新到了一批不同网卡型号的机器。先问这三个问题,能帮你砍掉大半无效排查时间。
2. 网络引导阶段的报错:DHCP、TFTP与启动文件
2.1 拿不到地址或引导文件:PXE-E51、PXE-E32与TFTP timeout
PXE阶段最常见的两组报错,一组是拿不到IP,一组是拿到IP但拿不到引导文件。
先看拿不到IP。PXE-E51表示DHCP服务器没有任何响应,常见原因有三个:DHCP服务没启动、地址池耗尽、客户端所在的二层VLAN和DHCP服务器不在同一广播域。排查时别急着上服务器看配置,先在客户端机房那个网段抓包最直接:
# 在DHCP服务器上抓客户端引导报文 tcpdump -i eth0 -n udp port 67 or 68如果什么都抓不到,问题基本在二层或者DHCP服务本身;如果抓到了DISCOVER但没看到OFFER,那要么是地址池满了,要么是DHCP策略里对该网段做了限制。另外有些环境里同时存在多个DHCP服务器,客户端拿到的是老环境的IP,启动文件自然找不到,这类问题ipconfig出来的IP一验证就能发现。
再看拿到IP但报PXE-E32“TFTP open timeout”。这个报错说明DHCP已经正常回包,但客户端连不上TFTP服务器,或者TFTP服务器没有响应。重点检查三个地方:DHCP配置里next-server指向的IP对不对;TFTP服务(监听UDP 69)是否活着;防火墙有没有放行UDP 69端口。很多系统都默认用systemd管理的tftp.socket,服务看着enable,但真正接请求的是socket激活,如果socket没起来,netstat全盲区。
顺带说一个后台排查的小技巧:在TFTP服务器本机上直接用tftp客户端拉一次文件,能立刻区分是服务端问题还是网络问题:
# 本机测试TFTP是否正常 tftp 127.0.0.1 -c get pxelinux.0能在本机get到,再去查防火墙和路由;本机都get不到,就是TFTP服务目录或权限的问题,别在客户端侧浪费时间。
2.2 pxelinux配置加载与内核、initrd缺失
PXE-E32通过之后,下一个高频报错是“PXE-E11: ARP timeout”或者加载阶段提示找不到文件。pxelinux.0下载成功后,会按照“UUID -> MAC地址 -> IP地址十六进制 -> default”的顺序在pxelinux.cfg目录下寻找配置文件。如果你只放了default,而客户端因为某种原因命中了MAC前缀的文件名,就会报“config file not found”。
而“Failed to load ldlinux.cso”这类报错,多半是pxelinux.0和配套的ldlinux.cso版本不匹配,重新整目录覆盖一遍就行。内核或initrd缺失的报错更直观,比如提示找不到vmlinuz或initrd.img,优先检查引导配置里relative路径是否和TFTP根目录下的实际文件一致。很多人喜欢把不同系统镜像塞到同一个TFTP根目录,路径层级一深,漏写一层子目录就会报文件不存在。
内核真正被加载后如果立即panic,出现“VFS: Unable to mount root fs”或者“Kernel panic – not syncing”,常见原因是initrd.img和vmlinuz不配套,或者文件下载不完整——TFTP是UDP协议,大文件在弱网环境下偶尔会缺块,PXE固件一般不会告诉你“文件损坏”。判断方法也简单:把它下载到正常机器上对比文件大小和MD5。我遇到过好几次ISO复制一半就挂载的场景,要么校验和不对,要么initrd末尾被截断,这种“看起来文件在,其实文件坏”的坑最隐蔽。
2.3 与网卡命名、多网卡环境相关的“假网络故障”
安装环境的网络是用内核引导参数来配置的,和最终系统的网络配置文件是两套逻辑。很多人ks里的network配置明明没问题,但安装程序就是连不上安装源,问题往往出在网卡命名上。
现代服务器普遍使用一致网络设备命名(veno这样的命名规则),而你的ks模板里如果写死了eth0,就很可能对不上实际网卡名。处理方法有两个方向:一是在kernel append参数里加net.ifnames=0 biosdevname=0强制使用eth0传统命名;二是ks里用network --device=配合MAC地址或实际接口名来指定。不要盲目禁用新命名规则,在有多网卡、有管理网口的服务器上,用MAC绑定更稳妥。
多网卡环境还有一个隐蔽问题:如果客户端有多块网卡都启用了PXE,固件可能从错误的网卡发起引导。此时即便引导成功,安装程序里看到的活跃网卡也不一定是你希望走管理网络的网卡。排查时在引导参数里临时加ksdevice=eno1指定接口,先用一台机器确认网卡名称,再固化到模板里。这个坑在机房新到的服务器上特别常见,两三个网口迷迷糊糊插错线,报错日志却指向网络不通,很容易让人围着配置绕圈。
3. ks.cfg与安装源阶段的报错
3.1 ks文件找不到、解析失败、编码与换行符的玄学
第二棒里最常见的报错是“Unable to download the kickstart file”或者进安装界面后提示找不到ks。ks=这个参数本身没问题,但安装环境当时还没有完成网络配置,URL自然访问不通。处理方法是把网络配置直接放到内核append参数里,而不是依赖ks文件里的network命令,形成一个“先有网络,再去拉ks”的顺序:
ks=http://192.168.1.10/ks/ks.cfg ip=192.168.1.100::192.168.1.1:255.255.255.0:::eth0这个参数的意思是:静态配置eth0,IP为192.168.1.100,网关192.168.1.1,掩码255.255.255.0。有了它,dracut就能在拉ks之前把网络准备好。
ks文件拉下来之后,下一个高频报错是解析失败。控制台或anaconda日志里会出现“Unknown command”或“Error parsing kickstart file”。我踩过最深的坑有两个:一是在Windows下编辑过ks文件,保存成了带BOM的UTF-8或CRLF换行;旧版anaconda对这两个东西非常敏感,一个隐藏的BOM字符就能让整个文件解析崩掉。二是在ks命令段落之间错误插入%pre或%packages段落,破坏了“命令段必须在前面”的结构。
处理换行符问题用一条命令清理:
# 去掉CRLF换行,保留LF sed -i 's/\r$//' ks.cfg修完之后用pykickstart自带的校验工具做一次静态检查,能拦截掉大部分语法级错误:
ksvalidator /path/to/ks.cfg注意ksvalidator只能查语法,查不出运行期的问题,比如网络不通、仓库路径不存在这类,它管不了。
3.2 url命令与HTTP/NFS安装源的高频故障
安装源这一层的报错,表现最典型的就是dracut阶段反复出现“Warning: dracut-initqueue timeout - starting timeout scripts”,然后卡在那里不动。这个报错的字面意思是安装环境挂载安装源失败。它由两类原因导致:一类是网络本身没起来,另一类是安装源地址不可达或路径错误。
如果是HTTP源,先用curl验证一遍URL能不能正常列出repodata目录:
curl -I http://192.168.1.10/repo/repodata/repomd.xml如果返回404或403,说明路径写错了或者HTTP服务权限不足。很多用Apache搭的镜像站点默认开启了目录索引,但SELinux的httpd上下文没放行,就会出现“能ping通、浏览器能开首页、curl repodata却403”的怪现象。直接用restorecon -Rv /var/www/html重建上下文,或者检查httpd错误日志就能定位。
NFS源也有自己的坑。安装器自带的NFS客户端可能和服务器端NFS版本不匹配,典型症状是挂载命令执行超时。在ks的安装源命令里可以显式指定版本和挂载选项:
url --url="nfs:192.168.1.10:/data/repo,nfsvers=3"另外NFS导出目录必须带ro选项,安装源目录一旦被意外以读写方式挂载还可能引发并发写入冲突,多台机器同时装的时候尤其明显。在NFS服务器上跑showmount -e先确认导出路径和你ks里写的一致,这一步只需要十秒钟,却至少能过滤掉一半的路径类问题。
3.3 仓库数据、镜像版本与架构不匹配
如果安装源路径没问题,但anaconda报“Could not find a valid repo”或者“Metadata file does not match checksum”,那基本是仓库元数据损坏或镜像不同步造成的。镜像站同步一半就断网的事我遇到过不止一次,repodata目录存在但里面的repomd.xml是残缺的,安装器自然不认。
判断方法很朴素:手工访问repodata下的文件,检查文件大小和服务器端原始文件是否一致。更省事的做法是直接用已安装系统里的包管理工具做一次仓库自检,比如yum repolist看能否正常解析。如果仓库本身没问题,就要考虑架构匹配问题——你拉的是x86_64的repodata,但ks里指定安装的是arm64,或者反过来,都会得到很奇怪的报错。
还有一类典型报错涉及GPG校验。ks里如果没有显式声明关闭gpgcheck,安装器会按仓库源默认配置去校验签名,遇到不认识的key会停下来等人确认,这在无人值守环境里就是永久卡死。内网自建仓库直接在repo命令后用--nogpgcheck,或者确认镜像站使用的密钥已经通过system authorization配置分发给所有装机对象。
版本不匹配的问题也常被忽视。安装器用新系统的dracut去挂载旧版本的安装源,或者ks里写了某个软件包组但源里对应的编译产物已经被移除,都会在安装途中报出“失败”而不是“找不到”。保持安装源与ks模板版本同步,属于被无数人验证过的基础守则。
4. 分区与磁盘阶段的报错
4.1 clearpart、part、volgroup 的顺序与执行细节
进入安装层之后,磁盘分区是报错重灾区。它的语法看起来简单,但顺序和细节很讲究。一个标准的LVM布局ks段落长这样:
clearpart --drives=sda --all --initlabel part /boot --fstype=xfs --size=1024 part pv.01 --size=1 --grow volgroup vg00 pv.01 logvol / --fstype=xfs --name=lv_root --vgname=vg00 --size=40960 logvol swap --name=lv_swap --vgname=vg00 --size=4096这条链路里最容易被忽略的是执行顺序。clearpart必须出现在part之前,而volgroup引用的pv必须已经通过part定义出来。很多人喜欢把“冗余代码”从网上模板里往上抄,结果pv.01这个逻辑名和另一个磁盘分区冲突,anaconda会直接报分区方案无效。
我在实际运维里踩过一个很典型的“Failed to wipe partition table: Device or resource busy”。它的原因是目标盘上原有系统启动时占用了分区表,或者机器原本做了Linux软RAID,内存里还有raid设备的引用。解决方式是明确指定目标盘,并在clearpart里用--initlabel重建磁盘标签:
clearpart --drives=sda --all --initlabel如果机器上挂着多块盘,强烈建议加ignoredisk --only-use=sda把安装目标限定到唯一磁盘,否则anaconda在部分固件环境下会自作主张选错盘,装完系统才发现写到了数据盘上,那才叫欲哭无泪。
4.2 LVM与/boot容量引发的连锁报错
LVM段落还有几个常见报错值得单独说。一个是“Not enough free space for LV”,出现这个报错先别怀疑磁盘太小,先检查你的PV是否真的在建LV之前留出了空间。ks的解析顺序是串行的,如果pv.01的size写死为固定大小,而后面的几个logvol加起来超过了它,就会报空间不足。最常用的写法是让PV“吃掉”剩余全部空间:
part pv.01 --size=1 --grow另外注意size单位默认是MiB还是MB,不同发行版有细微差别,我在模板里统一用--size=102400这种以MiB为单位的显式数值,避免单位换算导致分区比预期小一大截。
还有一个特别容易误导新手的场景:BIOS+MBR引导模式下,/boot分区必须落在磁盘前2TB范围且要求足够空间容纳grub文件;UEFI模式下则必须存在独立的EFI系统分区。很多模板是从老机器抄来的,只有/boot没有/boot/efi,放到UEFI机器上装到一半就报“No EFI system partition found”。正确的做法是在ks里同时定义两者:
part /boot --fstype=xfs --size=1024 part /boot/efi --fstype=efi --size=512/boot本身也不能给太小。新版引导程序和内核体积逐年变大,我一般至少给1024MiB,老模板里那个200MB的/boot在新内核上很容易在安装引导程序阶段失败,报错样式还特别隐晦,比如grub2-install执行失败。
4.3 找不到磁盘与驱动缺失
服务器正好是刚采购的新机型,或者虚拟化环境用了半虚拟化磁盘,安装程序就会报“No disks found”或“No valid disks selected”。这个报错的本质是anaconda在安装环境里没有加载到能识别这块磁盘的驱动。
物理机场景先检查磁盘控制器模式。很多服务器默认RAID模式,而RAID卡的驱动不包含在基础内核里;把SATA控制器切成AHCI、或确认RAID卡驱动已经通过驱动盘机制加载,问题就解决大半。如果确实需要额外驱动,用引导参数指定驱动更新包:
ks=http://192.168.1.10/ks/ks.cfg inst.dd=http://192.168.1.10/drivers/driver.rpm虚拟机场景则要检查磁盘类型。用virtio磁盘的虚拟机在标准发行版DVD安装时一般没问题,但如果你用的是精简定制过的引导环境,可能缺少virtio相关内核模块。临时先切到SATA模拟盘完成安装,或者把virtio模块补进initrd,都能化解。判断驱动是否真的没加载,最靠谱的依据是dmesg里有没有对应的磁盘设备,而不是看安装界面。
5. 软件包与脚本阶段的报错
5.1 %packages组名与依赖冲突
进入软件包安装阶段后,最常见的报错是ks里声明的软件包组不存在。很多老模板还在用@core这种组名,新版本发行版的comps里组名已经调整了,anaconda对不存在的组是警告还是报错取决于版本,有些版本直接忽略,装出来的系统缺一堆基础组件,直到上线才发现。所以模板在批量使用之前,一定要先确认组名在当前镜像的comps文件里真实存在,或者用环境组来定义基础环境:
%packages @^minimal-environment @standard tmux net-tools %end环境组前面的@^不是笔误,那个插入符就代表“environment”,用它替代一组零散的基础包,少了扯皮,多家发行版都认。
依赖冲突类的报错,比如“Package xx requires yy”,多半是你在%packages里同时塞了两个互相打架的包,或者源里某包被更新后和现有包组产生冲突。这类问题在program.log里能找到具体是哪个包失败,根据报错在模板里删掉冲突项即可。真正难搞的是那些“装完才发现缺依赖”的情况,安装器不报错但系统功能不完整,这类问题必须在灰度验证阶段用功能测试兜住。
5.2 %post脚本失败与SELinux上下文问题
%post脚本的报错有个特点:默认情况下它不会让安装失败,只在日志里记录返回码。这样一来,装完的机器看起来是成功的,但脚本里该做的配置全没生效,属于“软失败”。排查时先确认你的ks段落里有没有写--erroronfail:
%post --log=/root/post-install.log #!/bin/bash # ... 你的初始化逻辑 %end用--log=把脚本输出重定向到文件,装完后直接读这个文件定位哪一步失败,比对着黑屏猜效率高得多。还要分清楚脚本执行环境:默认%post在chroot环境里执行,命令是基于新系统的;如果你用了--nochroot,脚本看到的是安装环境,路径就变成/mnt/sysimage/root/...,写错路径是脚本最常见的自杀方式。
SELinux的坑通常不是报在%post阶段,而是报在第一次启动之后。比如你通过%post往/etc里写入了需要特定上下文的配置文件,系统强制SELinux模式下这些文件的上下文是错的,服务就会拒绝启动。报错样式五花八门,最常见的是“Failed to restart service”或者应用不断退出。处理办法分成两步:第一,模板里SELinux的配置应在安装早期就敲定,比如selinux --enforcing;第二,在%post末尾安排一次上下文重建:
# 强制重建SELinux上下文并在完成后自动重新标记 restorecon -Rv /etc 2>/dev/null || true touch /.autorelabel第一条在当前系统里重建主要目录上下文,第二条触发下次开机自动relabel,两层保险下来,SELinux导致的首次启动异常基本能杜绝。
5.3 bootloader与固件模式不匹配
系统文件拷完、脚本跑完,最后一步是装引导程序,报错一般不会让你等太久。最经典的是“Unable to install bootloader”或者装完重启后提示“No bootable device”。前者多发生在UEFI机器上的模板仍用bootloader --location=mbr,后者多发生在BIOS机器上却意外写了UEFI分区。
判断固件模式最直接的办法是看引导阶段屏幕显示:显示Boot Manager是UEFI,显示PXE/网卡启动列表的通常是BIOS模式。看不出就去看安装时的parted输出,磁盘上的分区表类型是gpt还是msdos也能侧面佐证。ks里bootloader指令用--location=mbr还是默认值,要跟固件实际模式对齐。
还有一个容易忽略的EFI引导管理器问题:安装器虽然写入成功,但服务器的EFI启动项在某种环境下没被正确更新,重启后固件直接略过新系统。症状就是明明装好了却找不到引导项。这类问题可以通过在%post里显式调用efibootmgr修复,或者检查固件里启动优先级,但我个人更推荐在模板里把引导日志打开,安装失败时能直接看到efibootmgr执行到哪一步出了问题。
6. 日志与现场取证技巧
6.1 anaconda日志文件应该怎么看
排错过程中最吃亏的做法是盯着屏幕猜,最有效的做法是直接翻日志。安装环境的日志集中在/var/log/anaconda/目录下,几个文件各管一段:
| 日志文件 | 记录内容 | 排障用途 |
|---|---|---|
| anaconda.log | 安装器主流程 | 定位卡在哪个阶段 |
| storage.log | 磁盘与分区操作 | 分区失败看这个 |
| program.log | 外部命令及输出 | 包安装、脚本执行细节 |
| syslog | 系统级日志 | 网络与内核信息 |
| X.log | GUI显示相关 | 图形界面卡死时看 |
如果机器还在安装过程中,这些日志其实在安装环境的/tmp里,你没法直接登录进磁盘系统看。解决办法是给引导参数加inst.sshd,让安装环境启动SSH服务,然后从管理机连上去翻/tmp下的日志。这个参数在批量调试时是神技,不用对着串口一屏一屏翻,直接把日志文件scp回来分析。
装完却失败的机器,重启后日志在/root/anaconda-ks.cfg和/var/log/anaconda下仍然存在,但有一类安装器内部报错(traceback)未必会写进这些常规日志,它会在屏幕上弹出一个“Bug report”式的对话框,真正详细的堆栈在/root的traceback目录里。看到这类报错先别急着重启机器,把整个traceback目录打包保留下来再说,重启就永久丢失现场。
6.2 串口、控制台脚本与远程取证的组合拳
无人值守装机的最大难点是,故障机可能在没接显示器没接键盘的角落里,你只能靠带外管理通道看它。最惯用的手法是给引导参数加上串口控制台输出:
ks=http://192.168.1.10/ks/ks.cfg inst.text console=ttyS0,115200n8然后通过带外管理工具的虚拟串口(IPMI SOL之类)连上去。有了这条参数,你就能在本地窗口完整看到安装全过程,包括日志滚动和报错堆栈,远程排错效率提升不止一个档次。
“inst.text”是大杀器。默认的图形安装界面在部分显卡驱动缺失时黑屏无输出,加上它直接回退到文本模式,报错信息全打印到控制台。调试阶段我还建议把内核参数里的rhgb quiet全去掉,这两个参数会吞掉大量屏幕日志,让故障现场看起来干干净净但其实什么线索都没留下。
如果条件允许,图形界面排错还能用VNC方式远程观察,但那是实时的,事后取证能力远不如串口日志。我的习惯是模板里默认保留串口输出参数,只有性能测试或安全合规明确要求时才去掉。
6.3 前置止损:用低成本手段避免大规模翻车
批量安装最忌讳的是拿生产环境直接试错。一套合理的交付流程应当是:先在本地虚拟机用同一份ks跑通了,再放到一台带外管理可靠的物理机上验证,最后才进入批量阶段。虚拟机验证省时间,物理机验证覆盖真实固件与驱动,二者不可互相替代。
ksvalidator这种静态校验只是第一道门槛,它连“URL里路径是否存在”都管不了,更别说分区表在各种固件上的行为差异。真正有意义的验证是看完安装后的系统:启动是否正常、网络是否按预期配置、关键服务是否在跑、SELinux是否没有把应用拦下来。把这些做成一个自动化的冒烟检查脚本,让它成为批量安装流程的一部分。
还有一条经验:DHCP作用域最好单独划分一个PXE测试网段。很多无人值守装机的批量事故,源头是有人改了DHCP配置导致整个机房的机器意外进入PXE装机流程,一夜之间业务系统全被清空重装。测试网段和正式网段分开,是花小钱防大灾的习惯。
7. 高频报错速查表(个人笔记版)
把这些年实际处理过的报错整理成了一张速查表,扔在你自己的运维手册里,遇到问题先查表,能省不少时间。
| 表面报错 | 大概率原因 | 排查动作 | 有效处理 |
|---|---|---|---|
| PXE-E51: No DHCP offers | DHCP作用域/VLAN不通或服务异常 | 抓包看DHCP报文 | 检查DHCP配置与地址池 |
| PXE-E32: TFTP open timeout | TFTP服务异常或防火墙拦截 | 本机tftp get测试 | 放行UDP 69/重启tftp.socket |
| File Not Found(加载阶段) | pxelinux.cfg或内核路径错误 | 检查引导配置与实际路径 | 修正路径、确认文件完整 |
| dracut-initqueue timeout | 网络没起或安装源不可达 | 观察dracut输出、curl验证源URL | 引导参数加静态IP、检查HTTP/NFS |
| Unknown command(ks解析) | 换行符错乱/命令拼写错 | ksvalidator校验 | 清理CRLF、修正命令 |
| Could not find a valid repo | 仓库路径错误或repodata缺失 | curl检查repodata | 修复镜像站同步/修正路径 |
| No disks found | 存储驱动缺失或控制器模式不对 | 看dmesg磁盘设备 | 切AHCI/加inst.dd驱动 |
| Not enough free space for LV | PV大小不足或单位错误 | 核对分区段落数值 | PV用--grow、修正size |
| Package xx requires yy | 包组冲突或源版本不一致 | 查program.log | 删冲突包、同步源版本 |
| %post返回非零 | 脚本执行环境或路径错误 | 查看--log输出 | 区分chroot路径、修脚本 |
| Unable to install bootloader | BIOS/UEFI模式与模板不匹配 | 查看分区表类型与固件 | 对齐bootloader指令和分区方案 |
| Failed to set SELinux context | 文件上下文未重建 | 开机日志查拒绝项 | restorecon/autorelabel兜底 |
这张表解决的是“看到报错能不能马上反应到原因”,但每一条背后都有上面章节里讲的细节,不要只背结论不修根因。
8. 最后分享几点排错习惯
文章最后不做什么总结,就说几个我用这些年踩坑换来的个人习惯。第一,故障机器不急着重装。每次都先稳定复现、截图、打包日志,再考虑重启,这个习惯帮我保住了不少“唯一一次现场”。第二,模板一定要纳入版本管理,ks文件每一次改动都要有记录可查,不然“上次还能装,这次怎么就不行”会永远纠缠你。第三,新机型到货第一件事不是跑业务,而是拿最小化的ks验证引导、驱动和分区方案,先把底探明白再谈批量。
还有一个小技巧值得分享:在交付流程里放一个“冒烟检查”步骤,用装完的机器自动跑一遍网络、密码策略、磁盘布局、关键服务自检,结果写回管理平台。它不能直接解决kickstart报错,但能让那些“安装成功但系统有问题”的隐形错误全部现形。无人值守装机做到最后,比的不是谁命令敲得熟,而是谁能让整套流程在无人盯守的情况下稳定交付,少一点半夜电话,多一点安心睡觉。