机房里刚到了一批新机器,四十二台裸机堆在机架上,网线一根没接,硬盘全空。上一次遇到这种场面,我是一台一台插 U 盘、点下一步、选时区、划分区,折腾了整整两天,中间还因为手抖把两台机器的分区格式选错,返工重来。所以这次我决定不再干这种体力活,直接把 Cobbler 拉出来用。Cobbler 是一套裸机批量装机服务,它把 DHCP、TFTP、HTTP、DNS、Kickstart 这些原本要手工拼接的环节打包成一套对象化的管理接口,让你用几条命令就能定义"哪台机器装哪个系统、用什么分区、装完执行什么脚本"。它适合手上管着几十上百台物理机、需要反复重装、又不想每次动手的运维同学,也适合实验室、教学机房、私有云底座这类需要快速交付大量同构机器的场景。这篇东西我把从装包到第一次成功 PXE 引导的全过程拆开讲,包括我踩过的坑和最后沉淀下来的配置模板。
1. 批量装机的老麻烦:Cobbler 能替你扛下什么
1.1 从四十二台裸机说起
先把场景摆清楚。手上这批机器配置完全一致:双路 CPU、256G 内存、两块 960G 的企业级 SSD 做系统盘、十二块 4T 机械盘做数据盘,网卡是双口万兆。需求也很统一:全部装同一个内核版本的 Linux,系统盘做 RAID1,数据盘做 RAID5,装完自动配置内网软件源、注入监控 Agent、写好主机名和 IP。这种"完全同构"的批量需求,恰恰是 Cobbler 最舒服的地带。
如果用传统方式做,流程是这样的:插 U 盘,进 BIOS 改启动顺序,进安装界面手动选语言时区键盘,手动划分区,手动选软件包,手动设网络,等半小时装完,再登进去跑一堆配置脚本。四十二台机器,就算每台只花四十分钟,也是二十八个小时,而且人不可能全程不出错。Cobbler 把前面这些步骤全部固化成模板,机器只要通电、网线插好、BIOS 里把网络启动打开,剩下的事情它自己跑完,你只需要回去喝杯咖啡,回来批量验收。
这里有个关键认知:Cobbler 本身不"装系统",它是个调度中枢和配置生成器。真正干活的还是 PXE 引导加 Kickstart 应答文件这套底层机制,Cobbler 的价值在于把散落各处的配置文件统一成数据库里的对象,你改一个 profile,背后几十个配置文件和目录会被自动重新生成。理解了这一层,后面遇到问题你就知道该往哪个方向查。
1.2 Cobbler 与其他方案的横向比较
装机这件事方案不少,我在不同项目里都用过,这里做个实在的对比,方便你判断自己该不该上 Cobbler。
| 方案 | 上手难度 | 适合规模 | 主要短板 |
|---|---|---|---|
| 手工 U 盘 | 极低 | 1 到 5 台 | 完全不可重复,出错率高 |
| 手搓 PXE 加 Kickstart | 中等偏高 | 10 到 50 台 | 配置文件散落,改一处要动三四个文件 |
| Cobbler | 中等 | 30 到上千台 | 概念多,初期调试链路长 |
| Ansible 加 PXE | 中等 | 50 台以上 | Ansible 只管装完之后的配置,管不了引导 |
| MAAS | 中等偏高 | 100 台以上 | 依赖组件重,适合大规模标准化集群 |
我自己的判断标准很简单:如果你一年之内重装机器的次数超过二十次,或者单次重装数量超过十台,Cobbler 的投入产出比就划算了。它的学习成本主要集中在前期把 PXE 链路打通那一两天,一旦跑通,后面每加一台机器就是一条cobbler system add命令的事。
另一个容易被忽略的点是 Cobbler 的可审计性。所有装机配置都存在/var/lib/cobbler/config/下的 JSON 文件里,谁改了哪个 profile、什么时候改的,翻文件时间戳就能看出来。相比之下手搓 PXE 的时候,有人偷偷改了一下pxelinux.cfg/default,排查半天都找不到人。这个特性在多人协作的运维团队里价值很高。
1.3 我的实验环境规划
讲实操之前,先把我的环境交代清楚,你照着复现的时候可以等比缩放。
服务端我用的是一台旧的一路服务器,Linux 发行版是 Rocky Linux 9,IP 规划为192.168.60.10,这张网卡兼做 Cobbler 服务、DHCP 服务和 TFTP 服务。为什么要把这几个角色放在一台机器上?因为在隔离的装机网段里,一台机器就能扛住 DHCP 和 TFTP 的并发,机器数量上了三百台再考虑拆分。客户端机器统统接在一台二层交换机上,交换机上联到服务端这块网卡,整个网段用192.168.60.0/24。
DHCP 地址池我规划成192.168.60.100到192.168.60.200,正好一百零一个地址,够用。为什么预留这么多?因为 PXE 引导过程中,机器会先用临时地址引导,装完之后按 Kickstart 里写死的静态 IP 重新配置网络,所以地址池只需要覆盖"同时开机但还没装完"的机器数量,不需要覆盖总数。我这批四十二台机器分批开机,每批十台,池子留一百个绰绰有余。
网关和 DNS 我统一指向192.168.60.1,这是一台单独的路由设备。时间同步指向内网的 NTP 服务器,因为装机过程中签名校验和日志时间戳都依赖准确的系统时间。域名后缀我用了lab.local,纯粹是内部使用,不涉及任何外部解析。
先把这些参数记在一张纸上,后面填配置的时候你会反复用到。
2. 安装前的功课:系统、网络与依赖梳理
2.1 服务端系统选型与硬件底线
Cobbler 服务端对系统版本比较挑,官方支持的主流是 RHEL 系 8/9 和 Debian 系 11/12。我选 Rocky Linux 9 的原因很实在:Cobbler 在 RHEL 系上的打包最完整,dnf源里直接就有,签名和目录布局都经过大量验证。Debian 系也能装,但部分依赖包的版本需要手动对齐,早期版本还有 Python 版本冲突的坑,新手不建议从那边起步。
硬件底线其实很低。Cobbler 自己几乎不吃 CPU 和内存,真正占资源的是它托管的安装镜像和软件包仓库。我给它留了 4 核 CPU、8G 内存、200G 系统盘,另外挂了一块 2T 的独立盘专门放镜像和仓库。为什么要把镜像单独放一块盘?因为导入一个完整的发行版 ISO 展开后大概 8 到 12G,如果你还要托管多个发行版加多个软件仓库,系统盘很容易被撑爆,/var/www/cobbler一满,整个服务就写不进去了。
网络方面有一张千兆以上的网卡是必须的。为什么强调带宽?装机的数据流全是服务端往外发,一个 8G 的镜像被十台机器同时拉取就是 80G 的流量,千兆网卡跑到 100MB/s 出头,十台机器同时跑就得排队,装一台的时间会被拉长到让人怀疑人生。如果有条件上万兆,体验会舒服很多,尤其是导入镜像和同步仓库的时候。
2.2 网络规划:DHCP 段、TFTP 与 HTTP 三件事
Cobbler 的 PXE 链路本质上是三个协议各管一段:TFTP 负责把引导程序送到客户端,DHCP 负责告诉客户端"去哪儿找引导程序",HTTP 负责在系统真正开始安装后把内核、initrd 和 Kickstart 文件递过去。任何一环断了,机器就卡在黑屏或者 "No boot filename received" 这类提示上。
这里有个非常容易踩的坑:你的装机网段里绝对不能有第二个 DHCP 服务在跑。我见过最典型的情况是机房上联的路由器自带 DHCP,客户端一开机会同时收到两个 OFFER,谁的响应先到就听谁的,结果就是十台机器里随机有三四台拿不到正确的引导信息。部署前一定要确认装机网段是隔离的二层环境,或者把上游设备的 DHCP 关掉。
TFTP 的配置也有讲究。默认的块大小是 512 字节,传输一个 50M 的内核镜像会慢得让人抓狂。可以在 DHCP 的选项里加上option tftp-server-name和调整 TFTP 的块大小参数来加速,但要注意不是所有网卡的 PXE 固件都支持大块传输,老网卡可能会因为协议不兼容直接失败。我的做法是先按默认参数跑通链路,确认能装了再逐步调优,不要一开始就把参数拉到极限。
HTTP 这段相对简单,Cobbler 自己会启动一个基于 Apache 或者它自带 Web 服务的 HTTP 端点,默认监听 80 端口。需要注意的是这个 80 端口同时承担了 Web 管理界面和安装文件分发的职责,如果你在同一台机器上还跑了别的 Web 服务,端口冲突就来了,趁早改掉或者干脆别装。
2.3 防火墙端口、SELinux 与时间同步
端口这一块我列一张表,照着开就行,别偷懒直接关防火墙,后期要过安全审计的时候你会后悔。
| 协议 | 端口 | 用途 |
|---|---|---|
| UDP | 67、68 | DHCP 服务端与客户端 |
| UDP | 69 | TFTP 引导文件传输 |
| TCP | 80 | HTTP 安装源与 Kickstart 分发 |
| TCP | 443 | Web 管理界面 HTTPS |
| TCP | 25151 | Cobbler 自身的 API 通信 |
Rocky Linux 9 上开端口用firewall-cmd,开完之后一定要加--permanent再--reload,只跑一次不写永久规则的话,重启就全没了,我为此白排查过一次。SELinux 这块建议先设成 permissive 模式跑通,而不是直接关掉。原因是装完之后你还要在 enforcing 模式下长期运行,如果一开始就 disabled,后面切回来会冒出一堆权限问题,不如一开始就用 permissive,把audit.log里的拒绝记录当成排查线索。
时间同步这个细节经常被忽略。Cobbler 生成配置、签名校验、日志时间戳都依赖系统时间,如果服务端时间和客户端差了超过一定范围,Kickstart 里的某些校验环节会直接失败。我的做法是在服务端配好 chrony 指向内网 NTP,然后在 Kickstart 模板里也带上时间同步配置,让客户端装完自动对齐。
2.4 依赖安装
依赖这块我把 Rocky 9 上的完整命令贴出来,你可以直接抄。
dnf install -y epel-release dnf install -y cobbler cobbler-web dhcp-server tftp-server xinetd pykickstart dnf install -y httpd rsync bind bind-utils syslinux syslinux-tftpboot systemctl enable --now cobblerd httpd tftp这里解释几个容易困惑的地方。cobbler-web是 Web 管理界面,可选装,但装上有好处,排查配置的时候图形界面能一眼看到对象关系。pykickstart是 Kickstart 语法校验工具,装它是因为 Cobbler 在生成应答文件时会调用它做校验,缺了会报错。syslinux和syslinux-tftpboot提供 PXE 引导文件,这两个包在不同版本的仓库里名字可能略有差异,找不到的时候用dnf provides */pxelinux.0反查一下。
装完之后先别急着改配置,跑一下systemctl status cobblerd看服务起没起来。这时候它多半会报一些配置缺失的警告,属于正常现象,因为我们还没填基础参数。记住这个顺序:先装包,再看服务状态,再改配置,再看状态。瞎改配置之前不知道服务本身有没有问题,会让排查变得很混乱。
3. Cobbler 服务端安装与初始化调教
3.1 三种安装方式与版本选择
Cobbler 的安装方式主要有三种,我把它们的适用场景说清楚。
第一种是发行版官方仓库直接装,也就是上面那条dnf install cobbler。这种最省事,版本通常是 3.3 或 3.4,配置文件格式已经是 YAML 了,跟官方文档基本对得上。新手强烈建议走这条路,不要一上来就折腾源码编译。
第二种是 EPEL 仓库装,版本可能比官方仓库新或者旧,取决于你的发行版。好处是更新及时,坏处是依赖版本有时候会和系统自带的冲突。如果你的发行版官方仓库里已经有 cobbler,就没必要绕这一圈。
第三种是从源码或者项目提供的仓库装,能拿到最新的特性,比如对某些新发行版的签名支持、改进的 Web 界面。代价是升级要靠自己维护,出问题的时候没有包管理器的依赖保护。
我自己的选择是官方仓库版本。原因很简单,这套东西是要长期无人值守跑在机房里的,比起新特性,我更在意依赖关系的确定性。装机服务一旦挂了,新机器就全部交付不了,这个风险不值得为了某个新功能去冒。版本确认用cobbler --version,顺便记下来,后面查文档的时候要对得上版本号。
3.2 关键配置项逐条拆解
Cobbler 3.x 的主配置文件是/etc/cobbler/settings.yaml,这个文件是 YAML 格式,缩进敏感,改之前先备份一份。下面这几个参数是必改的,我逐条说为什么。
server: 192.168.60.10 next_server: 192.168.60.10 manage_dhcp: 1 manage_tftp: 1 manage_dns: 0 pxe_just_once: 1 default_password_crypted: "$1$随机盐$加密后的密码串" allow_duplicate_macs: falseserver是客户端在安装阶段访问 HTTP 源时用的地址,填服务端 IP。next_server是 DHCP 告诉客户端的 TFTP 服务器地址,通常和 server 相同,但在多网卡或者有 NAT 的环境里可能不一样,这里必须填客户端能直接访问到的那个地址,填错了客户端就会一直卡在获取引导文件。manage_dhcp设成 1 表示让 Cobbler 接管 DHCP 配置的生成,它会根据模板渲染出 dhcpd.conf,这个开关打开后你就不要手动改/etc/dhcp/dhcpd.conf了,改了也会被覆盖。
pxe_just_once这个参数值得单独讲。设成 1 之后,客户端完成一次安装会自动把 PXE 引导标记取消,避免机器装完后重启又进引导循环。我第一年用 Cobbler 的时候没开这个开关,结果有一台机器装完重启三次又回到安装界面,运维小哥以为镜像坏了,查了一下午。这个参数在 3.x 里默认值可能不同,务必显式写上。
default_password_crypted是默认 root 密码的加密串,生成方式如下:
openssl passwd -1 -salt "$(openssl rand -base64 6)" 'YourPassword'把输出原样填进配置。为什么要用加密串而不是明文?因为 Kickstart 文件最终是通过 HTTP 明文传输的,如果里面写明文密码,同网段抓包就能拿到,这在安全审计里是硬伤。
3.3 cobbler check 的每一条告警怎么消
配置改完跑cobbler check,你会看到一串告警,这是 Cobbler 最贴心的设计,它把常见问题都替你检查了。我把最常出现的几条列出来,讲清楚每条背后的原因。
| 告警内容 | 原因 | 处理方式 |
|---|---|---|
| server and next_server 字段未配置 | 默认值还是 localhost | 改成服务端实际 IP |
| default_password_crypted 未设置 | 默认密码是占位符 | 用 openssl 生成后填入 |
| 缺少引导加载程序文件 | tftpboot 目录下没有 pxelinux.0 | 跑cobbler mkloaders或从 syslinux 目录复制 |
| dhcpd 未安装或未启动 | manage_dhcp 打开但服务没跑 | 安装 dhcp-server 并 enable |
| 需要 rsync 支持 | 某些发行版导入依赖 rsync | 安装 rsync 包 |
| SELinux 可能阻止访问 | permissive 之外的策略 | 先切 permissive 观察 |
新版 Cobbler 获取引导文件的方式变了,早期版本用cobbler get-loaders从一个固定的在线源拉取,新版改成了cobbler mkloaders,直接从本地已安装的 syslinux 包里生成。如果你的环境不能访问外网,get-loaders会直接卡住然后超时,这是很多人第一次装就卡住的根本原因。用mkloaders就不依赖网络,我强烈推荐这条路径。
cobbler check每修一条就重跑一次,直到只剩一两条无害的提示为止。这里的心态要摆正:不要追求零告警,有些告警是针对你没用到的功能(比如 DNS 管理)发出的,只要你不用那个功能,忽略它完全没问题。
3.4 cobbler sync 干了什么
cobbler check是自检,cobbler sync是真正把配置落到磁盘上并重启相关服务。这个命令值得单独讲清楚,因为不理解它的行为,你会经常遇到"我明明改了配置怎么不生效"的问题。
执行cobbler sync的时候,它会做这几件事:根据模板渲染出 dhcpd.conf 并放到/etc/dhcp/,然后重启 dhcpd;把引导文件、内核、initrd 同步到/var/lib/tftpboot/下对应的目录;生成pxelinux.cfg/default引导菜单;如果有 DNS 管理还会生成 named 的 zone 文件;最后把 HTTP 服务下的安装树索引刷新一遍。整个过程是幂等的,重复执行不会出问题,所以你可以放心地改一次配置 sync 一次。
理解它的工作原理对排查特别重要。比如有次我改了 Kickstart 模板但装机还是老样子,原因就是没 sync,客户端拉到的是旧的 HTTP 路径缓存。还有次 DHCP 不生效,是因为 dhcpd 重启失败了,cobbler sync的输出里其实有报错,但我没仔细看。所以养成习惯:每次 sync 之后,把它的输出从头到尾看一遍,有红色报错就立刻处理,别攒着。
4. 发行版导入与 Profile 定制:把装机变成选择题
4.1 distro、profile、system 三层对象模型
Cobbler 最核心的设计就是这三个对象,理解它们的关系是后面所有操作的基础。
distro是发行版,对应一份内核加 initrd 加安装树的组合,代表"一套可以安装的系统"。profile是配置档,它建立在某个 distro 之上,附加了 Kickstart 文件、软件源、内核参数,代表"一种安装方式"。system是具体机器,它绑定某个 profile,再叠加自己的 MAC、IP、主机名,代表"这一台特定的机器"。
用生活化的比方:distro 是菜谱里的"食材清单",profile 是"这道菜怎么做",system 是"今天中午给我做一份"。一台机器引导时,DHCP 根据 MAC 找到对应的 system,system 指向 profile,profile 指向 distro,链路就串起来了。如果 MAC 没匹配到 system,Cobbler 会退回到默认 profile,这是很多"配置了 system 但没生效"问题的根源。
这三个对象都是可以继承和覆盖的。比如你可以在 profile 里定义一组内核参数,在具体 system 上再加一条inst.vnc开启远程安装,覆盖行为是叠加而不是替换。搞懂这个继承关系,你就能用很少的模板覆盖很多差异化需求。
4.2 import 导入 ISO 的完整过程
导入发行版就是把 ISO 或者安装树塞进 Cobbler,让它认识这个发行版。我以导入一个通用 Linux 发行版为例,把完整流程走一遍。
先把 ISO 挂载到本地目录:
mkdir -p /mnt/iso mount -o loop,ro /data/iso/linux-server-dvd.iso /mnt/iso然后执行导入:
cobbler import --path=/mnt/iso --name=linux-server-9 --arch=x86_64这里有个参数计算和选择的细节。--name我建议带上版本号和架构,因为后面你可能会导入多个版本,名字里不带版本,几个月后自己都分不清哪个是哪个。导入过程会复制大约 8 到 12G 的数据,机器慢的话要等几分钟,期间不要中断,中断了会留下半截目录,得手动清理/var/www/cobbler/distro_mirror/。
导入完成后用cobbler distro list和cobbler profile list确认。正常情况下,一次 import 会自动生成一个 distro 和一个同名的 profile,profile 用的是默认的 Kickstart 模板。这时候你已经可以直接用这个默认 profile 装机了,只不过用的是通用配置,分区和软件包都不是你想要的。
导入过程中容易卡住的一个点是签名匹配。Cobbler 会根据安装树里的文件特征判断这是什么发行版,判断不出来就报"unknown distribution"。遇到这种情况先跑cobbler signature update更新特征库,如果还是不行,可能就是你的发行版太新或者太偏,需要手动指定--breed参数告诉它这是哪一类。
4.3 Kickstart 模板改造
默认模板只能保证"装得上去",离"装得符合要求"还差得远。我的做法是复制一份默认模板出来改。
cp /var/lib/cobbler/kickstarts/sample_end.ks /var/lib/cobbler/kickstarts/lab-server.ks然后编辑这个文件,重点改这几块。
分区方案我用的是固定写法,因为所有机器硬件一致,没必要用自动分区。系统盘做 RAID1 的写法大致是把两块 SSD 分别指定为 RAID 成员,然后定义根分区和 boot 分区落在 RAID1 设备上。数据盘做 RAID5 需要至少三块盘,十二块盘可以做成一个 RAID5 加一个热备。这里要注意 RAID 的元数据版本和 chunk 大小,机械盘做 RAID5 我用 512K 的 chunk,SSD 做 RAID1 用默认值就可以,具体参数要结合你的阵列卡或者软件 RAID 的实际能力来定。
网络配置我全部写死静态地址,因为装机的机器 IP 是规划好的。模板里用变量占位:
network --bootproto=static --ip=$ip_address --netmask=255.255.255.0 --gateway=192.168.60.1 --hostname=$hostname --nameserver=192.168.60.1这些变量会从 system 对象里取值,这就是为什么前面强调要把 system 对象的信息填全。如果 system 里没填 IP,这里就会渲染成空值,装完网络直接不通。
%post段是最能体现功夫的地方。我把内网软件源配置、监控 Agent 安装、SSH 密钥注入、基础安全加固脚本全塞在这里。写法上要把脚本内容先拉下来再执行,而不是直接把一大段脚本写在 Kickstart 里,因为 Kickstart 的语法校验对特殊字符比较敏感,写在文件里更容易维护。
4.4 repo 与 snippet 的复用
当你有多个 profile 的时候,重复的配置片段就该抽出来。Cobbler 提供了 snippet 机制,可以把一段 Kickstart 片段单独存成文件,在多个模板里用$SNIPPET('名字')引用。
我把"配置内网软件源"和"安装基础工具包"这两段抽成了 snippet。好处是多台机器、多个发行版的模板可以共用,改一处全部生效。当你的内网源地址变了,只需要改一个 snippet 文件,不用挨个模板去搜替换,这个维护成本的差别在环境多了之后非常明显。
repo 对象则是用来托管软件仓库的。比如你有一个内网的包仓库,可以cobbler repo add把它注册进来,然后在 profile 里引用。这样客户端安装过程中就能直接从内网拉包,速度和可控性都比走外部源好得多。注意 repo 的镜像同步会用 rsync,第一次同步数据量大的时候要留足磁盘和时间。
5. 全流程实战:从按下 PXE 到远程登录
5.1 DHCP 接管与 PXE 引导链路
配置 DHCP 模板是打通链路的关键一步。Cobbler 的 DHCP 模板在/etc/cobbler/dhcp.template,你需要根据实际网段改这几处:
subnet 192.168.60.0 netmask 255.255.255.0 { option routers 192.168.60.1; option domain-name-servers 192.168.60.1; option subnet-mask 255.255.255.0; range dynamic-bootp 192.168.60.100 192.168.60.200; filename "pxelinux.0"; next-server $next_server; }这里最容易出错的是$next_server这个变量。它是 Cobbler 在渲染模板时替换的,值来自settings.yaml里的next_server。如果你在模板里直接写死了 IP 而没有用变量,那就绕过了 Cobbler 的管理,两者不一致的时候会很难查。我的建议是模板里一律用变量,把实际值统一放在 settings 里维护。
filename这一行指定客户端加载哪个引导程序。传统 BIOS 机器用pxelinux.0,UEFI 机器要用grubx64.efi或者shimx64.efi。如果你的机器混着新旧两种固件,就必须在 DHCP 里做条件判断,按客户端的架构声明返回不同的 filename。我这次的机器全是 UEFI,所以直接配 UEFI 的路径,如果你的环境混合,这块要额外处理,否则老机器会引导失败。
改完模板跑cobbler sync,然后确认 dhcpd 起来了。用ss -ulnp | grep 67看端口有没有监听,用journalctl -u dhcpd -f跟踪日志。客户端开机进网络引导之后,日志里会出现 DISCOVER、OFFER、REQUEST、ACK 四个阶段的记录,看到 ACK 说明地址分配成功,接下来就是 TFTP 拉引导文件了。
5.2 添加 system 对象与 MAC 绑定
机器第一次开机的时候,我还不知道它的 MAC 地址,这时候有两个做法。一是先在交换机或者服务器的 DHCP 日志里看客户端请求的 MAC,二是直接让机器用默认 profile 装,装完再登记。我倾向前者,因为绑定 MAC 之后能精确控制每台机器的 IP 和主机名,装完直接就能用。
拿到 MAC 之后,添加 system 对象的命令长这样:
cobbler system add --name=node01 \ --profile=linux-server-9-x86_64 \ --mac=00:11:22:33:44:55 \ --ip-address=192.168.60.101 \ --hostname=node01.lab.local \ --static=1 \ --netmask=255.255.255.0 \ --gateway=192.168.60.1 \ --dns-name=node01.lab.local这里每一个参数都有讲究。--static=1告诉 Cobbler 这台机器用静态地址,Kickstart 渲染的时候会走静态那段逻辑。--dns-name是给系统内部记录用的,如果开了 DNS 管理,它会自动生成正向解析记录。--mac的格式必须是冒号分隔的小写十六进制,大写或者横杠分隔在某些版本上匹配不上,我因为这个小写问题排查过一次。
批量添加的时候不要手敲四十二条命令,用脚本生成再执行。我一般是从一份 CSV 表格里读 MAC 和 IP 规划,用 shell 循环拼出命令。这里提醒一句,cobbler system add之后必须cobbler sync才生效,批量添加完最后统一 sync 一次就行,不用每加一台 sync 一次。
5.3 验证、抓包与日志定位
链路跑通之后,验证是有方法的,不要靠猜。我在客户端开机之后,会在服务端同时开三个窗口:一个tail -f /var/log/messages看 DHCP 相关日志,一个tail -f /var/log/cobbler/cobbler.log看 Cobbler 自身的处理记录,一个tcpdump -i 网卡 -n port 69看 TFTP 有没有实际传输。
这三个窗口的组合能快速定位问题出在哪一段。如果 DHCP 日志里连 DISCOVER 都没有,说明客户端的网络启动没开或者网线有问题。如果有 DISCOVER 但没有 ACK,说明地址池空了或者配置有误。如果 DHCP 走完了但 TFTP 没有流量,说明 filename 或者 next_server 配错了。如果 TFTP 有流量但客户端报错,多半是引导文件本身不对,比如 BIOS 机器拿到了 UEFI 的文件。
装完之后,Cobbler 的日志还会记录这台机器什么时候开始装、用的哪个 profile。翻/var/log/cobbler/下的日志是排查"这台机器为什么和别人装得不一样"的第一手材料。养成把日志路径记在脑子里的习惯,比到处问人快得多。
5.4 koan 重装与批量下发
机器已经装好系统在后面跑着,现在需要重装,怎么办?重新开机进 PXE 太麻烦,Cobbler 提供了 koan 工具,可以在系统内部直接触发重装。
koan --server=192.168.60.10 --system=node01 --replace-self这条命令会让客户端拉取对应的引导文件,然后重启进入安装流程。--replace-self表示替换当前系统自己。这个机制在需要把一台机器从 A 系统换成 B 系统的时候特别有用,不用跑到机房插 U 盘。
批量场景下,可以用 Ansible 或者简单的 SSH 循环去推这条命令,实现几十台机器的统一重装。这里有个安全提醒:--replace-self会直接覆盖当前系统,执行前一定要确认 IP 规划、主机名、数据盘挂载策略都是对的,尤其是数据盘如果没在 Kickstart 里排除,重装的时候可能被清空。我的做法是在 Kickstart 的分区段里把数据盘明确排除,只动系统盘,这样重装不影响数据。
6. 踩过的坑与排查速查表
6.1 常见问题速查表
装机这活儿,出问题是常态,我把这些年积累的高频问题整理成一张表,遇到的时候先查表。
| 现象 | 可能原因 | 定位方法 | 处理 |
|---|---|---|---|
| 客户端提示 No boot filename received | DHCP 下发参数缺失 | 看 dhcpd 日志和抓包 | 检查 filename 和 next_server |
| 卡在 TFTP 传输不动 | 引导文件缺失或权限不对 | 看 TFTP 日志和端口流量 | 重跑 mkloaders 并检查目录权限 |
| 装机界面反复出现 | pxe_just_once 未开启 | 查 settings.yaml | 设为 1 并 sync |
| 装完网络不通 | system 对象 IP 未填或静态标记缺失 | 检查 system report | 补全参数并 sync |
| 拉包很慢或失败 | 软件源指向了外部地址 | 看 Kickstart 渲染结果 | 换成内网 repo |
| 改模板不生效 | 没有执行 sync | 对比渲染后文件 | 执行 cobbler sync |
| 机器装到一半失败 | 磁盘命名和模板不匹配 | 看安装日志 | 用磁盘标识而非固定设备名 |
6.2 五个独家避坑技巧
第一个技巧是磁盘设备名不要写死成/dev/sda这种。不同批次的机器、不同的阵列卡、甚至固件版本不同,磁盘枚举顺序都可能变。我现在的做法是用/dev/disk/by-id/或者 RAID 控制器给出的标识来指定磁盘,虽然模板看起来复杂一点,但换一批硬件不用改模板。这个教训来自一次换供应商之后,新机器的系统盘变成了/dev/sdb,导致 Kickstart 分区失败。
第二个技巧是给装机日志留够空间。大批量装机的时候日志量很大,/var/log如果和系统盘在同一个分区,很容易被写满,写满之后服务就开始各种诡异报错。我把日志目录单独挂了一个 20G 的分区,并且配了 logrotate,避免历史日志把空间吃光。
第三个技巧是在正式装机之前,先用一台测试机把全流程跑三遍。第一遍验证引导链路,第二遍验证分区和软件包,第三遍验证 post 脚本。为什么是三次而不是一次?因为这三类问题的排查思路完全不同,分开验证能让你精确知道问题出在哪一层。三遍都过之后再批量跑,返工的风险大大降低。
第四个技巧是给 Kickstart 里的关键步骤加日志输出。%post段里的脚本我习惯每执行一步就往一个固定文件里写一行带时间戳的记录,装完之后登进去看这个文件,一眼就知道哪个环节没跑成。没有日志的装机脚本,排查起来跟开盲盒没区别。
第五个技巧是留一份"最小可用配置"的备份。Cobbler 的整套配置集中在/etc/cobbler/和/var/lib/cobbler/两个目录,我会定期把这两个目录打包备份到另一台机器上。为什么强调这个?因为一旦服务端这台机器挂了,重建 Cobbler 的配置是很费时间的,而且有些参数是当时调试出来的,记不住。有备份的话,新机器装好系统、还原这两个目录、导入镜像,半小时就能恢复服务。
6.3 服务端日常维护与后续扩展
跑起来之后,日常维护其实不多,但有几点要定期做。第一是定期跑cobbler check,有时候系统更新会改变某些路径或者依赖,提前发现比装机当天发现好。第二是定期清理不再使用的 distro 和 profile,cobbler distro remove的时候注意是否要一并删除镜像文件,命名不对可能会留下大量废弃目录占着磁盘。第三是注意 Web 服务日志的轮转,装机高峰期访问量大,日志涨得很快。
后续如果要扩展,方向有几个。一是接入自动化流程,把 Cobbler 的对象管理封成 API 调用,新机器入库的时候自动创建 system 对象,实现真正的零手工。二是把装机完成后的配置管理交给专门的工具,让 Cobbler 只负责把系统装起来,装完之后的软件配置、服务编排交给上层工具处理,职责更清晰。三是做装机结果的可观测,把每次装机的结果汇总到一个面板上,哪些成功哪些失败一目了然,而不是靠人一台台去登。
我自己的体会是,Cobbler 这种工具的价值不在于它多先进,而在于它把一件重复度极高的事情变得可控。第一次调通链路那一两天是有点折磨,尤其是 DHCP 和 TFTP 那几段一旦配错,报错信息又很含糊。但只要把主流程跑通一次,并且把配置备份好、把日志看明白,后面几十上百台机器就是批处理的事。真正花时间的从来不是装机本身,而是那些没被记录下来的隐性配置。