PXE 与 Cobbler 批量自动装机
本文合并自:04-自动装机.md、01-Cobbler批量自动装机.md
一、为什么需要批量自动装机
1.1 手工装机的瓶颈
手工插光盘/U 盘装系统,在只有一两台机器时完全可以接受,但一旦规模上去,就会暴露三个致命问题:
| 问题 | 具体表现 |
|---|---|
| 效率瓶颈 | 一台机器从插盘到装完、配好 IP,熟练工也要 20~40 分钟。机房上架 50 台服务器,一个人串行操作需要两三天,且必须全程守在机器前敲下一步 |
| 一致性问题 | 人手操作必然产生差异:分区大小不一致、时区有的选上海有的选纽约、SELinux 有的关了有的忘关、软件包组勾选不同。后期排障时"为什么这台机器行那台不行"往往就源于装机阶段的不一致 |
| 不可追溯 | 手工点选的过程无法版本化、无法评审、无法复现。人员离职后没人说得清当初到底怎么装的 |
| 物理限制 | 机房里没有那么多光驱和显示器,很多机架服务器根本不带光驱,只能靠 IPMI/KVM over IP 挂载虚拟光驱,操作更慢 |
1.2 典型场景
- 机房上架:一批新到货的 30~200 台服务器,需要统一装成同一版本的 CentOS/Rocky,统一分区、统一基线配置。
- 系统重装/回收:测试环境机器被弄脏了,需要一键推倒重装回到干净状态。
- 多角色差异化装机:同一批机器里,10 台要装成数据库节点(大
/data分区、无图形界面),20 台要装成 Web 节点(标准分区、装 nginx 依赖),需要按 MAC 地址区分。 - 异地机房:多个机房各自需要一套装机服务,配置需要在机房之间复制同步。
1.3 装机方式对比
| 方式 | 适用规模 | 前置条件 | 速度 | 灵活性 | 说明 |
|---|---|---|---|---|---|
| 光盘安装 | 1~2 台 | ISO 刻盘、机器有光驱、BIOS 第一启动顺序改为光驱 | 慢(受光驱读取速度限制) | 高(可交互任意选择) | 将 ISO 镜像刻录到光盘,通过光驱安装 |
| U 盘安装 | 1~5 台 | ISO 写入 U 盘(dd / Rufus / UltraISO)、BIOS 第一启动顺序改为 USB | 中(USB 3.0 比光驱快很多) | 高 | 目前单机装机最常用方式,机架服务器无光驱时的替代 |
| 硬盘安装 | 1 台,特殊场景 | 本机硬盘上已存有 ISO 镜像,通过 grub 引导 | 中 | 中 | 可用于装第二个系统或重装本机系统。只重格根分区,绝对不要格掉 ISO 所在的那个分区 |
| PXE 网络安装 | 10~500 台 | 网卡支持 PXE、可控的二层网络、一台服务端跑 DHCP+TFTP+HTTP | 快(可并行装几十台) | 高(Kickstart 可完全定制) | 本文重点。无人值守,一次配置反复使用 |
| 镜像克隆(dd / Clonezilla / ghost) | 5~50 台同型号机器 | 硬件型号一致或高度相似、有一台做好的样板机 | 极快(按块拷贝) | 低(主机名/IP/MAC/machine-id 需要装后二次处理,硬件不同易蓝屏或起不来) | dd 逐块复制整盘,Clonezilla 支持多播批量克隆 |
| 虚拟化模板克隆 | 虚拟机场景 | 已有 KVM/VMware 模板,配合 virt-clone / virt-sysprep | 极快(秒级到分钟级) | 中(靠 sysprep 与 cloud-init 做个性化) | 虚拟机批量交付的标准做法 |
| 云环境镜像 + cloud-init | 云上任意规模 | 公有云/私有云平台、自定义镜像、cloud-init 已装入镜像 | 极快(API 调用即出机器) | 高(user-data 脚本任意定制) | 云时代取代 PXE 的主流方案,装机变成"起实例 + 首次启动跑 user-data" |
详见 15-01-KVM虚拟化.md
无人值守安装的两条主流技术路线:
- kickstart:
PXE + DHCP + TFTP + (NFS/HTTP/FTP) + ks.cfg,纯手工搭建,各服务独立配置。 - cobbler:在 kickstart 基础上做了一层封装,把上面这些服务统一管理起来,自动生成各服务的配置文件,提供更便捷的管理方式。
本文按"先原理与手工实现,再用 Cobbler 自动化"的顺序组织:先把 PXE + Kickstart 手工搭一遍,理解每个服务的作用;再用 Cobbler 把这些手工劳动自动化。
二、PXE 工作原理
2.1 PXE 是什么
PXE(Preboot eXecution Environment,预启动执行环境,也写作 Preboot Execute Environment)是 Intel 公司提出的技术标准,工作在 Server/Client 网络模式下,支持客户端从服务端下载软件,并通过 TFTP(Trivial File Transfer Protocol,简单文件传输协议)把启动软件包下载到客户端内存中执行。
工作模型:
安装服务器
|
---------------------------------
| | | | |
pc1 pc2 pc3 pc4 pc5 ......
客户端侧的前提条件很简单,只需两点:
- 网卡集成 PXE 芯片(PXE Boot ROM)。现代服务器网卡和绝大多数消费级主板集成网卡都支持,虚拟机的虚拟网卡(e1000/vmxnet3/virtio)也都支持。
- BIOS/UEFI 中开启网络启动,并把网络启动(Network Boot / PXE / Boot from LAN)调到第一启动顺序,或在开机时按 F12 临时选择网络启动。
客户端不需要任何操作系统、不需要硬盘上有任何数据,一台全新的裸机就能装。
2.2 完整启动流程(逐步)
这是全文最需要吃透的一张流程,排错时基本就是按这个顺序逐段验证:
① 客户端网卡加电,PXE ROM 初始化,以 UDP 广播发出 DHCP DISCOVER
(源 0.0.0.0:68 → 目的 255.255.255.255:67,报文中带 PXEClient 标识)
↓
② DHCP 服务器(UDP 67)收到后 OFFER/ACK,返回四类信息:
- 客户端 IP、子网掩码、网关(option routers)、DNS
- next-server:告诉客户端"引导文件在哪台 TFTP 服务器上"
- filename:告诉客户端"要下载的引导文件叫什么",BIOS 下通常是 pxelinux.0
↓
③ 客户端拿到 IP 后,向 next-server 指定的主机用 TFTP(UDP 69)
下载 filename 指定的引导程序 pxelinux.0,载入内存执行
↓
④ pxelinux.0 启动后,继续用 TFTP 依次尝试读取配置文件
pxelinux.cfg/<UUID> → pxelinux.cfg/01-<MAC> → pxelinux.cfg/<IP 十六进制>
→ ... → pxelinux.cfg/default
(这个"从最精确到最通用"的查找顺序,正是按 MAC 差异化装机的底层机制)
读到菜单定义后,显示引导菜单(vesamenu.c32/menu.c32 负责渲染,boot.msg 是提示文字)
↓
⑤ 用户选择(或超时自动进入)某个 LABEL,pxelinux.0 依据该 LABEL 的
kernel / append 指令,用 TFTP 下载安装内核 vmlinuz 和初始内存盘 initrd.img
↓
⑥ 内核解压启动,initrd.img 中的安装程序 anaconda 开始运行,
并解析内核命令行上的参数(如 ks=、inst.repo=、ip=、ksdevice=)
↓
⑦ anaconda 按 ks= 指定的 URL,通过 HTTP/FTP/NFS 下载 Kickstart 应答文件;
再按 ks 文件里 url/nfs/cdrom 指令指定的位置获取安装源(Packages 仓库)
↓
⑧ anaconda 按 ks 文件的应答自动完成:分区 → 格式化 → 安装软件包 →
设置 root 密码/时区/网络 → 装引导器 → 执行 %post → reboot
全程无人值守
2.3 BIOS 与 UEFI 启动的差异
这是实际部署中最容易踩的坑之一:BIOS 与 UEFI 需要下发的引导文件完全不同。
| 项目 | 传统 BIOS(Legacy / CSM) | UEFI |
|---|---|---|
| DHCP filename 下发 | pxelinux.0 |
grubx64.efi,或安全启动场景下的 shim.efi / shimx64.efi(由 shim 再去加载 grubx64.efi) |
| 引导程序来源 | syslinux 包提供 pxelinux.0、menu.c32、vesamenu.c32 | grub2-efi-x64-modules / shim-x64 包提供,或从安装镜像 EFI/BOOT/ 目录拷贝 |
| 菜单配置文件 | pxelinux.cfg/default |
grub.cfg(放在 tftpboot 根或 EFI/ 子目录,语法是 grub 的 menuentry,不是 syslinux 语法) |
| 架构判断 | — | DHCP 可依据 option 93(client-arch)区分 BIOS(00:00) 与 UEFI x64(00:07/00:09),同一台 DHCP 同时服务两类客户端 |
也就是说:把 UEFI 客户端指向 pxelinux.0 一定失败,表现通常是网卡拿到了 IP 但立刻报错或直接跳到下一个启动项。虚拟机实验时,建议先统一用 BIOS/Legacy 模式把流程跑通,再处理 UEFI。
2.4 涉及的服务与角色分工
| 服务 | 软件包 | 协议/端口 | 在 PXE 中的职责 | 传输的内容 |
|---|---|---|---|---|
| DHCP | dhcp / dhcp-server | UDP 67(服务端)、UDP 68(客户端) | 给客户端分配 IP、掩码、网关、DNS;并通过 next-server 与 filename 告知引导文件的位置和名字 |
仅配置参数,不传文件 |
| TFTP | tftp-server(客户端 tftp) | UDP 69 | 传输小体积引导文件。TFTP 是简单文件传输协议,提供简单、不可靠的文件传输服务,基于 UDP 69 端口,无认证、无加密,只适合传小文件 | pxelinux.0、menu.c32/vesamenu.c32、boot.msg、pxelinux.cfg/default、vmlinuz、initrd.img |
| HTTP | httpd | TCP 80 | 提供大体积安装源(整个光盘的 Packages)与 ks 应答文件 | 整个安装镜像目录、ks.cfg |
| FTP | vsftpd | TCP 21(+ 被动端口) | 同上,二选一 | 同上 |
| NFS | nfs-utils | TCP/UDP 2049(+ rpcbind 111) | 同上,二选一 | 同上 |
| rsync | rsync | TCP 873 | Cobbler 场景下用于镜像同步、多机房复制 | 镜像树 |
服务器端所需技术与服务,归纳为四点:
- NFS 服务器,或 HTTP、FTP 三种协议之一:共享安装光盘目录文件。
- TFTP 服务器:共享启动相关文件。
- DHCP 服务器:为客户端分配 IP、网关、DNS、主机名、NIS 域、NTP 等。
- kickstart 程序生成的
ks.cfg配置文件:定义分区、格式化、root 密码、时区、安装包等;可为安装方案命名,由客户端选择是否按该方案安装。
满足前三点即可构成一台手动网络安装服务器(客户端会进入 anaconda 交互界面,需要人来点下一步);加上第四点 ks.cfg 才是无人值守安装。
2.5 客户端安装流程(源文档概述版)
- 客户端(支持 PXE 的网卡)选择网络启动。
- 通过 DHCP 获取 IP,与服务器通信。
- 通过 TFTP 下载系统引导文件。
- 按照
ks.cfg配置文件中的方式自动安装操作系统。 - 安装最后一步按照
ks.cfg配置的软件包进行安装。
三、环境准备
3.1 实验环境规划
| 角色 | 主机名 | IP / 网段 | 系统 | 承担的服务 |
|---|---|---|---|---|
| 装机服务端 | pxe-server | 192.168.100.10/24(实验网段 192.168.100.0/24) | CentOS 7.x(同时给出 CentOS 6 写法) | dhcpd、tftp-server、httpd(可选 vsftpd/nfs) |
| DHCP 地址池 | — | 192.168.100.100 ~ 192.168.100.200 | — | 分配给待装机客户端 |
| 网关 / DNS | — | 192.168.100.10(实验中让服务端兼任)或 192.168.100.1 | — | — |
| 客户端 | — | 由 DHCP 动态获取 | 待安装 | 裸机,仅需网卡支持 PXE、内存 ≥ 2G |
| Cobbler 服务端(第二部分实验) | cobbler-server | 3.3.3.4/24 | CentOS 7 | cobbler 统管全部服务 |
客户端内存建议 2G 以上。内存过小会导致安装时报空间不足错误(CentOS 7 的 anaconda 会把安装源缓存在内存里)。
3.2 关键前提:网段内不能有其他 DHCP 服务器
这是 PXE 实验最高频的失败原因,必须放在第一位强调:
- DHCP 是广播抢答机制,客户端接受最先到达的那个 OFFER。
- 如果实验网段里还有另一台 DHCP(家用路由器、公司办公网 DHCP、VMware/VirtualBox 自带的 DHCP、另一台同学的实验机),客户端很可能拿到那台的 IP。那台 DHCP 不会下发
next-server和filename,客户端拿到 IP 后无处下载引导文件,表现为:拿到了 IP 却报 PXE-E32 / 直接跳过网络启动。 - 更严重的是,你搭的 DHCP 也可能反过来污染办公网,把同事的机器网关改到你的实验机上,属于生产事故。
注意:为防止 DHCP 服务器冲突,不要在桥接网络内搭建 DHCP 服务器。使用 KVM 的同学请使用私有网络(isolated network)。
各虚拟化平台关闭自带 DHCP 的方法:
【VMware Workstation / Player】
Edit → Virtual Network Editor → 选中要用的 VMnet(如 VMnet1 仅主机 / VMnet8 NAT)
→ 取消勾选 "Use local DHCP service to distribute IP address to VMs"
→ 若用 VMnet8,还需注意 NAT 设置里的网关地址不要与你的规划冲突
→ 服务端与客户端虚拟机的网络都设为同一个 VMnet(推荐"仅主机 Host-only",最干净)
【VirtualBox】
管理 → 主机网络管理器 → 选中 vboxnet0 → 取消勾选 "启用 DHCP 服务器"
或命令行:VBoxManage dhcpserver modify --netname HostInterfaceNetworking-vboxnet0 --disable
虚拟机网络模式设为"仅主机(Host-only)"或"内部网络(Internal Network)"
【KVM / libvirt】
默认的 default 网络自带 dnsmasq DHCP,必须避开:
virsh net-destroy default ; virsh net-autostart default --disable
或新建一个 isolated(私有)网络且不配置 <dhcp> 段:
virsh net-define isolated.xml ; virsh net-start isolated
验证网段内是否有别的 DHCP(在服务端上执行,观察是否有非自己的应答):
# 抓包看有几个 DHCP 服务器在应答
tcpdump -i eth0 -nn port 67 or port 68
# 或用 nmap 探测
nmap --script broadcast-dhcp-discover
3.3 关闭防火墙与 SELinux
实验环境直接关闭,生产环境按需放行。
# ---------- CentOS 7 ----------
systemctl stop firewalld
systemctl disable firewalld
setenforce 0
sed -i 's/^SELINUX=enforcing/SELINUX=disabled/' /etc/selinux/config
# ---------- CentOS 6 ----------
service iptables stop
chkconfig iptables off
setenforce 0
sed -i 's/^SELINUX=enforcing/SELINUX=disabled/' /etc/selinux/config
生产环境正确放行(不关防火墙的做法):
# ---------- CentOS 7 firewalld ----------
firewall-cmd --permanent --add-service=dhcp # UDP 67
firewall-cmd --permanent --add-service=tftp # UDP 69
firewall-cmd --permanent --add-service=http # TCP 80
firewall-cmd --permanent --add-service=ftp # TCP 21,用 vsftpd 时
firewall-cmd --permanent --add-service=nfs # 用 NFS 时
firewall-cmd --permanent --add-service=rpc-bind
firewall-cmd --permanent --add-service=mountd
firewall-cmd --reload
# ---------- CentOS 6 iptables ----------
iptables -I INPUT -p udp --dport 67 -j ACCEPT
iptables -I INPUT -p udp --dport 69 -j ACCEPT
iptables -I INPUT -p tcp --dport 80 -j ACCEPT
service iptables save
# SELinux 不关时,需要放行 tftp/httpd 的相关布尔值与上下文
setsebool -P tftp_home_dir on
restorecon -Rv /var/lib/tftpboot
restorecon -Rv /var/www/html
详见 07-03-防火墙与SELinux.md
3.4 挂载系统镜像作为安装源
把 CentOS 的 ISO 挂到一个目录,作为安装源与本地 yum 源的共同来源:
mkdir -p /mnt/cdrom
# 方式一:挂载物理光驱 / 虚拟机已连接的 ISO
mount /dev/cdrom /mnt/cdrom
mount /dev/sr0 /mnt/cdrom # 同上,设备名可能不同
# 方式二:挂载放在硬盘上的 ISO 文件(推荐,速度快且不占光驱)
mount -o loop /root/CentOS-7-x86_64-DVD-1611.iso /mnt/cdrom
# 开机自动挂载
echo '/root/CentOS-7-x86_64-DVD-1611.iso /mnt/cdrom iso9660 loop,defaults 0 0' >> /etc/fstab
mount -a
# 确认挂载成功(应能看到 Packages、isolinux、images、repodata 等目录)
ls /mnt/cdrom
3.5 配置本地 yum 源
服务端自己装 dhcp/tftp/httpd 时需要一个可用的 yum 源,直接用刚挂载的镜像最省事:
mkdir -p /etc/yum.repos.d/bak
mv /etc/yum.repos.d/*.repo /etc/yum.repos.d/bak/
vim /etc/yum.repos.d/local.repo
[local]
name=CentOS-Local-DVD
baseurl=file:///mnt/cdrom
enabled=1
gpgcheck=0
yum clean all
yum repolist
详见 05-02-常用软件安装与yum源配置.md
四、DHCP 配置
4.1 安装
# CentOS 7
yum -y install dhcp
# CentOS 6
yum -y install dhcp
CentOS 6 与 7 的 dhcpd 主配置文件路径都是 /etc/dhcp/dhcpd.conf,但初始内容与服务管理方式不同:
| 项目 | CentOS 6 | CentOS 7 |
|---|---|---|
| 配置文件 | /etc/dhcp/dhcpd.conf(初始几乎为空,模板在 /usr/share/doc/dhcp-4.1.1/dhcpd.conf.sample) |
/etc/dhcp/dhcpd.conf(初始为空,模板在 /usr/share/doc/dhcp*/dhcpd.conf.example) |
| 服务名 | dhcpd |
dhcpd.service |
| 启动 | service dhcpd start |
systemctl start dhcpd |
| 开机自启 | chkconfig dhcpd on |
systemctl enable dhcpd |
| 指定监听网卡 | /etc/sysconfig/dhcpd 里的 DHCPDARGS=eth0 |
systemctl edit dhcpd 或改 /usr/lib/systemd/system/dhcpd.service 的 ExecStart 末尾加网卡名 |
4.2 完整配置文件
# /etc/dhcp/dhcpd.conf
# ---- 全局参数 ----
ddns-update-style none; # 不做动态 DNS 更新
ignore client-updates; # 忽略客户端提交的主机名更新
allow booting; # 允许客户端网络引导(PXE 必需)
allow bootp; # 允许响应 bootp 请求(PXE 必需)
default-lease-time 21600; # 默认租期 6 小时
max-lease-time 43200; # 最大租期 12 小时
# ---- 作用域:为 192.168.100.0/24 网段服务 ----
subnet 192.168.100.0 netmask 255.255.255.0 {
range 192.168.100.100 192.168.100.200; # 地址池
option routers 192.168.100.10; # 网关
option subnet-mask 255.255.255.0; # 子网掩码
option domain-name-servers 192.168.100.10; # DNS
option domain-name "example.com";
option time-offset 28800; # 东八区偏移秒数
# ======== 以下两行是 PXE 的关键,缺一不可 ========
next-server 192.168.100.10; # TFTP 服务器的 IP(引导文件在哪台机器上)
filename "pxelinux.0"; # 要下载的引导文件名(BIOS 用 pxelinux.0)
# ===============================================
}
同时服务 BIOS 与 UEFI 客户端的写法(依据 option 93 判断架构):
option architecture-type code 93 = unsigned integer 16;
subnet 192.168.100.0 netmask 255.255.255.0 {
range 192.168.100.100 192.168.100.200;
option routers 192.168.100.10;
next-server 192.168.100.10;
class "pxeclients" {
match if substring (option vendor-class-identifier, 0, 9) = "PXEClient";
if option architecture-type = 00:07 or option architecture-type = 00:09 {
filename "uefi/shimx64.efi"; # UEFI x64
} else {
filename "pxelinux.0"; # Legacy BIOS
}
}
}
为单台机器固定 IP(按 MAC 绑定,手工方案下的差异化基础):
host db01 {
hardware ethernet 00:0c:29:aa:bb:cc;
fixed-address 192.168.100.51;
filename "pxelinux.0";
next-server 192.168.100.10;
}
4.3 启动服务与排错
# 语法检查(强烈建议改完必做,语法错会导致服务起不来)
dhcpd -t -cf /etc/dhcp/dhcpd.conf
# CentOS 7
systemctl start dhcpd
systemctl enable dhcpd
systemctl status dhcpd
# CentOS 6
service dhcpd start
chkconfig dhcpd on
service dhcpd status
# 确认监听 UDP 67
netstat -anup | grep 67 # CentOS 6
ss -anup | grep 67 # CentOS 7
# 查看日志与租约
tail -f /var/log/messages
cat /var/lib/dhcpd/dhcpd.leases
常见启动失败原因:
No subnet declaration for ethX:dhcpd 监听的网卡 IP 不属于配置文件里任何一个 subnet 段。检查网卡 IP 与 subnet 网段是否一致,多网卡服务器要显式指定监听网卡。- 配置文件末尾少了
}或;:dhcpd -t会直接指出行号。 - 服务起了但客户端拿不到 IP:先排查有没有别的 DHCP 抢答,再抓包
tcpdump -i eth0 -nn port 67。
详见 09-01-DHCP服务.md
五、TFTP 配置
TFTP 只负责传输小体积的引导文件(几 MB 的 vmlinuz 和几十 MB 的 initrd.img),大文件(整个 Packages 目录)交给 HTTP。
5.1 安装
# 服务端
yum -y install tftp-server
# 客户端测试工具(服务端也装一个用于自测)
yum -y install tftp
# CentOS 6 还必须装 xinetd(tftp 由 xinetd 托管)
yum -y install xinetd
5.2 CentOS 6:由 xinetd 托管
CentOS 6 的 tftp 是一个由 xinetd 超级守护进程按需拉起的服务,本身没有独立的启动脚本,必须改 xinetd 的配置片段:
vim /etc/xinetd.d/tftp
service tftp
{
socket_type = dgram
protocol = udp
wait = yes
user = root
server = /usr/sbin/in.tftpd
server_args = -s /var/lib/tftpboot # TFTP 根目录
disable = no # 关键:默认是 yes,必须改成 no
per_source = 11
cps = 100 2
flags = IPv4
}
# 一行命令改 disable
sed -i '/disable/s/yes/no/' /etc/xinetd.d/tftp
# 重启 xinetd 使 tftp 生效
service xinetd restart
chkconfig xinetd on
# 确认 UDP 69 已监听
netstat -anup | grep 69
详见 08-03-时间同步与Xinetd.md
5.3 CentOS 7:systemd socket 激活
CentOS 7 把 tftp 改成了 systemd 的 socket 激活模式,提供 tftp.service 与 tftp.socket 两个单元,不再需要 xinetd:
systemctl start tftp
systemctl enable tftp
systemctl status tftp
# 更规范的做法:启用 socket 单元,有请求时才拉起 service
systemctl start tftp.socket
systemctl enable tftp.socket
# 确认监听
ss -anup | grep 69
修改 TFTP 根目录(CentOS 7):
systemctl edit tftp.service
[Service]
ExecStart=
ExecStart=/usr/sbin/in.tftpd -s /var/lib/tftpboot
CentOS 6 与 7 的 tftp 差异对照:
| 项目 | CentOS 6 | CentOS 7 |
|---|---|---|
| 托管方式 | xinetd 超级守护进程 | systemd socket 激活 |
| 配置文件 | /etc/xinetd.d/tftp,disable = no |
/usr/lib/systemd/system/tftp.service + tftp.socket |
| 启动命令 | service xinetd restart |
systemctl start tftp(或 tftp.socket) |
| 开机自启 | chkconfig xinetd on |
systemctl enable tftp.socket |
| 根目录 | server_args = -s /var/lib/tftpboot |
ExecStart 的 -s /var/lib/tftpboot |
TFTP 根目录统一是 /var/lib/tftpboot,客户端请求 pxelinux.0 时,实际取的是 /var/lib/tftpboot/pxelinux.0(路径中不包含根目录本身)。
5.4 验证 TFTP 可用
一定要在配置引导文件后做这一步自测,能省下大量排错时间:
# 放一个测试文件
echo hello > /var/lib/tftpboot/test.txt
chmod 644 /var/lib/tftpboot/test.txt
# 用 tftp 客户端从本机取(注意 get 后面不要加路径前缀)
cd /tmp
tftp 192.168.100.10
tftp> get test.txt
tftp> quit
cat /tmp/test.txt
# 一行式写法
tftp 192.168.100.10 -c get pxelinux.0
# 从另一台机器测(验证防火墙是否放行)
tftp 192.168.100.10 -c get pxelinux.0 && echo "TFTP OK"
取不到时的排查顺序:服务是否监听 UDP 69 → 文件是否真的在 /var/lib/tftpboot/ 下 → 文件权限是否 others 可读 → 防火墙 UDP 69 → SELinux 上下文(restorecon -Rv /var/lib/tftpboot)。
六、准备引导文件
6.1 安装 syslinux 并拷贝 pxelinux.0
pxelinux.0 由 syslinux 软件包提供:
yum -y install syslinux
# 拷贝引导程序到 TFTP 根目录
cp /usr/share/syslinux/pxelinux.0 /var/lib/tftpboot/
# 菜单渲染模块(二者取一,vesamenu 是图形化菜单,menu 是纯文本菜单)
cp /usr/share/syslinux/menu.c32 /var/lib/tftpboot/
cp /usr/share/syslinux/vesamenu.c32 /var/lib/tftpboot/
# 一些菜单模块可能依赖的库(CentOS 7 的 syslinux 6.x 需要)
cp /usr/share/syslinux/ldlinux.c32 /var/lib/tftpboot/ 2>/dev/null
cp /usr/share/syslinux/libcom32.c32 /var/lib/tftpboot/ 2>/dev/null
cp /usr/share/syslinux/libutil.c32 /var/lib/tftpboot/ 2>/dev/null
CentOS 6 的 pxelinux.0 在
/usr/share/syslinux/pxelinux.0(老版本可能在/usr/lib/syslinux/pxelinux.0),找不到时用rpm -ql syslinux | grep pxelinux定位。
6.2 从镜像拷贝内核与初始内存盘
# 安装内核与初始内存盘(位于镜像的 images/pxeboot/ 下)
cp /mnt/cdrom/images/pxeboot/vmlinuz /var/lib/tftpboot/
cp /mnt/cdrom/images/pxeboot/initrd.img /var/lib/tftpboot/
6.3 拷贝菜单相关文件
# 建立菜单配置目录(注意目录名是 pxelinux.cfg,不能拼错)
mkdir -p /var/lib/tftpboot/pxelinux.cfg
# 直接拿光盘 isolinux 目录下的菜单文件作为起点
cp /mnt/cdrom/isolinux/isolinux.cfg /var/lib/tftpboot/pxelinux.cfg/default
# 提示文字与菜单背景/图形模块
cp /mnt/cdrom/isolinux/boot.msg /var/lib/tftpboot/
cp /mnt/cdrom/isolinux/vesamenu.c32 /var/lib/tftpboot/
cp /mnt/cdrom/isolinux/splash.png /var/lib/tftpboot/ 2>/dev/null
# CentOS 6 的光盘里还有这些提示文件,可一并拷贝
cp /mnt/cdrom/isolinux/*.msg /var/lib/tftpboot/ 2>/dev/null
# 权限
chmod -R 644 /var/lib/tftpboot/*
chmod 755 /var/lib/tftpboot/pxelinux.cfg
最终 TFTP 根目录结构:
/var/lib/tftpboot/
├── pxelinux.0 # PXE 引导程序(BIOS)
├── vesamenu.c32 # 图形菜单模块
├── menu.c32 # 文本菜单模块
├── boot.msg # 菜单提示文字
├── splash.png # 菜单背景图(可选)
├── vmlinuz # 安装内核
├── initrd.img # 初始内存盘(内含 anaconda)
└── pxelinux.cfg/
└── default # 引导菜单定义
6.4 pxelinux.cfg/default 逐项讲解
vim /var/lib/tftpboot/pxelinux.cfg/default
default vesamenu.c32 # 默认加载的菜单模块(图形菜单);也可直接写 LABEL 名
timeout 60 # 菜单等待时间,单位 1/10 秒,60 = 6 秒;0 = 无限等待
prompt 0 # 0=显示菜单不显示 boot: 提示符;1=显示 boot: 提示符
display boot.msg # 显示提示文字文件
# ---- 菜单外观美化 ----
menu background splash.png # 背景图
menu title CentOS 7 PXE Install Menu # 菜单标题
menu color border 0 #ffffffff #00000000
menu color sel 7 #ffffffff #ff000000
menu color title 0 #ffffffff #00000000
menu color tabmsg 0 #ffffffff #00000000
menu color unsel 0 #ffffffff #00000000
menu color hotsel 0 #ff000000 #ffffffff
menu color timeout_msg 0 #ffffffff #00000000
menu color timeout 0 #ffffffff #00000000
# ---- 菜单项 1:自动化安装(无人值守,本文重点)----
label linux
menu label ^Auto Install CentOS 7 (Kickstart)
menu default # 标记为默认选中项,超时后进入这一项
kernel vmlinuz # 指定内核文件(相对 TFTP 根目录)
append initrd=initrd.img inst.repo=http://192.168.100.10/centos7 inst.ks=http://192.168.100.10/ks/ks.cfg quiet
# append 里都是传给内核/anaconda 的参数:
# initrd= 初始内存盘
# inst.repo= 安装源位置(CentOS 7 新语法;CentOS 6 用 method= 或 repo=)
# inst.ks= Kickstart 应答文件的 URL(CentOS 7 新语法;CentOS 6 用 ks=)
# ksdevice= 指定用哪块网卡(eth0 / bootif / link / 具体 MAC)
# ip=dhcp 让 anaconda 阶段也用 dhcp 取 IP
# text 纯文本安装界面(省内存)
# quiet 减少启动输出
# ---- 菜单项 2:交互式图形安装(保留人工介入的入口)----
label manual
menu label ^Manual Install CentOS 7 (Graphical)
kernel vmlinuz
append initrd=initrd.img inst.repo=http://192.168.100.10/centos7
# ---- 菜单项 3:从本地硬盘启动(重要,防止误装)----
label local
menu label Boot from ^local drive
localboot 0xffff # 0xffff / -1 表示交还给本地磁盘启动
# ---- 菜单项 4:救援模式 ----
label rescue
menu label ^Rescue installed system
kernel vmlinuz
append initrd=initrd.img inst.repo=http://192.168.100.10/centos7 rescue
配置项速查:
| 配置项 | 作用 |
|---|---|
default |
默认加载的模块或默认 LABEL |
timeout |
等待用户选择的时间,单位 1/10 秒;0 表示永久等待(人工场景),生产批量装机常设 30~60 |
prompt |
是否显示 boot: 提示符 |
label xxx |
定义一个菜单项,xxx 是内部名称 |
menu label |
菜单上显示的文字,^ 后的字母为快捷键 |
menu default |
该项为默认高亮项,配合 timeout 实现超时自动安装 |
kernel |
要加载的内核文件(相对 TFTP 根目录的路径) |
append |
追加到内核命令行的参数,initrd= 与 ks= 都写在这里 |
localboot 0xffff |
不装系统,改为从本地硬盘启动 |
ipappend 2 |
把 PXE 启动用的网卡 MAC 以 BOOTIF= 形式传给内核,配合 ksdevice=bootif 使用 |
CentOS 6 与 7 的内核参数差异(写错会导致找不到安装源):
| 用途 | CentOS 6 | CentOS 7 及以后 |
|---|---|---|
| 指定 ks 文件 | ks=http://IP/ks.cfg |
inst.ks=http://IP/ks.cfg(ks= 仍兼容) |
| 指定安装源 | method=http://IP/centos6 或 repo= |
inst.repo=http://IP/centos7(repo= 仍兼容) |
| 指定网卡 | ksdevice=eth0 |
ip=eth0:dhcp 或 ksdevice=bootif + ipappend 2 |
| 文本模式 | text |
inst.text / text |
6.5 多系统多版本引导菜单的组织
要在一套 PXE 上同时提供 CentOS 6、CentOS 7、Rocky 8 等多个版本,关键是按版本分子目录存放内核与 initrd,避免文件名冲突:
/var/lib/tftpboot/
├── pxelinux.0
├── vesamenu.c32
├── pxelinux.cfg/
│ └── default
└── images/
├── centos6-x86_64/
│ ├── vmlinuz
│ └── initrd.img
├── centos7-x86_64/
│ ├── vmlinuz
│ └── initrd.img
└── rocky8-x86_64/
├── vmlinuz
└── initrd.img
menu title Multi-OS PXE Install Menu
timeout 300
default vesamenu.c32
label local
menu label Boot from ^local drive
menu default
localboot 0xffff
label centos6-min
menu label CentOS ^6.9 x86_64 Minimal
kernel images/centos6-x86_64/vmlinuz
append initrd=images/centos6-x86_64/initrd.img ks=http://192.168.100.10/ks/centos6-min.cfg ksdevice=eth0
label centos7-min
menu label CentOS ^7.9 x86_64 Minimal
kernel images/centos7-x86_64/vmlinuz
append initrd=images/centos7-x86_64/initrd.img inst.ks=http://192.168.100.10/ks/centos7-min.cfg
label centos7-db
menu label CentOS 7.9 x86_64 - ^DB Node (big /data)
kernel images/centos7-x86_64/vmlinuz
append initrd=images/centos7-x86_64/initrd.img inst.ks=http://192.168.100.10/ks/centos7-db.cfg
label rocky8-min
menu label ^Rocky Linux 8 x86_64 Minimal
kernel images/rocky8-x86_64/vmlinuz
append initrd=images/rocky8-x86_64/initrd.img inst.ks=http://192.168.100.10/ks/rocky8-min.cfg
按 MAC 差异化的进阶技巧:pxelinux.cfg/ 下可以放以 MAC 命名的配置文件,pxelinux.0 会优先读取它,从而让特定机器跳过菜单直接装指定方案。文件名格式为 01- 前缀加小写 MAC,冒号换成短横线:
# MAC 为 00:0c:29:aa:bb:cc 的机器,专用配置
vim /var/lib/tftpboot/pxelinux.cfg/01-00-0c-29-aa-bb-cc
default db
prompt 0
timeout 1
label db
kernel images/centos7-x86_64/vmlinuz
append initrd=images/centos7-x86_64/initrd.img inst.ks=http://192.168.100.10/ks/centos7-db.cfg
这个机制手工维护很痛苦(几十台机器就是几十个文件),正是 Cobbler 的 cobbler system add --mac 要替我们做的事。
七、Kickstart 应答文件
7.1 Kickstart 是什么
Kickstart 是 anaconda 安装程序的应答文件。平时手工装系统时 anaconda 会一步步问你:用什么语言、时区选哪里、root 密码是什么、怎么分区、装哪些包……Kickstart 就是把这些问题的答案提前写在一个文本文件里,anaconda 启动后读取它,不再询问,直接照做。
- 它是无人值守安装的核心:PXE 只解决了"从网络启动安装程序",Kickstart 才解决了"安装程序不用人回答问题"。
- 只要 ks 文件中回答了所有必答项,安装就是全自动的;漏答任何一项,安装就会停在那一步的交互界面上等人——这是 ks 排错最常见的现象。
7.2 三种生成方式
方式一:用 /root/anaconda-ks.cfg 做模板(最实用,强烈推荐)
任何一台手工装好的 CentOS,在 /root/ 下都会留一份本次安装的完整应答记录:
cat /root/anaconda-ks.cfg
做法是:先按目标要求手工装一台"样板机",然后把它的 anaconda-ks.cfg 拷出来,改几个地方(安装源 URL、网络、密码)就能直接用。这样生成的 ks 文件语法一定正确、配置项一定完整。
cp /root/anaconda-ks.cfg /var/www/html/ks/ks.cfg
方式二:图形工具 system-config-kickstart
yum install system-config-kickstart
system-config-kickstart
使用时需要注意:必须把软件仓库名改成 development,否则图形界面在"选择软件包"那一步看不到任何内容:
vim /etc/yum.repos.d/local.repo
[development]
name=development
baseurl=file:///yum/
enabled=1
gpgcheck=0
图形操作过程可参考截图 system-config-kickstart01.png 至 system-config-kickstart14.png。
该工具的局限:
- 只支持 RHEL/CentOS 6 时代的一部分配置项,不支持 LVM 的完整写法、不支持
%pre、btrfs、--onpart等,生成的文件往往还需要手工补充。 - CentOS 7 之后官方基本停止维护,CentOS 8/Rocky 已不再提供该包。
- 需要图形环境才能运行。
方式三:手工编写。掌握配置项后最灵活的方式,也是生产环境的常态(ks 文件应当纳入 Git 版本管理)。
特别提醒:ks 文件中不能出现任何中文字符(包括注释行),否则将无法启动安装。
详见 14-01-Git版本控制.md
7.3 ks 文件的三段结构
┌─────────────────────────────────┐
│ 命令段(Command Section) │ install/url/lang/rootpw/part/network ...
├─────────────────────────────────┤
│ %packages ... %end │ 要安装哪些包组和包
├─────────────────────────────────┤
│ %pre ... %end (可选) │ 安装前执行的脚本(分区之前)
│ %post ... %end (可选) │ 安装后执行的脚本(系统装好、重启前)
│ %addon ... %end(可选) │ 附加组件,如 kdump
└─────────────────────────────────┘
顺序上命令段必须在最前面,%packages、%pre、%post 的相对顺序不强制,但每个段必须用 %end 闭合(CentOS 7 起强制要求,漏写 %end 会导致 ks 解析失败)。
7.4 命令段配置项逐项详解
安装源与安装模式
install # 执行全新安装(而非 upgrade);CentOS 8+ 已废弃可省略
upgrade # 升级已有系统(与 install 二选一,极少用)
# ---- 安装源,四种方式选一种 ----
url --url="http://192.168.100.10/centos7" # HTTP(推荐)
url --url="https://192.168.100.10/centos7" --noverifyssl
url --url="ftp://192.168.100.10/centos7" # FTP
nfs --server=192.168.100.10 --dir=/var/ftp/centos7 # NFS
cdrom # 从本地光驱安装
harddrive --partition=sdb1 --dir=/iso # 从本地硬盘上的镜像安装
# ---- 安装界面模式,三选一 ----
text # 纯文本界面(推荐,省内存、无需图形包)
graphical # 图形界面
cmdline # 完全无界面,全自动场景;一旦缺答案会直接失败而不是等待
skipx # 不配置 X Window(装最小化系统时加上)
eula --agreed # 自动同意许可协议(CentOS 7 起,不加会停在 EULA 确认界面)
firstboot --disable # 关闭首次启动向导(--disable / --enable / --reconfig)
语言、键盘、时区
lang en_US.UTF-8 # 系统语言(可加 --addsupport=zh_CN.UTF-8)
keyboard 'us' # CentOS 6 写法
keyboard --vckeymap=us --xlayouts='us' # CentOS 7 写法
timezone Asia/Shanghai --utc # 时区;--utc 表示硬件时钟为 UTC
timezone Asia/Shanghai --isUtc # CentOS 7 的等价写法
timezone Asia/Shanghai --nontp # 不启用 chronyd 时间同步
timezone Asia/Shanghai --utc --ntpservers=ntp1.aliyun.com,ntp2.aliyun.com
--utc表示把硬件时钟当作 UTC 时间。纯 Linux 环境建议用 UTC;与 Windows 双系统的机器不要加--utc,否则两个系统看到的时间会差 8 小时。
root 密码与用户
# 明文(仅供实验,生产禁止)
rootpw --plaintext 123456
# 加密串(推荐)
rootpw --iscrypted $6$rounds=...
rootpw --iscrypted $1$lCWjtTge$uuB/0hPOI.n25entF4ghI0
rootpw --lock # 锁定 root,只用普通用户 + sudo
# 创建普通用户
user --name=devops --groups=wheel --password=$6$xxx... --iscrypted --shell=/bin/bash --homedir=/home/devops
user --name=app --uid=2000 --gid=2000 --password=xxx --iscrypted --gecos="App User"
生成加密密码串的几种方法:
# 1) SHA-512(现代系统首选,对应 $6$ 前缀)
openssl passwd -6 'YourPassword'
openssl passwd -6 -salt "$(openssl rand -base64 8)" 'YourPassword'
# 2) MD5(老系统 / Cobbler 默认用,对应 $1$ 前缀)
openssl passwd -1 -salt 'random-phrase-here' 'your-password-here'
# 3) Python 生成(openssl 版本不支持 -6 时)
python -c 'import crypt,getpass; print(crypt.crypt(getpass.getpass(), crypt.mksalt(crypt.METHOD_SHA512)))'
python3 -c 'import crypt; print(crypt.crypt("YourPassword", crypt.mksalt(crypt.METHOD_SHA512)))'
# 4) grub2 引导菜单密码(不是系统密码,用于给 grub 加密码保护)
grub2-mkpasswd-pbkdf2
要点:绝对不要在 ks 文件里写明文密码。 ks 文件通常放在 HTTP 目录下,任何能访问装机网段的人
curl一下就能看到全部内容。即使用了--iscrypted,加密串泄露也可被离线爆破,因此还要做到:ks 目录做 IP 白名单限制、装机完成后立刻改密码或改用密钥登录、装机网段与办公网隔离。
认证、SELinux、防火墙
# CentOS 6/7 认证配置
auth --useshadow --passalgo=sha512
authconfig --enableshadow --passalgo=sha512
authconfig --enableshadow --passalgo=sha512 --enablefingerprint
# CentOS 8+ 改用
authselect select sssd
selinux --disabled # 关闭(实验/多数国产业务环境的现实选择)
selinux --permissive # 仅告警不拦截(推荐的折中:先观察日志再决定)
selinux --enforcing # 强制(最安全,但需要为业务写策略)
firewall --disabled # 关闭防火墙
firewall --enabled --service=ssh # 启用并只放行 ssh
firewall --enabled --port=22:tcp,80:tcp,443:tcp # 启用并放行指定端口
firewall --enabled --trust=eth1 --service=ssh,http # 信任某网卡
取舍建议:内网集群、有统一边界防火墙时,
--disabled可以接受且能省掉大量排障;机器有公网 IP 或跨安全域时必须--enabled并显式放行。SELinux 同理,能力允许时优先--permissive而非直接--disabled,至少保留审计日志。
网络
# DHCP(最常见)
network --bootproto=dhcp --device=eth0
network --bootproto=dhcp --device=eth0 --onboot=yes --noipv6
network --bootproto=dhcp --device=link --activate # 用第一块有链路的网卡
# 静态 IP
network --bootproto=static --device=eth0 --ip=192.168.100.51 --netmask=255.255.255.0 \
--gateway=192.168.100.1 --nameserver=223.5.5.5,8.8.8.8 --onboot=yes --hostname=db01.example.com
# CentOS 7 网卡名可能是 ens33/eno1,可用 MAC 精确指定
network --bootproto=static --device=00:0c:29:aa:bb:cc --ip=192.168.100.51 \
--netmask=255.255.255.0 --gateway=192.168.100.1 --nameserver=223.5.5.5
# 双网卡:一块业务一块管理
network --bootproto=static --device=eth0 --ip=10.0.0.51 --netmask=255.255.255.0 --gateway=10.0.0.1 --nameserver=223.5.5.5 --activate
network --bootproto=static --device=eth1 --ip=192.168.200.51 --netmask=255.255.255.0 --nodefroute --onboot=yes
# 关闭 IPv6、指定主机名
network --hostname=web01.example.com
| 参数 | 说明 |
|---|---|
--bootproto |
dhcp / static / bootp / ibft(从固件读取) |
--device |
网卡名(eth0/ens33)、MAC 地址、link(第一块有链路的)、bootif(PXE 启动用的那块) |
--onboot |
是否开机激活,yes/no。最容易漏的一项,写 no 会导致装完机器没网 |
--activate |
安装阶段就激活该网卡 |
--noipv6 |
禁用 IPv6 |
--nodefroute |
该网卡不作为默认路由(多网卡必用,否则默认路由会乱) |
--hostname |
设置主机名 |
引导加载器
bootloader --location=mbr --append="rhgb quiet crashkernel=auto"
bootloader --location=mbr --boot-drive=sda --append="net.ifnames=0 biosdevname=0"
bootloader --location=mbr --password=$6$xxx # 给 grub 加密码
bootloader --location=none # 不装引导器(极少用)
bootloader --location=partition # 装到分区的第一个扇区
| 参数 | 说明 |
|---|---|
--location |
mbr(默认,装到磁盘主引导记录)/ partition / none |
--append |
追加到装好系统后的内核启动参数。常用:rhgb quiet(安静启动)、net.ifnames=0 biosdevname=0(把 ens33 改回 eth0 传统命名,运维脚本兼容性更好)、crashkernel=auto(给 kdump 预留内存)、elevator=deadline(老内核下 SSD 的 IO 调度) |
--boot-drive |
多磁盘时明确指定装到哪块盘,避免装错 |
--timeout |
grub 菜单等待秒数 |
磁盘清理与分区(最危险的一段)
zerombr # 清空/初始化磁盘的 MBR(无效分区表时自动初始化)
clearpart --all --initlabel # 清除所有分区并初始化磁盘标签
clearpart --linux # 只清除 Linux 分区(保留 Windows 等其他分区)
clearpart --none # 不清除任何分区
clearpart --all --initlabel --drives=sda # 只对 sda 动手,其他盘不动(强烈推荐)
clearpart --all --initlabel --drives=sda,sdb
ignoredisk --only-use=sda # 让 anaconda 只看到 sda,其余磁盘完全忽略(最安全)
ignoredisk --drives=sdb,sdc # 显式忽略某些盘
危险警示:
zerombr+clearpart --all --initlabel会无条件清空目标磁盘上的所有分区和数据,且没有任何确认提示。这是 Kickstart 里最容易造成事故的两行。真实事故场景:一台机器上除了系统盘 sda 还挂了存有数据的 sdb/sdc,ks 里写的是
clearpart --all,结果数据盘被一起清空。必须遵守的三条纪律:
- 一定要加
--drives=或配合ignoredisk --only-use=限定盘符范围,不要裸用--all。- 确认盘符:不同环境盘符不同——物理机 SATA/SAS 是
sda,KVM virtio 是vda,NVMe 是nvme0n1(分区名是nvme0n1p1而不是nvme0n11),部分 RAID 卡是sda但也可能是cciss/c0d0。盘符写错会导致"分区失败"或"装到了错误的盘上"。- 给已有数据的机器重装前,先确认数据已备份,并优先在
%pre里加判断逻辑。
分区命令 part / partition:
# 标准分区(BIOS + MBR)
part /boot --fstype=xfs --size=1024 --asprimary --ondisk=sda
part swap --fstype=swap --size=4096 --asprimary --ondisk=sda
part / --fstype=xfs --size=20480 --asprimary --ondisk=sda
part /data --fstype=xfs --size=1 --grow --ondisk=sda # 剩余空间全给 /data
# UEFI 机器必须有 EFI 系统分区
part /boot/efi --fstype=efi --size=600 --fsoptions="umask=0077,shortname=winnt" --ondisk=sda
part biosboot --fstype=biosboot --size=1 # BIOS + GPT 时需要
# 带上下限的写法
part /var --fstype=xfs --size=10240 --maxsize=51200 --grow --ondisk=sda
| 参数 | 说明 |
|---|---|
--size=N |
最小尺寸,单位 MiB。必填 |
--grow |
占用剩余全部空间;多个分区都写 --grow 时按 size 比例分配 |
--maxsize=N |
配合 --grow 使用,限制最大不超过 N MiB |
--asprimary |
强制为主分区(MBR 下最多 4 个主分区,超出会失败) |
--fstype |
xfs(CentOS 7 默认)/ ext4 / ext3 / swap / vfat / efi / biosboot |
--ondisk= / --onbiosdisk |
指定建在哪块磁盘上,多盘环境必写 |
--onpart=sda1 |
使用已存在的分区,不重新创建(保留数据重装时用) |
--noformat |
不格式化(配合 --onpart 保留数据) |
--encrypted --passphrase=xxx |
加密该分区 |
--recommended |
让 anaconda 按内存大小推荐尺寸(多用于 swap) |
--label= |
设置文件系统标签 |
LVM 分区写法(生产更常用,方便后期扩容):
# 1. /boot 必须是标准分区,不能放在 LVM 里
part /boot --fstype=xfs --size=1024 --asprimary --ondisk=sda
# 2. 创建物理卷 PV(用 pv.NN 作为标识符)
part pv.01 --size=1 --grow --ondisk=sda
# 3. 创建卷组 VG
volgroup vg_sys pv.01
volgroup vg_sys --pesize=4096 pv.01
# 4. 创建逻辑卷 LV
logvol / --vgname=vg_sys --name=lv_root --fstype=xfs --size=30720
logvol swap --vgname=vg_sys --name=lv_swap --fstype=swap --size=4096
logvol /var --vgname=vg_sys --name=lv_var --fstype=xfs --size=20480
logvol /home --vgname=vg_sys --name=lv_home --fstype=xfs --size=10240
logvol /data --vgname=vg_sys --name=lv_data --fstype=xfs --size=1 --grow
# 也可以让 anaconda 自动分区(简单场景)
autopart --type=lvm
autopart --type=lvm --nohome --fstype=xfs
autopart --type=plain # 不用 LVM
生产经验:不要把 VG 的全部空间一次分完,留 20%~30% 空闲,后期哪个 LV 不够就
lvextend+xfs_growfs扩,比重装划算得多。
详见 03-01-磁盘管理与文件系统.md
安装结束动作
reboot # 安装完成后自动重启(PXE 场景常用,但注意见下方警示)
reboot --eject # 重启并弹出光盘
poweroff # 安装完成后关机(机房批量装机推荐,装完自动关机便于统计)
halt # 停机,显示 "安装完成" 后等待人工操作(默认行为)
shutdown # 同 poweroff
重要坑:写了
reboot而客户端 BIOS 第一启动顺序仍是网络启动,机器会重启后再次进入 PXE,然后又装一遍,陷入无限重装循环。三种解法:①
pxelinux.cfg/default里把localboot项设为menu default并把 timeout 设短,超时自动从本地硬盘启动;② 用poweroff代替reboot,装完关机,人工确认后再改启动顺序;③ Cobbler 场景下cobbler sync后系统装完会自动把该 system 的 netboot 标记置为 false(cobbler system edit --name=xx --netboot-enabled=0),不再下发安装菜单。
7.5 %packages 段
%packages --nobase --ignoremissing --excludedocs
@^minimal # 环境组(CentOS 7 起用 @^ 前缀),最小化安装
@core # 核心包组,几乎必选
@base # 基本包组
@development # 开发工具组
@additional-devel
@desktop-debugging
@fonts
@gnome-desktop
@input-methods
@kde-desktop
@legacy-x
@platform-devel
@remote-desktop-clients
@x11
# ---- 单个软件包 ----
initial-setup
initial-setup-gui
vinagre
tigervnc
firefox
net-tools
wget
elinks
vim-enhanced
bash-completion
tree
lrzsz
sysstat
lsof
tcpdump
ntpdate
chrony
openssh-clients
rsync
# ---- 排除某些包(前面加减号)----
-NetworkManager
-postfix
-firewalld
-abrt*
%end
| 写法 | 含义 |
|---|---|
@^minimal / @^graphical-server-environment |
环境组(Environment Group),对应图形安装界面上的"最小安装/带 GUI 的服务器"等大类。CentOS 7 起引入 |
@base / @core / @development |
包组(Group),对应"附加选项"栏 |
vim-enhanced |
单个 RPM 包名 |
-postfix |
排除该包,不安装 |
--nobase |
不安装 @base 组(做真正的最小化安装) |
--ignoremissing |
遇到源里不存在的包时跳过而不是中断安装。非常重要,否则一个包名写错整个安装就停住 |
--excludedocs |
不安装文档文件,可省几百 MB |
--default |
安装该环境的默认包集合 |
--instLangs=en |
只安装指定语言的本地化文件 |
最小化服务器的推荐起点:
@^minimal+@core,再按需加net-tools vim wget lsof tcpdump sysstat chrony bash-completion。装得越少,攻击面越小、启动越快、后期打补丁越省事。
7.6 %pre 段(安装前脚本)
%pre 在 ks 文件被解析后、磁盘分区之前执行,运行在 anaconda 的 initrd 环境里(可用命令有限,busybox 级别 + 部分工具)。典型用途:
用途一:按磁盘大小动态生成分区方案
%pre --log=/tmp/ks-pre.log
#!/bin/sh
# 找出第一块磁盘的名字(兼容 sda / vda / nvme0n1)
DISK=$(lsblk -dno NAME,TYPE | awk '$2=="disk"{print $1; exit}')
SIZE=$(($(cat /sys/block/${DISK}/size) * 512 / 1024 / 1024 / 1024)) # 单位 GB
echo "Detected disk: ${DISK}, size: ${SIZE}GB" >> /tmp/ks-pre.log
if [ ${SIZE} -lt 100 ]; then
# 小盘:简单分区
cat > /tmp/part-include <<EOF
clearpart --all --initlabel --drives=${DISK}
part /boot --fstype=xfs --size=1024 --asprimary --ondisk=${DISK}
part swap --fstype=swap --size=2048 --ondisk=${DISK}
part / --fstype=xfs --size=1 --grow --ondisk=${DISK}
EOF
else
# 大盘:LVM,单独划 /data
cat > /tmp/part-include <<EOF
clearpart --all --initlabel --drives=${DISK}
part /boot --fstype=xfs --size=1024 --asprimary --ondisk=${DISK}
part pv.01 --size=1 --grow --ondisk=${DISK}
volgroup vg_sys pv.01
logvol / --vgname=vg_sys --name=lv_root --fstype=xfs --size=51200
logvol swap --vgname=vg_sys --name=lv_swap --fstype=swap --size=8192
logvol /var --vgname=vg_sys --name=lv_var --fstype=xfs --size=20480
logvol /data --vgname=vg_sys --name=lv_data --fstype=xfs --size=1 --grow
EOF
fi
%end
在命令段里引用生成的分区文件:
%include /tmp/part-include
用途二:按 MAC 地址判断机器角色
%pre --log=/tmp/ks-pre.log
#!/bin/sh
MAC=$(ip link show | awk '/link\/ether/{print $2; exit}' | tr -d ':')
case "${MAC}" in
000c29aabbcc)
echo "network --bootproto=static --device=eth0 --ip=192.168.100.51 --netmask=255.255.255.0 --gateway=192.168.100.1 --nameserver=223.5.5.5 --hostname=db01" > /tmp/net-include
echo "ROLE=db" > /tmp/role
;;
000c29ddeeff)
echo "network --bootproto=static --device=eth0 --ip=192.168.100.52 --netmask=255.255.255.0 --gateway=192.168.100.1 --nameserver=223.5.5.5 --hostname=web01" > /tmp/net-include
echo "ROLE=web" > /tmp/role
;;
*)
echo "network --bootproto=dhcp --device=eth0 --onboot=yes" > /tmp/net-include
echo "ROLE=default" > /tmp/role
;;
esac
%end
%include /tmp/net-include
%pre里的/tmp与后续安装环境是同一个 ramdisk,因此写在/tmp下的文件在%post(不加--nochroot时需通过/mnt/sysimage换算)中依然可访问。
7.7 %post 段(安装后脚本)
%post 在软件包全部装完、系统已经成型、重启之前执行。这是"装机 + 初始化一体化"的关键,能省掉装完机再逐台跑初始化脚本的工作。
参数说明:
| 参数 | 说明 |
|---|---|
| (默认,无参数) | 在 chroot 环境中执行,即根目录已经是新装系统的 /,可以直接 yum install、写 /etc/xxx |
--nochroot |
在安装环境中执行,新系统挂在 /mnt/sysimage 下。用于需要访问安装介质或把安装环境的文件拷进新系统的场景 |
--log=/root/ks-post.log |
把脚本的输出记录到日志(强烈建议一定加,否则 %post 出错你完全不知道发生了什么) |
--interpreter=/usr/bin/python |
换用其他解释器 |
--erroronfail |
脚本失败时中断安装并报错(默认是忽略失败继续) |
--nochroot 用法示例(把安装源里的文件拷到新系统):
%post --nochroot --log=/mnt/sysimage/root/ks-post-nochroot.log
#!/bin/bash
# 此时新系统的根在 /mnt/sysimage
cp /tmp/role /mnt/sysimage/root/role
cp -a /run/install/repo/extra/ /mnt/sysimage/opt/ 2>/dev/null
%end
完整的系统初始化 %post 实例(生产可直接参考):
%post --log=/root/ks-post.log
#!/bin/bash
set -x
# ============ 1. 配置内网 yum 源 ============
mkdir -p /etc/yum.repos.d/bak
mv /etc/yum.repos.d/CentOS-*.repo /etc/yum.repos.d/bak/ 2>/dev/null
cat > /etc/yum.repos.d/local.repo <<'EOF'
[base]
name=CentOS-$releasever - Base - Local Mirror
baseurl=http://192.168.100.10/centos7/
enabled=1
gpgcheck=0
[epel]
name=Extra Packages for Enterprise Linux 7 - Local Mirror
baseurl=http://192.168.100.10/epel7/
enabled=1
gpgcheck=0
EOF
yum clean all
yum makecache
# ============ 2. 安装常用工具 ============
yum -y install vim wget curl net-tools lsof tcpdump sysstat iotop htop \
tree lrzsz unzip zip bash-completion telnet nmap-ncat \
chrony rsync git psmisc dstat
# ============ 3. 优化 sshd ============
cp /etc/ssh/sshd_config /etc/ssh/sshd_config.bak
sed -i 's/^#\?UseDNS.*/UseDNS no/' /etc/ssh/sshd_config
sed -i 's/^#\?GSSAPIAuthentication.*/GSSAPIAuthentication no/' /etc/ssh/sshd_config
sed -i 's/^#\?PermitRootLogin.*/PermitRootLogin yes/' /etc/ssh/sshd_config
sed -i 's/^#\?Port 22/Port 22/' /etc/ssh/sshd_config
systemctl enable sshd
# ============ 4. 注入运维公钥(免密登录,Ansible 的前提)============
mkdir -p /root/.ssh
chmod 700 /root/.ssh
cat > /root/.ssh/authorized_keys <<'EOF'
ssh-rsa AAAAB3NzaC1yc2EAAAADAQABAAABgQC... ops@jumpserver
EOF
chmod 600 /root/.ssh/authorized_keys
restorecon -R /root/.ssh 2>/dev/null
# ============ 5. 关闭无用服务 ============
for svc in postfix firewalld NetworkManager avahi-daemon cups bluetooth \
abrtd abrt-ccpp kdump rpcbind; do
systemctl disable ${svc} >/dev/null 2>&1
systemctl stop ${svc} >/dev/null 2>&1
done
# ============ 6. 关闭 SELinux(如 ks 中未关)============
setenforce 0 2>/dev/null
sed -i 's/^SELINUX=.*/SELINUX=disabled/' /etc/selinux/config
# ============ 7. 时间同步 ============
sed -i '/^server /d' /etc/chrony.conf
cat >> /etc/chrony.conf <<'EOF'
server ntp1.aliyun.com iburst
server ntp2.aliyun.com iburst
server 192.168.100.10 iburst
EOF
systemctl enable chronyd
timedatectl set-timezone Asia/Shanghai
# ============ 8. 内核与系统参数优化 ============
cat >> /etc/sysctl.conf <<'EOF'
net.ipv4.tcp_syncookies = 1
net.ipv4.tcp_tw_reuse = 1
net.ipv4.ip_local_port_range = 10000 65000
net.ipv4.tcp_max_syn_backlog = 8192
net.core.somaxconn = 32768
net.ipv6.conf.all.disable_ipv6 = 1
net.ipv6.conf.default.disable_ipv6 = 1
vm.swappiness = 10
fs.file-max = 655350
EOF
sysctl -p >/dev/null 2>&1
# ============ 9. 文件描述符限制 ============
cat >> /etc/security/limits.conf <<'EOF'
* soft nofile 65535
* hard nofile 65535
* soft nproc 65535
* hard nproc 65535
EOF
# ============ 10. 历史命令记录时间戳 & 中文环境 ============
cat >> /etc/profile <<'EOF'
export HISTTIMEFORMAT="%F %T `whoami` "
export HISTSIZE=10000
EOF
# ============ 11. 按 %pre 判定的角色做差异化初始化 ============
if [ -f /root/role ]; then
. /root/role
case "${ROLE}" in
db) yum -y install mariadb-server ;;
web) yum -y install nginx ;;
esac
fi
# ============ 12. 打标记,便于确认装机来源 ============
echo "Installed by PXE+Kickstart at $(date '+%F %T')" > /etc/motd
echo "Installed by PXE+Kickstart at $(date '+%F %T')" > /root/.install-stamp
# ============ 13. 简单的 %post 验证文件(源文档示例)============
touch /tmp/123
touch /root/123
mkdir -p /root/Desktop && touch /root/Desktop/123
%end
%post里执行yum install的前提是新系统已经能连通 yum 源。如果 ks 里network --onboot=no或者内网源地址不通,%post里的 yum 会全部失败(而且默认不会中断安装,你看不到报错)。所以:① 一定加--log=;② 装完后先cat /root/ks-post.log检查。
%post中做的初始化配置,也可以交给配置管理工具在装机后统一处理,这样 ks 文件能保持简洁、变更更易审计。 详见 14-02-Ansible自动化部署.md 详见 14-04-SaltStack配置管理.md
7.8 %addon 段与 kdump
%addon com_redhat_kdump --enable --reserve-mb='auto'
%end
# 明确不启用 kdump(最小化机器可省内存)
%addon com_redhat_kdump --disable
%end
其他常见 addon:
# RHEL 的安全基线(OpenSCAP)
%addon org_fedora_oscap
content-type = scap-security-guide
profile = xccdf_org.ssgproject.content_profile_pci-dss
%end
每个
%addon、%packages、%pre、%post段都必须以%end闭合。CentOS 7 起漏写%end会直接报语法错误,安装停在交互界面。
7.9 语法检查:ksvalidator
在把 ks 文件放上服务器之前,一定要先做语法检查,这一步能拦掉 80% 的"装机停在交互界面"问题。
# 安装
yum -y install pykickstart
# 检查(不指定版本时按当前系统版本校验)
ksvalidator /var/www/html/ks/ks.cfg
# 指定目标系统版本校验(不同版本语法有差异,必须对版本)
ksvalidator -v RHEL6 /var/www/html/ks/centos6.cfg
ksvalidator -v RHEL7 /var/www/html/ks/centos7.cfg
ksvalidator -v RHEL8 /var/www/html/ks/rocky8.cfg
# 列出所有支持的版本
ksvalidator -l
# 检查 URL 上的 ks 文件(顺便验证 URL 是否可访问,一举两得)
ksvalidator http://192.168.100.10/ks/ks.cfg
# 忽略过时选项警告
ksvalidator -e /var/www/html/ks/ks.cfg
无错误时没有任何输出(Unix 风格的"沉默即成功")。有错误时会给出行号和原因,例如:
The following problem occurred on line 23 of the kickstart file:
Unknown command: parti
pykickstart 附带的其他工具:
ksflatten -c ks.cfg -o flat.cfg # 把 %include 展开成一个完整文件
ksverdiff -f RHEL6 -t RHEL7 # 对比两个版本之间的 ks 语法差异,升级时非常有用
八、提供安装源与 ks 文件
TFTP 只传引导文件,几个 GB 的 Packages 必须用 HTTP / FTP / NFS 之一发布。
8.1 用 httpd 发布(推荐)
yum -y install httpd
# 方式一:把镜像挂载点直接软链到 web 根目录
mkdir -p /var/www/html
ln -s /mnt/cdrom /var/www/html/centos7
# 方式二(更推荐):把镜像内容整体拷到 web 目录(约 4~9G,避免挂载点意外卸载导致装机中断)
mkdir -p /var/www/html/centos7
cp -a /mnt/cdrom/. /var/www/html/centos7/
# 或者用 mount --bind
mount --bind /mnt/cdrom /var/www/html/centos7
echo '/mnt/cdrom /var/www/html/centos7 none bind 0 0' >> /etc/fstab
# 允许目录列表(便于浏览器验证)
cat > /etc/httpd/conf.d/pxe.conf <<'EOF'
<Directory "/var/www/html/centos7">
Options +Indexes +FollowSymLinks
AllowOverride None
Require all granted
</Directory>
<Directory "/var/www/html/ks">
Options +Indexes
AllowOverride None
Require all granted
# 生产环境建议限制来源网段
# Require ip 192.168.100.0/24
</Directory>
EOF
# CentOS 7
systemctl start httpd
systemctl enable httpd
# CentOS 6
service httpd start
chkconfig httpd on
用软链接方式发布时,若 SELinux 未关闭,必须额外允许:
setsebool -P httpd_read_user_content on并chcon -R -t httpd_sys_content_t /var/www/html/,否则客户端会报 403 / 找不到安装源。
详见 10-01-Apache服务.md
8.2 用 vsftpd 发布
yum -y install vsftpd
mkdir -p /var/ftp/centos7
mount --bind /mnt/cdrom /var/ftp/centos7
# 或 cp -a /mnt/cdrom/. /var/ftp/centos7/
# CentOS 7
systemctl start vsftpd && systemctl enable vsftpd
# CentOS 6
service vsftpd start && chkconfig vsftpd on
# 验证
ftp 192.168.100.10 # 用 anonymous 匿名登录,应能看到 centos7 目录
curl ftp://192.168.100.10/centos7/
ks 中对应写法:url --url="ftp://192.168.100.10/centos7"
详见 09-03-FTP服务.md
8.3 用 NFS 发布
yum -y install nfs-utils rpcbind
mkdir -p /nfsshare/centos7
mount --bind /mnt/cdrom /nfsshare/centos7
cat >> /etc/exports <<'EOF'
/nfsshare/centos7 192.168.100.0/24(ro,sync,no_root_squash)
EOF
# CentOS 7
systemctl start rpcbind nfs-server
systemctl enable rpcbind nfs-server
exportfs -rv
# CentOS 6
service rpcbind start && service nfs start
chkconfig rpcbind on && chkconfig nfs on
exportfs -rv
# 验证
showmount -e 192.168.100.10
ks 中对应写法:nfs --server=192.168.100.10 --dir=/nfsshare/centos7
详见 09-02-NFS与autofs.md
8.4 三者对比与选型
| 协议 | 端口 | 优点 | 缺点 | 推荐度 |
|---|---|---|---|---|
| HTTP | TCP 80 | 单端口、防火墙最好放行、浏览器/curl 就能验证、并发能力强、可直接用 CDN/反代扩展、ks 文件和安装源可共用一个服务 | 无(对装机场景几乎没有短板) | ★★★★★ 首选 |
| FTP | TCP 21 + 数据端口 | 传统方案,老文档多 | 被动模式需要放行一大段随机端口,防火墙/NAT 环境下麻烦;匿名访问配置易出错 | ★★☆ |
| NFS | 2049 + rpcbind 111 | 大文件传输效率高,服务端可直接 bind 挂载 | 依赖 rpcbind,端口多且部分随机,防火墙难放行;跨网段/跨机房不友好;权限模型复杂 | ★★☆ |
推荐 HTTP 的原因:一个 80 端口同时解决"安装源"和"ks 文件"两件事,防火墙只需放行一条规则,且可以用 curl 从任何位置一秒验证是否可达——这个可验证性在排错时价值极高。Cobbler 内部也正是用 httpd 来发布 ks_mirror 和 ks 文件的。
8.5 把 ks.cfg 放到 web 目录并验证(最容易忘的一步)
mkdir -p /var/www/html/ks
cp /root/anaconda-ks.cfg /var/www/html/ks/ks.cfg
chmod 644 /var/www/html/ks/ks.cfg
# SELinux 未关时
restorecon -Rv /var/www/html/
必须做的验证(在服务端和另一台机器上都做一遍):
# 1. ks 文件能取到,且内容正确
curl http://192.168.100.10/ks/ks.cfg
curl -I http://192.168.100.10/ks/ks.cfg # 应返回 200 OK
# 2. 安装源目录能访问,且 repodata 存在
curl -I http://192.168.100.10/centos7/
curl -I http://192.168.100.10/centos7/repodata/repomd.xml # 必须 200
curl -s http://192.168.100.10/centos7/ | head
# 3. 引导文件能通过 tftp 取到
tftp 192.168.100.10 -c get pxelinux.0
# 4. ks 语法与 URL 一起校验
ksvalidator http://192.168.100.10/ks/ks.cfg
这一步的价值:客户端 anaconda 报"找不到 ks 文件"或"找不到安装源"时,99% 是因为这两个 URL 在服务端就不通(打错路径、httpd 没启、SELinux 拦了、防火墙没放行)。先在服务端 curl 通了再去装机,能省掉一轮虚拟机启动的等待时间。
九、完整实战:手工搭建 PXE + Kickstart
下面把前面各步串成一份可复现的完整操作清单,在一台干净的 CentOS 7 上从头到尾执行即可。
9.1 服务端操作清单
# ========== 步骤 0:环境准备 ==========
# 服务端固定 IP 192.168.100.10/24,网络模式为"仅主机"或"私有网络"
# 确认虚拟化平台自带的 DHCP 已关闭!
hostnamectl set-hostname pxe-server
nmcli connection modify eth0 ipv4.method manual ipv4.addresses 192.168.100.10/24 \
ipv4.gateway 192.168.100.1 ipv4.dns 223.5.5.5 connection.autoconnect yes
nmcli connection up eth0
systemctl stop firewalld && systemctl disable firewalld
setenforce 0
sed -i 's/^SELINUX=enforcing/SELINUX=disabled/' /etc/selinux/config
# ========== 步骤 1:挂载镜像 + 配本地 yum 源 ==========
mkdir -p /mnt/cdrom
mount -o loop /root/CentOS-7-x86_64-DVD-1611.iso /mnt/cdrom
echo '/root/CentOS-7-x86_64-DVD-1611.iso /mnt/cdrom iso9660 loop,defaults 0 0' >> /etc/fstab
mkdir -p /etc/yum.repos.d/bak && mv /etc/yum.repos.d/*.repo /etc/yum.repos.d/bak/
cat > /etc/yum.repos.d/local.repo <<'EOF'
[local]
name=CentOS-Local-DVD
baseurl=file:///mnt/cdrom
enabled=1
gpgcheck=0
EOF
yum clean all && yum repolist
# ========== 步骤 2:安装全部所需软件 ==========
yum -y install dhcp tftp-server tftp syslinux httpd pykickstart xinetd
# ========== 步骤 3:配置 DHCP ==========
cat > /etc/dhcp/dhcpd.conf <<'EOF'
ddns-update-style none;
ignore client-updates;
allow booting;
allow bootp;
default-lease-time 21600;
max-lease-time 43200;
subnet 192.168.100.0 netmask 255.255.255.0 {
range 192.168.100.100 192.168.100.200;
option routers 192.168.100.10;
option subnet-mask 255.255.255.0;
option domain-name-servers 192.168.100.10;
next-server 192.168.100.10;
filename "pxelinux.0";
}
EOF
dhcpd -t -cf /etc/dhcp/dhcpd.conf # 语法检查
systemctl restart dhcpd && systemctl enable dhcpd
ss -anup | grep :67
# ========== 步骤 4:配置 TFTP ==========
# CentOS 7
systemctl start tftp.socket && systemctl enable tftp.socket
# CentOS 6 则改为:
# sed -i '/disable/s/yes/no/' /etc/xinetd.d/tftp ; service xinetd restart ; chkconfig xinetd on
ss -anup | grep :69
# ========== 步骤 5:准备引导文件 ==========
cp /usr/share/syslinux/pxelinux.0 /var/lib/tftpboot/
cp /usr/share/syslinux/menu.c32 /var/lib/tftpboot/
cp /usr/share/syslinux/vesamenu.c32 /var/lib/tftpboot/
cp /mnt/cdrom/images/pxeboot/vmlinuz /var/lib/tftpboot/
cp /mnt/cdrom/images/pxeboot/initrd.img /var/lib/tftpboot/
cp /mnt/cdrom/isolinux/boot.msg /var/lib/tftpboot/
cp /mnt/cdrom/isolinux/splash.png /var/lib/tftpboot/ 2>/dev/null
mkdir -p /var/lib/tftpboot/pxelinux.cfg
cat > /var/lib/tftpboot/pxelinux.cfg/default <<'EOF'
default vesamenu.c32
timeout 100
prompt 0
display boot.msg
menu background splash.png
menu title CentOS 7 PXE Install Menu
label local
menu label Boot from ^local drive
menu default
localboot 0xffff
label auto
menu label ^Auto Install CentOS 7 (Kickstart)
kernel vmlinuz
append initrd=initrd.img inst.repo=http://192.168.100.10/centos7 inst.ks=http://192.168.100.10/ks/ks.cfg text quiet
label manual
menu label ^Manual Install CentOS 7
kernel vmlinuz
append initrd=initrd.img inst.repo=http://192.168.100.10/centos7
EOF
chmod -R 644 /var/lib/tftpboot/* ; chmod 755 /var/lib/tftpboot/pxelinux.cfg
tftp 192.168.100.10 -c get pxelinux.0 && echo "TFTP OK"
# ========== 步骤 6:用 httpd 发布安装源 ==========
mkdir -p /var/www/html/centos7 /var/www/html/ks
mount --bind /mnt/cdrom /var/www/html/centos7
echo '/mnt/cdrom /var/www/html/centos7 none bind 0 0' >> /etc/fstab
systemctl restart httpd && systemctl enable httpd
curl -I http://192.168.100.10/centos7/repodata/repomd.xml
# ========== 步骤 7:编写 ks 文件 ==========
cat > /var/www/html/ks/ks.cfg <<'EOF'
#platform=x86, AMD64, or Intel EM64T
#version=DEVEL
install
text
skipx
eula --agreed
firstboot --disable
reboot
url --url="http://192.168.100.10/centos7"
lang en_US.UTF-8
keyboard --vckeymap=us --xlayouts='us'
timezone Asia/Shanghai --utc
rootpw --iscrypted $1$lCWjtTge$uuB/0hPOI.n25entF4ghI0
user --name=devops --groups=wheel --iscrypted --password=$1$lCWjtTge$uuB/0hPOI.n25entF4ghI0
auth --useshadow --passalgo=sha512
selinux --disabled
firewall --disabled
network --bootproto=dhcp --device=eth0 --onboot=yes --noipv6
bootloader --location=mbr --boot-drive=sda --append="net.ifnames=0 biosdevname=0 rhgb quiet"
ignoredisk --only-use=sda
zerombr
clearpart --all --initlabel --drives=sda
part /boot --fstype=xfs --size=1024 --asprimary --ondisk=sda
part swap --fstype=swap --size=2048 --asprimary --ondisk=sda
part / --fstype=xfs --size=1 --grow --asprimary --ondisk=sda
%packages --nobase --ignoremissing
@^minimal
@core
vim-enhanced
net-tools
wget
curl
lsof
tcpdump
tree
lrzsz
bash-completion
chrony
-postfix
-firewalld
%end
%post --log=/root/ks-post.log
#!/bin/bash
sed -i 's/^#\?UseDNS.*/UseDNS no/' /etc/ssh/sshd_config
sed -i 's/^#\?GSSAPIAuthentication.*/GSSAPIAuthentication no/' /etc/ssh/sshd_config
systemctl enable sshd
systemctl disable postfix 2>/dev/null
echo "Installed by PXE+Kickstart at $(date '+%F %T')" > /etc/motd
touch /root/.install-stamp
%end
EOF
# ========== 步骤 8:语法与可访问性校验 ==========
ksvalidator -v RHEL7 /var/www/html/ks/ks.cfg && echo "KS syntax OK"
curl http://192.168.100.10/ks/ks.cfg | head
9.2 客户端操作与验证
1. 新建一台虚拟机(内存 ≥ 2G,硬盘 ≥ 20G,不挂载任何 ISO)
- 网络必须与服务端在同一个"仅主机/私有"网段
- 固件类型选 BIOS / Legacy(先跑通 BIOS,UEFI 后面再说)
2. 进入 BIOS/固件设置,把 Network Boot / PXE 调到第一启动顺序
(VMware 中开机瞬间按 F2 进 BIOS,或按 ESC 选择"Network boot from ...")
若网络引导失败,请在客户端虚拟机中调整启动顺序,优先从网络启动
3. 开机后应依次看到:
a) 网卡固件输出 "CLIENT MAC ADDR: ... GUID: ..."
b) "DHCP.../ CLIENT IP: 192.168.100.101 MASK: 255.255.255.0"
GATEWAY IP: 192.168.100.10 ← DHCP 阶段成功
c) "PXE->EB: !PXE at ... Downloading NBP file..."
TFTP 传输进度条 ← TFTP 取 pxelinux.0 成功
d) 出现自定义的 "CentOS 7 PXE Install Menu" 菜单 ← 菜单文件读取成功
e) 选中 "Auto Install CentOS 7 (Kickstart)" 回车
f) 屏幕滚动内核启动信息,加载 vmlinuz / initrd.img
g) 出现 anaconda 文本安装界面,直接跳过所有提问,
开始 "Starting package installation process" ← ks 生效
h) 软件包安装进度走完 → 执行 %post → 自动 reboot
4. 服务端同步观察(三个窗口同时看,排错效率最高):
tail -f /var/log/messages # DHCP 分配记录
tail -f /var/log/httpd/access_log # 能看到客户端 GET /ks/ks.cfg 与大量 GET /centos7/Packages/xxx.rpm
tcpdump -i eth0 -nn port 67 or port 69 # DHCP/TFTP 报文
5. 装完验证:
- 客户端能用 ks 里设置的 root 密码登录
- cat /etc/motd 能看到装机时间戳
- cat /root/ks-post.log 检查 %post 是否全部成功
- lsblk / df -h 确认分区符合 ks 中的规划
- 客户端重启后应从本地硬盘启动(若又进了 PXE,见前文 reboot 循环的三种解法)
客户端调试小技巧:在 anaconda 阶段按 Ctrl+Alt+F2 可以切到 shell(tty2),Ctrl+Alt+F3/F4/F5 分别是安装日志、存储日志、程序日志。在 tty2 里可以直接:
ip a # 看客户端实际拿到的 IP
ping 192.168.100.10 # 通不通
curl http://192.168.100.10/ks/ks.cfg # ks 能不能取到(最有价值的一条)
curl -I http://192.168.100.10/centos7/repodata/repomd.xml # 安装源能不能取到
cat /tmp/anaconda.log ; cat /tmp/syslog ; cat /tmp/storage.log
9.3 手工方案的痛点
跑通一遍后回头看,手工方案的问题非常明显:
| 痛点 | 具体表现 |
|---|---|
| 配置分散在四五个服务里 | dhcpd.conf、xinetd/tftp、tftpboot/pxelinux.cfg/default、httpd 配置、ks.cfg——改一处装机方案往往要同时动两三个文件,且它们之间的 IP、路径必须手工保持一致 |
| 多版本多架构管理困难 | 加一个 CentOS 6 就要新建 images 子目录、拷一份内核 initrd、加一段菜单、再写一份 ks;架构(i386/x86_64)、BIOS/UEFI 组合起来是笛卡尔积式的膨胀 |
| 每次改动要手工同步 | 换了服务端 IP,要同时改 dhcpd.conf 的 next-server、default 里的 inst.repo 与 inst.ks、ks 里的 url,漏一处就装机失败 |
| 按 MAC 差异化难以维护 | 每台机器一个 pxelinux.cfg/01-xx-xx-... 文件,几十台机器就是几十个文件,还要人工记录 MAC 与角色的对应关系 |
| 没有集中的状态视图 | 无法回答"当前支持哪些系统版本""哪台机器绑的是哪个方案""这批机器装成功了几台" |
| 易错点多 | 前面每一节都有各自的坑(disable=no、restorecon、--drives、%end、ks URL),任何一个漏掉就是一次失败的装机尝试 |
| 无 API 无可视化 | 无法与 CMDB、工单系统、Ansible 联动 |
这些痛点正是 Cobbler 要解决的:把 DHCP、TFTP、HTTP、Kickstart、rsync 统一封装起来,用一套命令管理,配置文件由它自动生成。
十、Cobbler 是什么
Cobbler 是一个用 Python 编写的 Linux 系统安装与配置管理平台,它并不重新实现 PXE,而是把 DHCP、TFTP、HTTP、Kickstart、rsync、DNS 这些服务统一封装管理起来。
它的核心价值只有一句话:你只维护 Cobbler 里的对象(distro/profile/system),Cobbler 负责自动生成上述各服务的配置文件。
具体来说,一次 cobbler sync 会自动完成:
- 生成
/etc/dhcp/dhcpd.conf(含 next-server、filename、按 MAC 的 host 段) - 生成
/var/lib/tftpboot/pxelinux.cfg/default以及每台机器的01-MAC专属菜单 - 把内核 vmlinuz 与 initrd.img 摆放到
/var/lib/tftpboot/images/<distro>/下 - 通过 httpd 发布
/var/www/cobbler/ks_mirror/(安装源)与动态渲染的 ks 文件 - 生成 UEFI 所需的 grub 目录结构(较新版本)
提供三种使用方式:
- CLI:
cobbler <object> <action>,是最主要的操作方式 - Web UI:cobbler-web,浏览器管理,适合非专职人员和演示
- XML-RPC API:
http://IP/cobbler_api,可被脚本、CMDB、自动化平台调用(koan 客户端就是通过它通信的)
无人值守安装的两条路线再对比一次:
- kickstart:
pxe + nfs/http/ftp + dhcp + tftp + ks.cfg - cobbler:在 kickstart 基础上进行封装,提供更便捷的管理方式
十一、Cobbler 架构与核心概念
11.1 核心对象
| 对象 | 含义 | 说明 |
|---|---|---|
| distro(发行版/镜像) | 一个操作系统发行版,记录内核 vmlinuz、初始内存盘 initrd、架构、安装源路径、默认内核参数 | 由 cobbler import 从 ISO 自动生成,一般不手工创建 |
| profile(配置档/安装方案) | = 一个 distro + 一个 kickstart 文件 + 一组内核参数 | 一个 distro 可对应多个 profile(同一个 CentOS 7 镜像,可以有"最小化""数据库节点""桌面版"多个方案) |
| system(系统/具体主机) | 一台具体的机器,按 MAC 地址绑定到某个 profile,可单独指定 IP、网关、主机名、ks 覆盖参数 | 生产环境最有价值的对象,实现"不同机器装不同系统" |
| repo(仓库) | 一个 yum 仓库的镜像定义,用 reposync 同步到本地 |
关联到 profile 后,装机完成的系统会自动指向内网源 |
| image | 直接引导一个已有的镜像文件(ISO/裸镜像/虚拟机镜像),不走 distro 那套内核+initrd 的路子 | 用于引导 ISO、内存诊断工具等 |
| mgmtclass(管理类) | 管理分类,把一组配置管理(Puppet/Chef)的类与参数挂到 profile/system 上 | 与 Puppet 联动时使用 |
11.2 层级关系
┌───────────────────────────────┐
│ distro: centos7.3-x86_64 │ ← cobbler import 生成
│ kernel : .../vmlinuz │ 记录内核与 initrd
│ initrd : .../initrd.img │
└───────────────┬───────────────┘
│ 一个 distro 可派生多个 profile
┌─────────────────────┼─────────────────────┐
▼ ▼ ▼
┌────────────────────┐ ┌────────────────────┐ ┌────────────────────┐
│ profile: c7-min │ │ profile: c7-db │ │ profile: c7-desktop│
│ ks: minimal.ks │ │ ks: db-lvm.ks │ │ ks: desktop.ks │
│ kopts: text │ │ kopts: ... │ │ repos: [epel] │
└─────────┬──────────┘ └─────────┬──────────┘ └────────────────────┘
│ 一个 profile 可绑定多台 system
┌──────┴──────┐ ┌─────┴─────┐
▼ ▼ ▼ ▼
┌──────────┐ ┌──────────┐ ┌──────────┐ ┌──────────┐
│ web01 │ │ web02 │ │ db01 │ │ db02 │
│ mac:..aa │ │ mac:..bb │ │ mac:..cc │ │ mac:..dd │ ← system,按 MAC 绑定
│ ip:.51 │ │ ip:.52 │ │ ip:.61 │ │ ip:.62 │ 可各自指定固定 IP
└──────────┘ └──────────┘ └──────────┘ └──────────┘
repo(本地 yum 镜像)──── 关联 ──→ profile (--repos=epel,base)
继承规则:system 的设置覆盖 profile,profile 的设置覆盖 distro。没有对应 system 的机器(未登记 MAC)会看到 PXE 菜单,从中手工选一个 profile。
十二、Cobbler 安装
实验环境中 Cobbler 服务器地址为 3.3.3.4/24。
cobbler server (3.3.3.4/24) ------- client
12.1 第一步:安装 Cobbler 相关软件包
需要 EPEL 源、local 源、CentOS 163 源。由于实验使用私有网络,而私有网络无法连接共享源,可先使用桥接网络安装软件包,再切换为私有网络。
yum -y install epel-release
yum install cobbler cobbler-web tftp tftp-server rsync xinetd httpd httpd-devel httpd-tools syslinux dhcp dhcp-common dhcp-libs pykickstart fence-agents debmirror system-config-kickstart -y
各包的作用:
| 软件包 | 作用 |
|---|---|
| cobbler | 主程序、cobblerd 守护进程、cobbler CLI |
| cobbler-web | Web 管理界面(Django 应用,跑在 httpd 里) |
| tftp / tftp-server | 传输引导文件 |
| xinetd | CentOS 6/7 早期版本下托管 tftp |
| httpd + httpd-devel + httpd-tools | 发布安装源、ks 文件、Web UI;htdigest 来自 httpd-tools |
| dhcp / dhcp-common / dhcp-libs | DHCP 服务 |
| syslinux | 提供 pxelinux.0、menu.c32 等引导文件 |
| rsync | 镜像同步、replicate 多机房复制 |
| pykickstart | ksvalidator 语法校验 |
| fence-agents | 电源管理(远程开关机装机) |
| debmirror | 同步 Debian/Ubuntu 源(不用也建议装,否则 cobbler check 会报) |
| system-config-kickstart | 图形化生成 ks 文件 |
12.2 第二步:启动服务并执行 cobbler check
systemctl restart cobblerd.service
systemctl restart httpd.service
systemctl enable cobblerd.service
systemctl enable httpd.service
httpd 必须先起来,因为
cobbler check、cobbler import等操作是通过http://IP/cobbler_api这个 XML-RPC 接口进行的。httpd 没起会报ProtocolError ... 503 Service Unavailable。
使用 cobbler check 查看需要修改的配置项:
cobbler check
典型输出如下:
The following are potential configuration items that you may want to fix:
1 : The 'server' field in /etc/cobbler/settings must be set to something other than localhost, or kickstarting features will not work. This should be a resolvable hostname or IP for the boot server as reachable by all machines that will use it.
2 : For PXE to be functional, the 'next_server' field in /etc/cobbler/settings must be set to something other than 127.0.0.1, and should match the IP of the boot server on the PXE network.
3 : SELinux is enabled. Please review the following wiki page for details on ensuring cobbler works correctly in your SELinux environment:
https://github.com/cobbler/cobbler/wiki/Selinux
4 : change 'disable' to 'no' in /etc/xinetd.d/tftp
5 : Some network boot-loaders are missing from /var/lib/cobbler/loaders, you may run 'cobbler get-loaders' to download them, or, if you only want to handle x86/x86_64 netbooting, you may ensure that you have installed a *recent* version of the syslinux package installed and can ignore this message entirely. Files in this directory, should you want to support all architectures, should include pxelinux.0, menu.c32, elilo.efi, and yaboot. The 'cobbler get-loaders' command is the easiest way to resolve these requirements.
6 : enable and start rsyncd.service with systemctl
7 : comment out 'dists' on /etc/debmirror.conf for proper debian support
8 : comment out 'arches' on /etc/debmirror.conf for proper debian support
9 : The default password used by the sample templates for newly installed machines (default_password_crypted in /etc/cobbler/settings) is still set to 'cobbler' and should be changed, try: "openssl passwd -1 -salt 'random-phrase-here' 'your-password-here'" to generate new one
Restart cobblerd and then run 'cobbler sync' to apply changes.
12.3 第三步:按 cobbler check 逐项修改
这是 Cobbler 部署的核心环节,下面把每一项都讲清楚怎么改。
① server 字段改为本机真实 IP
server 是客户端访问 Cobbler 的地址,会被写进 ks 文件里的 url、%post 的源地址等。必须是所有待装机机器都能访问到的可解析主机名或 IP。
sed -i 384s/127.0.0.1/3.3.3.4/ /etc/cobbler/settings
也可以直接编辑(更稳妥,行号会随版本变化):
vim /etc/cobbler/settings
server: 3.3.3.4
② next_server 字段改为本机真实 IP
next_server 就是 DHCP 下发的 next-server,即 TFTP 服务器地址,必须与装机网段上的 boot server IP 一致。
sed -i 272s/127.0.0.1/3.3.3.4/ /etc/cobbler/settings
next_server: 3.3.3.4
多网卡服务端的高频坑:如果服务端有多块网卡(一块连办公网一块连装机网段),
server和next_server必须填装机网段那块网卡的 IP。填错了表现为:客户端能拿到 IP,但 TFTP 超时(PXE-E32),或者进了 anaconda 但取不到安装源。
③ 关闭 SELinux
setenforce 0
sed -i 's/^SELINUX=.*/SELINUX=disabled/' /etc/selinux/config
如果启用了 SELinux,请关闭。不想关的话需要参考 Cobbler 官方 wiki 配置一系列布尔值与文件上下文,实验环境不建议折腾。
④ /etc/xinetd.d/tftp 的 disable 改为 no
sed -i /disable/s/yes/no/ /etc/xinetd.d/tftp
改完需要重启 xinetd 才生效(见第六步)。CentOS 7 上如果 cobbler 版本较新且不依赖 xinetd,则改用 systemctl enable --now tftp.socket。
⑤ 下载引导文件 loader
cobbler get-loaders
该命令从 cobbler.github.io 下载各架构的网络引导程序到 /var/lib/cobbler/loaders/(包括 pxelinux.0、menu.c32、elilo.efi、yaboot、grub 相关文件)。
内网无外网时的手工处理方式(这个场景非常常见):
# 方式一:只做 x86/x86_64 网络引导时,装一个较新的 syslinux 即可忽略这条提示
yum -y install syslinux
# 方式二:手工从 syslinux 拷贝到 loaders 目录
mkdir -p /var/lib/cobbler/loaders
cp /usr/share/syslinux/pxelinux.0 /var/lib/cobbler/loaders/
cp /usr/share/syslinux/menu.c32 /var/lib/cobbler/loaders/
cp /usr/share/syslinux/ldlinux.c32 /var/lib/cobbler/loaders/ 2>/dev/null
# UEFI 需要的话,从安装镜像里取
cp /mnt/cdrom/EFI/BOOT/grubx64.efi /var/lib/cobbler/loaders/ 2>/dev/null
cp /mnt/cdrom/EFI/BOOT/BOOTX64.EFI /var/lib/cobbler/loaders/ 2>/dev/null
# 方式三:从有网的机器上跑一次 get-loaders,把 /var/lib/cobbler/loaders/ 整个打包拷过来
tar czf loaders.tar.gz -C /var/lib/cobbler loaders
⑥ 启动 rsyncd 服务
systemctl start rsyncd
systemctl restart rsyncd.service
systemctl enable rsyncd.service
rsyncd 用于 Cobbler 对外提供镜像树同步(cobbler replicate 从机拉取、客户端 rsync 取安装源)。不做多机房复制时其实用不到,但 cobbler check 会一直提示。
⑦⑧ 处理 debmirror 的 Debian 架构配置
vim /etc/debmirror.conf
把这两行注释掉:
# @dists="sid";
# @arches="i386";
sed -i 's/^@dists=/#@dists=/' /etc/debmirror.conf
sed -i 's/^@arches=/#@arches=/' /etc/debmirror.conf
原因:这两个变量在配置文件里被硬编码后,会覆盖命令行传入的发行版和架构,导致同步 Debian 源时永远只同步 sid/i386。即使不装 Debian,注释掉它们才能让 check 通过。
⑨ 修改默认 root 密码 default_password_crypted(这步不能跳过)
Cobbler 自带的 ks 模板里,新装机器的 root 密码来自 default_password_crypted,默认值就是 cobbler。不改的话你装出来的每一台机器 root 密码都是 cobbler,等于全网公开。
openssl passwd -1 -salt 'xcvsfdsdfwq' '123'
将生成的密码字符串写入 /etc/cobbler/settings 第 101 行,替换原有内容:
default_password_crypted: "$1$xcvsfdsd$cGxdcHuQGCnu5vJw5M7zX1"
# 一步到位的写法(自己换密码和 salt)
NEWPASS=$(openssl passwd -1 -salt "$(openssl rand -base64 6)" 'YourStrongPassword')
sed -i "s|^default_password_crypted:.*|default_password_crypted: \"${NEWPASS}\"|" /etc/cobbler/settings
grep default_password_crypted /etc/cobbler/settings
注意:生成的哈希串里含有
$、/等字符,用sed替换时要注意转义或改用|作分隔符;用 vim 手工粘贴最稳妥。
⑩ (可选但推荐)manage_dhcp 设为 1,把 DHCP 交给 Cobbler 管理
sed -i 242s/0/1/ /etc/cobbler/settings
manage_dhcp: 1
设为 1 后,cobbler sync 会根据模板自动生成 /etc/dhcp/dhcpd.conf 并重启 dhcpd,这才是 Cobbler "统一管理"的精髓。设为 0 则你要自己维护 dhcpd.conf。
相关的其他开关:
manage_dhcp: 1 # 管理 DHCP
manage_dns: 0 # 管理 DNS(bind/dnsmasq),需要时置 1
manage_tftpd: 1 # 管理 tftpd
manage_rsync: 0 # 管理 rsyncd
restart_dhcp: 1 # sync 后自动重启 dhcpd
pxe_just_once: 1 # 装完一次后自动关闭该机器的 netboot,避免无限重装(强烈建议置 1)
next_server: 3.3.3.4
server: 3.3.3.4
每修一项后重启 cobblerd 并再次检查:
systemctl restart cobblerd.service
cobbler check
当看到以下输出时表示配置完成:
No configuration problems found. All systems go.
最后执行一次同步让改动生效:
cobbler sync
十三、导入系统镜像
13.1 第四步:导入 CentOS 7.3 ISO 镜像
将 CentOS 7.3 的 ISO 镜像挂载到 /yum 目录,然后执行导入:
mkdir -p /yum
mount -o loop /root/CentOS-7-x86_64-DVD-1611.iso /yum
# 或挂物理/虚拟光驱
mount /dev/cdrom /yum
cobbler import --path=/yum/ --name=centos7.3
完整参数写法:
cobbler import --path=/yum/ --name=centos7.3 --arch=x86_64
cobbler import --path=/yum/ --name=centos6.9 --arch=x86_64 --breed=redhat --os-version=rhel6
| 参数 | 说明 |
|---|---|
--path |
镜像挂载点,或已解压的安装树目录,也可以是 rsync:// / ssh:// 远程路径 |
--name |
给这个镜像起的名字。最终生成的 distro 名会自动拼上架构后缀,如 centos7.3-x86_64 |
--arch |
架构:x86_64 / i386 / ppc / arm。不指定时 Cobbler 会自动探测 |
--breed |
发行版系族:redhat / debian / ubuntu / suse |
--os-version |
具体版本,如 rhel6 / rhel7,影响 ks 模板的渲染 |
--available-as |
镜像已在别处通过 http/nfs 发布时,只建立引用而不拷贝(省空间) |
耗时与空间说明:cobbler import 会把整个镜像内容逐文件拷贝到 /var/www/cobbler/ks_mirror/<name>-<arch>/,一张 CentOS 7 DVD 约 4.3G,机械盘上通常需要 3~10 分钟,期间终端会持续输出 copying files 之类的日志,不要以为卡死了就 Ctrl+C。
空间占用提醒:每导入一个镜像就多占一份完整镜像的空间(4~9G)。同时维护 CentOS 6/7/8 三个版本就是 15G 以上,
/var分区必须留足空间。空间紧张时用--available-as参数避免拷贝,或者把/var/www/cobbler/ks_mirror单独挂一个大分区/LV。
检查导入过程是否有错误:
cobbler validateks
如果导入时出现
ProtocolError: <ProtocolError for 3.3.3.4:80/cobbler_api: 503 Service Unavailable>报错,说明 SELinux 未关闭,关闭后重启服务器再重试。(另一个常见原因是 httpd 没启动或 cobblerd 没启动。)
13.2 导入后自动生成的对象
一次 import 会自动生成一个 distro 和一个同名 profile:
确认导入的镜像名和默认 profile:
cobbler distro list
centos7.3-x86_64
cobbler profile list
centos7.3-x86_64
一个镜像名(distro)可以对应多个安装方案(profile)。
查看详细信息:
cobbler distro report --name=centos7.3-x86_64
Name : centos7.3-x86_64
Architecture : x86_64
Breed : redhat
Comment :
Initrd : /var/www/cobbler/ks_mirror/centos7.3-x86_64/images/pxeboot/initrd.img
Kernel : /var/www/cobbler/ks_mirror/centos7.3-x86_64/images/pxeboot/vmlinuz
Kernel Options : {}
Kernel Options (Post Install) : {}
Kickstart Metadata : {'tree': 'http://@@http_server@@/cblr/links/centos7.3-x86_64'}
Management Classes : []
OS Version : rhel7
Owners : ['admin']
Red Hat Management Key : <<inherit>>
Template Files : {}
cobbler profile report --name=centos7.3-x86_64
Name : centos7.3-x86_64
TFTP Boot Files : {}
Comment :
DHCP Tag : default
Distribution : centos7.3-x86_64
Enable gPXE? : 0
Enable PXE Menu? : 1
Kernel Options : {}
Kickstart : /var/lib/cobbler/kickstarts/sample_end.ks
Kickstart Metadata : {}
...
# 查看某个 profile 使用的 kickstart 文件
cobbler profile report --name=centos7.3-x86_64 | grep Kickstart
Kickstart : /var/lib/cobbler/kickstarts/sample_end.ks
Kickstart Metadata : {}
导入后镜像会被放置到 /var/www/cobbler/ks_mirror/ 目录中,并通过 httpd 发布:
ls /var/www/cobbler/ks_mirror/
# centos7.3-x86_64 config
# 可通过浏览器/curl 验证
curl -I http://3.3.3.4/cobbler/ks_mirror/centos7.3-x86_64/repodata/repomd.xml
13.3 distro 常用命令
# 列出所有 distro
cobbler distro list
# 查看详情
cobbler distro report --name=centos7.3-x86_64
# 修改 distro(如追加默认内核参数)
cobbler distro edit --name=centos7.3-x86_64 --kopts="net.ifnames=0 biosdevname=0"
# 删除一个 distro
cobbler distro remove --name=centos73-x86_64
删除 distro 会连带影响依赖它的 profile,Cobbler 会要求先删 profile 或用
--recursive。
十四、Kickstart 模板管理
14.1 模板目录与自带样例
Cobbler 的 ks 文件统一放在 /var/lib/cobbler/kickstarts/:
ls /var/lib/cobbler/kickstarts/
default.ks legacy.ks pxerescue.ks sample_esx4.ks sample.ks
esxi4-ks.cfg sample_end.ks sample_esxi4.ks sample_esxi5.ks
install_profiles/ sample_autoyast.xml ...
| 文件 | 说明 |
|---|---|
sample.ks |
经典样例,CentOS 6 风格(段不以 %end 结尾) |
sample_end.ks |
CentOS 7 风格样例,每段都用 %end 闭合;import 后的 profile 默认用这个 |
default.ks |
最简模板 |
pxerescue.ks |
救援模式模板 |
legacy.ks |
老版本兼容模板 |
sample_autoyast.xml |
SUSE 的 AutoYaST 应答文件样例 |
片段(snippet)目录:
ls /var/lib/cobbler/snippets/
# post_install_kernel_options network_config keep_ssh_host_keys kickstart_start
# kickstart_done post_run_deb main_partition_select ...
14.2 Cheetah 模板语法与常用变量
Cobbler 的 ks 文件不是静态文件,而是 Cheetah 模板,客户端请求 ks 时由 Cobbler 动态渲染后返回。这样同一个模板可以服务不同的 profile/system,IP、源地址、密码都自动填入。
常用变量与语法:
| 语法 | 说明 |
|---|---|
$tree |
最常用。安装源的完整 URL,渲染后类似 http://3.3.3.4/cblr/links/centos7.3-x86_64。写 ks 时用 url --url=$tree 就不用硬编码 IP |
$server |
Cobbler 服务器地址(settings 里的 server) |
$http_server |
HTTP 服务地址(含端口) |
$distro_name / $profile_name / $system_name |
当前对象名 |
$hostname |
system 对象上设置的主机名 |
$default_password_crypted |
settings 里配置的加密 root 密码 |
$breed / $os_version / $arch |
系族/版本/架构 |
$SNIPPET('name') |
引入一个片段,把 /var/lib/cobbler/snippets/name 的内容嵌入此处 |
$getVar('varname','default') |
取变量,取不到时用默认值(安全取值) |
#if ... #else ... #end if |
条件判断 |
#for x in $list ... #end for |
循环 |
#set $var = value |
定义变量 |
\$ |
转义美元符号。shell 变量必须写成 \$,否则会被 Cheetah 当模板变量吃掉 |
#raw ... #end raw |
整段不做模板渲染(%post 里有大量 shell 变量时非常有用) |
使用模板语法的 ks 示例:
# /var/lib/cobbler/kickstarts/centos7-tpl.ks
install
text
eula --agreed
reboot
# 安装源用变量,换服务器 IP 时不用改 ks
url --url=$tree
lang en_US.UTF-8
keyboard --vckeymap=us --xlayouts='us'
timezone Asia/Shanghai --utc
# root 密码来自 settings 的 default_password_crypted
rootpw --iscrypted $default_password_crypted
auth --useshadow --passalgo=sha512
selinux --disabled
firewall --disabled
# 引入 Cobbler 自带的网络配置片段,自动按 system 的设置生成 network 行
$SNIPPET('network_config')
bootloader --location=mbr --append="net.ifnames=0 biosdevname=0"
# 按自定义变量 disk_type 决定分区方案
#if $getVar('disk_type','sata') == 'nvme'
#set $disk = 'nvme0n1'
#else
#set $disk = 'sda'
#end if
ignoredisk --only-use=$disk
zerombr
clearpart --all --initlabel --drives=$disk
part /boot --fstype=xfs --size=1024 --asprimary --ondisk=$disk
part pv.01 --size=1 --grow --ondisk=$disk
volgroup vg_sys pv.01
logvol / --vgname=vg_sys --name=lv_root --fstype=xfs --size=30720
logvol swap --vgname=vg_sys --name=lv_swap --fstype=swap --size=4096
logvol /data --vgname=vg_sys --name=lv_data --fstype=xfs --size=1 --grow
%packages --nobase --ignoremissing
@^minimal
@core
vim-enhanced
net-tools
wget
%end
%pre
$SNIPPET('log_ks_pre')
%end
%post --log=/root/ks-post.log
$SNIPPET('log_ks_post')
$SNIPPET('kickstart_start')
#raw
# 这一段里的 $ 都是 shell 变量,用 #raw 保护起来不被 Cheetah 解析
for svc in postfix firewalld; do
systemctl disable ${svc} >/dev/null 2>&1
done
echo "Installed at $(date '+%F %T')" > /etc/motd
#end raw
# 让新系统指向内网 yum 源($tree 会被渲染成真实 URL)
cat > /etc/yum.repos.d/cobbler.repo <<'EOF'
[base]
name=cobbler-base
baseurl=$tree
enabled=1
gpgcheck=0
EOF
$SNIPPET('post_install_network_config')
$SNIPPET('kickstart_done')
%end
14.3 自定义片段(snippet)复用
把重复的初始化逻辑抽成片段,多个 ks 共用:
vim /var/lib/cobbler/snippets/my_base_init
# /var/lib/cobbler/snippets/my_base_init
#raw
sed -i 's/^#\?UseDNS.*/UseDNS no/' /etc/ssh/sshd_config
sed -i 's/^#\?GSSAPIAuthentication.*/GSSAPIAuthentication no/' /etc/ssh/sshd_config
mkdir -p /root/.ssh && chmod 700 /root/.ssh
cat > /root/.ssh/authorized_keys <<'KEYEOF'
ssh-rsa AAAAB3NzaC1yc2E... ops@jumpserver
KEYEOF
chmod 600 /root/.ssh/authorized_keys
cat >> /etc/security/limits.conf <<'LIMEOF'
* soft nofile 65535
* hard nofile 65535
LIMEOF
#end raw
在任意 ks 的 %post 里一行引入:
%post --log=/root/ks-post.log
$SNIPPET('my_base_init')
%end
14.4 关联自定义 ks 到 profile 并校验
# 关联(修改 profile 使用的 kickstart 文件)
cobbler profile edit --name=new_centos7.3 --kickstart=/var/lib/cobbler/kickstarts/xxx.ks
# 校验所有 profile/system 的 ks 语法(Cobbler 会先渲染模板再用 ksvalidator 校验)
cobbler validateks
# 查看渲染后的最终 ks 内容(排错神器:能看到变量到底被渲染成了什么)
cobbler profile getks --name=new_centos7.3
cobbler system getks --name=db01
# 也可以直接用 curl 取渲染后的 ks,与客户端看到的完全一致
curl http://3.3.3.4/cblr/svc/op/ks/profile/new_centos7.3
curl http://3.3.3.4/cblr/svc/op/ks/system/db01
cobbler validateks与cobbler profile getks这两条命令要养成习惯:改完 ks 先 getks 看渲染结果,再 validateks 查语法,然后才去开虚拟机。
十五、自定义 Kickstart 安装方案(实战)
自动安装已经可以实现,但如果需要自定义安装内容,关键是自定义一个 ks 文件。
15.1 自定义 ks 文件的方法
- 熟悉 ks 文件的情况下,直接复制别人的模板修改,或使用
/root/anaconda-ks.cfg进行修改。 - 使用图形化工具
system-config-kickstart辅助配置(本节以该方式为例)。
安装图形化配置工具(上文已安装):
yum install system-config-kickstart
system-config-kickstart
需要将软件仓库名改成 development,否则图形界面在选择软件包那一步看不到内容:
vim /etc/yum.repos.d/local.repo
[development]
name=development
baseurl=file:///yum/
enabled=1
gpgcheck=0
图形操作过程可参考截图 system-config-kickstart01.png 至 system-config-kickstart14.png。
特别提醒:ks 文件中不能出现任何中文字符(包括注释行),否则将无法启动安装。
15.2 ks.cfg 完整示例(带图形桌面)
#platform=x86, AMD64, or Intel EM64T
#version=DEVEL
# Install OS instead of upgrade
install
# Keyboard layouts
keyboard 'us'
# Root password
rootpw --iscrypted $1$lCWjtTge$uuB/0hPOI.n25entF4ghI0
# Use network installation
url --url="http://3.3.3.4/cobbler/ks_mirror/centos73/"
# System language
lang en_US
# Firewall configuration
firewall --disabled
# System authorization information
auth --useshadow --passalgo=sha512
# Use graphical install
graphical
firstboot --disable
# SELinux configuration
selinux --disabled
# Network information
network --bootproto=dhcp --device=eth0
# Reboot after installation
reboot
# System timezone
timezone Asia/Shanghai --isUtc
# System bootloader configuration
bootloader --append="rhgb quiet" --location=mbr
# Clear the Master Boot Record
zerombr
# Partition clearing information
clearpart --all --initlabel
# Disk partitioning information
part /boot --asprimary --fstype="xfs" --size=300
part swap --asprimary --fstype="swap" --size=2000
part / --asprimary --fstype="xfs" --grow --size=1
%post
touch /tmp/123
touch /root/123
touch /root/Desktop/123
%end
%packages
@additional-devel
@desktop-debugging
@development
@fonts
@gnome-desktop
@input-methods
@kde-desktop
@legacy-x
@platform-devel
@remote-desktop-clients
@x11
initial-setup
initial-setup-gui
vinagre
tigervnc
firefox
net-tools
wget
elinks
vim-enhanced
%end
注意示例中的
url --url="http://3.3.3.4/cobbler/ks_mirror/centos73/"是硬编码的,实际使用中建议改成url --url=$tree由 Cobbler 渲染,避免服务器 IP 或 distro 名变动后失效。
15.3 将自定义 ks 文件创建为 profile
第一步:将 system-config-kickstart 生成的 ks 文件移动到 Cobbler 的 ks 目录,并取一个不同的名称:
mv /root/ks.cfg /var/lib/cobbler/kickstarts/centos7.3.ks
第二步:基于该 ks 文件创建新的 profile:
cobbler profile add --name=new_centos7.3 --distro=centos7.3-x86_64 --kickstart=/var/lib/cobbler/kickstarts/centos7.3.ks
查看 profile 列表:
cobbler profile list
centos7.3-x86_64
new_centos7.3
重启服务并同步:
systemctl restart cobblerd
cobbler sync
systemctl restart xinetd
第三步:新建客户端虚拟机,使用 new_centos7.3 这个安装方案进行测试。
15.4 profile 常用命令与参数
# 查看帮助
cobbler profile help
# 列出所有 profile
cobbler profile list
# 新增 profile(完整参数)
cobbler profile add --name=c7-min \
--distro=centos7.3-x86_64 \
--kickstart=/var/lib/cobbler/kickstarts/centos7-min.ks \
--kopts="net.ifnames=0 biosdevname=0 text" \
--kopts-post="quiet" \
--ksmeta="disk_type=sata role=web" \
--repos="epel7,base7" \
--name-servers="223.5.5.5 223.6.6.6" \
--name-servers-search="example.com" \
--enable-menu=1 \
--comment="CentOS 7 minimal for web nodes"
# 虚拟机相关参数(配合 koan 创建虚拟机时使用)
cobbler profile add --name=c7-vm --distro=centos7.3-x86_64 \
--kickstart=/var/lib/cobbler/kickstarts/centos7-min.ks \
--virt-type=kvm --virt-cpus=2 --virt-ram=2048 \
--virt-file-size=40 --virt-bridge=br0 --virt-disk-driver=raw
# 修改 profile(把 new_centos7.3 换一个新的 ks 文件)
cobbler profile edit --name=new_centos7.3 --kickstart=/var/lib/cobbler/kickstarts/xxx.ks
cobbler profile edit --name=c7-min --kopts="text ksdevice=bootif"
cobbler profile edit --name=c7-min --ksmeta="disk_type=nvme"
# 查看某个 profile 使用的 kickstart 文件
cobbler profile report --name=centos7.3-x86_64 | grep Kickstart
# 删除 profile
cobbler profile remove --name=centos7
cobbler profile remove --name=new_centos7.3
# 复制一个 profile 再改(快速派生新方案)
cobbler profile copy --name=c7-min --newname=c7-db
cobbler profile edit --name=c7-db --kickstart=/var/lib/cobbler/kickstarts/centos7-db.ks
注:源文档中
cobbler profil remove --name=centos7存在笔误,正确命令为cobbler profile remove。
| 参数 | 说明 |
|---|---|
--distro |
关联的 distro,必填 |
--kickstart |
关联的 ks 文件路径 |
--kopts |
追加到 PXE 引导时的内核参数(安装阶段生效) |
--kopts-post |
追加到装完系统后的内核参数(写进新系统的 grub) |
--ksmeta |
传给 ks 模板的自定义变量,格式 k1=v1 k2=v2,在 ks 里用 $k1 引用 |
--repos |
关联的 repo 对象名,装机后新系统自动指向这些内网源 |
--name-servers |
下发给客户端的 DNS |
--enable-menu |
是否在 PXE 菜单中显示该 profile(0 可隐藏内部方案) |
--server |
该 profile 使用的 server 地址(多网段/多机房时覆盖全局设置) |
--virt-* |
供 koan 创建虚拟机时使用的规格 |
十六、system 管理:按 MAC 绑定实现差异化装机
这是 Cobbler 在生产环境最有价值的功能:给每台机器登记 MAC 地址,让不同机器自动装成不同的系统、不同的分区、固定的 IP,客户端开机后连菜单都不会出现,直接开始装对应方案。
system 用于记录特定客户端主机的安装配置(如 MAC 地址、IP、绑定的 profile 等),可实现针对单台机器的定制化装机。
16.1 添加 system
# 数据库节点:装 c7-db 方案,固定 IP 192.168.100.61
cobbler system add --name=db01 \
--profile=c7-db \
--interface=eth0 \
--mac=00:0c:29:aa:bb:cc \
--ip-address=192.168.100.61 \
--subnet=255.255.255.0 \
--gateway=192.168.100.1 \
--name-servers="223.5.5.5" \
--hostname=db01.example.com \
--static=1 \
--netboot-enabled=1
# Web 节点:装 c7-min 方案,固定 IP 192.168.100.51
cobbler system add --name=web01 \
--profile=c7-min \
--interface=eth0 \
--mac=00:0c:29:dd:ee:ff \
--ip-address=192.168.100.51 \
--subnet=255.255.255.0 \
--gateway=192.168.100.1 \
--hostname=web01.example.com \
--static=1
# 多网卡机器:分两次 edit,每次指定一个 --interface
cobbler system edit --name=db01 --interface=eth1 \
--mac=00:0c:29:aa:bb:cd --ip-address=10.0.0.61 \
--subnet=255.255.255.0 --static=1 --management=0
# 用 ksmeta 给单台机器传自定义变量(覆盖 profile 的设置)
cobbler system edit --name=db01 --ksmeta="disk_type=nvme role=db data_size=500"
# 给单台机器指定完全不同的 ks 文件
cobbler system edit --name=db01 --kickstart=/var/lib/cobbler/kickstarts/db-special.ks
| 参数 | 说明 |
|---|---|
--name |
system 对象名(Cobbler 内部标识,习惯上用主机名) |
--profile |
绑定的安装方案,必填 |
--interface |
要配置的网卡名,后续的 --mac/--ip-address 都作用于这块网卡 |
--mac |
网卡 MAC 地址,Cobbler 靠它识别机器。Cobbler 会生成 pxelinux.cfg/01-<mac> 专属菜单和 dhcpd.conf 的 host 段 |
--ip-address |
分配给该网卡的 IP |
--subnet |
子网掩码 |
--gateway |
网关(system 级别是全局网关,interface 级别用 --if-gateway) |
--name-servers |
DNS |
--hostname |
主机名,会写进 ks 的 network --hostname= |
--static=1 |
该网卡配置为静态 IP(0 为 DHCP) |
--netboot-enabled |
是否允许网络安装。装完后置 0 可防止无限重装(pxe_just_once: 1 会自动做这件事) |
--management=1 |
标记为管理网卡 |
--kopts / --ksmeta / --kickstart |
覆盖 profile 的对应设置 |
--power-type / --power-address / --power-user / --power-pass |
电源管理参数(IPMI 等) |
16.2 查询与删除
cobbler system list
db01
web01
cobbler system report --name=db01
cobbler system report # 所有 system 的详情
cobbler system find --profile=c7-db # 按条件查找
cobbler system find --mac=00:0c:29:aa:bb:cc
cobbler system remove --name=web01
cobbler system copy --name=web01 --newname=web02
cobbler system edit --name=web02 --interface=eth0 --mac=00:0c:29:11:22:33 --ip-address=192.168.100.52
# 装完后关闭该机器的网络安装(避免重启又装一遍)
cobbler system edit --name=db01 --netboot-enabled=0
16.3 批量登记的思路
生产上几十台机器逐条敲命令不现实,常见做法:
# 从一个 CSV(name,mac,ip,profile,hostname)批量导入
while IFS=, read -r name mac ip profile hostname; do
cobbler system add --name="$name" --profile="$profile" \
--interface=eth0 --mac="$mac" --ip-address="$ip" \
--subnet=255.255.255.0 --gateway=192.168.100.1 \
--hostname="$hostname" --static=1
done < servers.csv
cobbler sync
MAC 地址的获取途径:机器铭牌/资产标签、交换机的 MAC 地址表(show mac address-table)、IPMI/BMC 界面、或者先让机器进一次 PXE 菜单从屏幕上抄 CLIENT MAC ADDR。
十七、DHCP 模板与同步
17.1 第五步:修改 DHCP 配置
编辑 /etc/cobbler/dhcp.template,将第 21 行至第 25 行修改为对应网段和 IP:
subnet 3.3.3.0 netmask 255.255.255.0 { # 设置 dhcp 服务器的网段
option routers 3.3.3.4; # 指定路由地址
option domain-name-servers 3.3.3.4; # 指定域名解析服务器
option subnet-mask 255.255.255.0;
range dynamic-bootp 3.3.3.100 3.3.3.128; # 指定 dhcp 地址池
模板文件的完整结构(Cheetah 模板,sync 时渲染成 dhcpd.conf):
# /etc/cobbler/dhcp.template
# ******************************************************************
# Cobbler managed dhcpd.conf file
# generated from cobbler dhcp.conf template ($date)
# Do NOT make changes to /etc/dhcpd.conf. Instead, make your changes
# in /etc/cobbler/dhcp.template, as /etc/dhcpd.conf will be
# overwritten.
# ******************************************************************
ddns-update-style interim;
allow booting;
allow bootp;
ignore client-updates;
set vendorclass = option vendor-class-identifier;
option pxe-system-type code 93 = unsigned integer 16;
subnet 3.3.3.0 netmask 255.255.255.0 {
option routers 3.3.3.4;
option domain-name-servers 3.3.3.4;
option subnet-mask 255.255.255.0;
range dynamic-bootp 3.3.3.100 3.3.3.128;
default-lease-time 21600;
max-lease-time 43200;
next-server $next_server;
class "pxeclients" {
match if substring (option vendor-class-identifier, 0, 9) = "PXEClient";
if option pxe-system-type = 00:02 {
filename "ia64/elilo.efi";
} else if option pxe-system-type = 00:06 {
filename "grub/grub-x86.efi";
} else if option pxe-system-type = 00:07 {
filename "grub/grub-x86_64.efi";
} else if option pxe-system-type = 00:09 {
filename "grub/grub-x86_64.efi";
} else {
filename "pxelinux.0";
}
}
}
# Cobbler 会在这里自动插入每一台 system 的 host 段
#for dhcp_tag in $dhcp_tags.keys():
## 由 Cobbler 根据 system 对象自动生成,不要手工写
#end for
cobbler sync 后生成的 /etc/dhcp/dhcpd.conf 中,每台登记过的 system 会得到一个 host 段:
host db01 {
hardware ethernet 00:0c:29:aa:bb:cc;
fixed-address 192.168.100.61;
option host-name "db01.example.com";
option subnet-mask 255.255.255.0;
option routers 192.168.100.1;
filename "/pxelinux.0";
next-server 3.3.3.4;
}
高频坑:要改 DHCP 配置,必须改
/etc/cobbler/dhcp.template,而不是直接改/etc/dhcp/dhcpd.conf。因为
manage_dhcp: 1时,每次cobbler sync都会用模板重新生成 dhcpd.conf 并覆盖它。你直接改 dhcpd.conf 的内容(比如加了一个网段、改了网关)在下一次 sync 后会全部消失,而且现象很隐蔽——"昨天还能装,今天客户端网关就不对了"。生成的 dhcpd.conf 文件头部就明确写着
Do NOT make changes to /etc/dhcpd.conf。同理,
/etc/cobbler/下的其他模板也遵循同样的规则:
dhcp.template→/etc/dhcp/dhcpd.confdnsmasq.template→/etc/dnsmasq.confnamed.template/zone.template→ bind 配置pxe/pxedefault.template→/var/lib/tftpboot/pxelinux.cfg/defaultpxe/pxesystem.template→/var/lib/tftpboot/pxelinux.cfg/01-<MAC>pxe/pxeprofile.template→ 菜单中的 profile 条目rsync.template→/etc/rsyncd.confmodules.conf→ 模块开关(认证方式等)
17.2 第六步:同步配置并启动 xinetd
cobbler sync
systemctl restart xinetd.service
systemctl enable xinetd.service
cobbler sync 究竟做了什么:
1. 依据 /etc/cobbler/dhcp.template + 所有 system 对象
→ 重新生成 /etc/dhcp/dhcpd.conf,并(restart_dhcp:1 时)重启 dhcpd
2. 依据 /etc/cobbler/pxe/*.template + 所有 profile/system
→ 重新生成 /var/lib/tftpboot/pxelinux.cfg/default(公共菜单)
→ 为每台 system 生成 /var/lib/tftpboot/pxelinux.cfg/01-<MAC>(专属菜单)
→ 生成 grub 目录下的 UEFI 菜单
3. 把每个 distro 的 vmlinuz / initrd.img
→ 拷贝到 /var/lib/tftpboot/images/<distro-name>/
4. 把 loaders 里的 pxelinux.0、menu.c32 等
→ 拷贝到 /var/lib/tftpboot/
5. 刷新 /var/www/cobbler/ 下的链接(links、ks_mirror、repo_mirror)
6. 触发 sync 相关的 triggers 钩子
只想同步单个对象、不做全量 sync(Cobbler 2.6+,全量 sync 在对象多时较慢):
cobbler sync --systems=db01,web01
查看自动生成的结果:
cat /etc/dhcp/dhcpd.conf
cat /var/lib/tftpboot/pxelinux.cfg/default
ls /var/lib/tftpboot/pxelinux.cfg/
ls /var/lib/tftpboot/images/
17.3 第七步:客户端安装测试
新建一台虚拟机,选择 PXE 安装,保证处于相同私有网络,建议内存为 2G 以上;内存过小可能导致安装时报空间不足错误。
如果安装过程中出现
printf: write error: No space left on device,表示虚拟机内存不足,将内存调整到 2G 以上即可。如果网络引导失败,请在客户端虚拟机中调整启动顺序,优先从网络启动。
观察 PXE 菜单:客户端拿到 IP 后应看到 Cobbler 生成的菜单,标题类似 Cobbler | http://cobbler.github.io/,其中列出:
(local) ← 从本地硬盘启动,默认项
centos7.3-x86_64 ← import 自动生成的 profile
new_centos7.3 ← 自定义的 profile
c7-min
c7-db
对已登记 MAC 的机器,Cobbler 生成的是 01-<MAC> 专属菜单,客户端会跳过选择直接进入绑定的 profile。
十八、实现全自动安装(免菜单选择)
要免除安装时的菜单选择按键,可编辑 /var/lib/tftpboot/pxelinux.cfg/default:
DEFAULT menu
PROMPT 0
MENU TITLE Cobbler | http://cobbler.github.io/ # 后面的网址可换成自定义内容
TIMEOUT 1 # 设置菜单等待时间,超过该时间自动进入下方定义的选项
TOTALTIMEOUT 6000
ONTIMEOUT centos7.3-x86_64 # 设置等待超时后自动进入的标签,具体选择视情况而定
kernel /images/centos7.3-x86_64/vmlinuz
LABEL local # 标签1;使用本地磁盘启动
MENU LABEL (local)
MENU DEFAULT
LOCALBOOT -1
LABEL centos7.3-x86_64 # 标签2;使用自定义镜像安装;标签可以有多个
MENU LABEL centos7.3-x86_64
append initrd=/images/centos7.3-x86_64/initrd.img ksdevice=bootif lang= kssendmac text ks=http://3.3.3.4/cblr/svc/op/ks/profile/centos7.3-x86_64
ipappend 2
MENU end
关键项说明:
| 项 | 作用 |
|---|---|
TIMEOUT 1 |
菜单只等 0.1 秒,几乎立刻超时 |
ONTIMEOUT centos7.3-x86_64 |
超时后自动进入这个 LABEL,从而实现"开机即装,无需按键" |
ksdevice=bootif + ipappend 2 |
让 anaconda 使用 PXE 启动时那块网卡(多网卡机器必须这么写) |
kssendmac |
安装时把 MAC 通过 HTTP 头发给服务端,Cobbler 借此识别机器 |
ks=http://3.3.3.4/cblr/svc/op/ks/profile/xxx |
Cobbler 动态渲染 ks 的 URL 格式(system 则是 .../ks/system/xxx) |
LOCALBOOT -1 |
从本地硬盘启动 |
注意:这个文件是
cobbler sync自动生成的,直接改会在下次 sync 时被覆盖。 要持久化这个改动,应该改模板/etc/cobbler/pxe/pxedefault.template,或者更推荐的做法——在/etc/cobbler/settings里设置:pxe_just_once: 1 default_ownership: [admin] # 让菜单超时后自动进入某个 profile以及给机器登记
system对象(有 system 的机器本来就不需要选菜单)。
十九、扩展操作参考
# 把 new_centos7.3 这个安装 profile 换一个新的 ks 文件
cobbler profile edit --name=new_centos7.3 --kickstart=/var/lib/cobbler/kickstarts/xxx.ks
# 删除一个 distro
cobbler distro remove --name=centos73-x86_64
# 删除名为 new_centos7.3 的安装 profile
cobbler profile remove --name=new_centos7.3
其他常用维护命令:
cobbler list # 列出所有对象(distro/profile/system/repo/image)
cobbler report # 所有对象的详细报告
cobbler version # 查看版本
cobbler status # 查看正在进行的安装任务及其状态(非常实用)
cobbler signature update # 更新发行版签名库(导入新版本系统报 breed 不识别时需要)
cobbler aclsetup --adduser=devops # 给普通用户授权使用 cobbler
cobbler hardlink # 对 ks_mirror 下重复文件做硬链接,节省磁盘空间
二十、Cobbler Web UI
20.1 访问与登录
# 确认 cobbler-web 已安装,httpd 已启动
rpm -q cobbler-web
systemctl restart httpd
访问地址(必须是 https,http 会被重定向或报错):
https://3.3.3.4/cobbler_web
https://<你的服务器IP>/cobbler_web
浏览器会提示证书不受信任(自签名证书),选择"继续访问"即可。
默认账号密码:
用户名:cobbler
密码: cobbler
20.2 修改 Web UI 密码
账号信息存放在 /etc/cobbler/users.digest,用 httpd-tools 提供的 htdigest 命令管理,realm 必须是 Cobbler(大写 C,写错会导致登录失败):
# 修改已有用户 cobbler 的密码(-c 会清空文件重建,谨慎使用)
htdigest /etc/cobbler/users.digest "Cobbler" cobbler
# 交互式输入两次新密码
# 新增一个用户
htdigest /etc/cobbler/users.digest "Cobbler" devops
# 第一次创建文件时才用 -c(会覆盖原文件!)
htdigest -c /etc/cobbler/users.digest "Cobbler" cobbler
# 查看文件内容确认
cat /etc/cobbler/users.digest
# cobbler:Cobbler:c4b4b5b0d43dd3c9d9b4f1a6d0e0f1a2
# 改完重启 httpd 与 cobblerd
systemctl restart httpd
systemctl restart cobblerd
授权配置在 /etc/cobbler/users.conf 与 /etc/cobbler/modules.conf:
# /etc/cobbler/modules.conf
[authentication]
module = authn_configfile # 用 users.digest 文件认证(默认)
# module = authn_pam # 用系统账号(PAM)认证
# module = authn_ldap # 用 LDAP 认证
# module = authn_denyall # 全部拒绝(关闭 Web UI)
[authorization]
module = authz_allowall # 通过认证即拥有全部权限(默认)
# module = authz_ownership # 按对象 owner 做细粒度授权
# /etc/cobbler/users.conf
[admins]
admin = ""
cobbler = ""
devops = ""
20.3 Web 界面功能区与 CLI 的对应
| Web 界面 | 对应 CLI |
|---|---|
| Distros 列表 / New Distro | cobbler distro list / distro add / distro edit |
| Profiles 列表 / New Profile | cobbler profile list / profile add / profile edit |
| Systems 列表 / New System | cobbler system list / system add / system edit |
| Repos | cobbler repo add / repo list |
| Images | cobbler image add |
| Kickstart Templates(可在线编辑 ks) | 直接编辑 /var/lib/cobbler/kickstarts/*.ks |
| Snippets(可在线编辑片段) | 直接编辑 /var/lib/cobbler/snippets/* |
| Import DVD | cobbler import --path=... --name=... |
| Sync | cobbler sync |
| Check | cobbler check |
| Events / Tasks(查看后台任务日志) | cobbler status + /var/log/cobbler/tasks/ |
| Config Mgmt Classes | cobbler mgmtclass add |
20.4 适用场景与局限
适合:
- 给不熟悉 CLI 的同事(值班、硬件工程师)提供一个"点一下就能装机"的入口
- 在线编辑 ks 模板和 snippet,带语法高亮,比 vim 直观
- 查看 Events/Tasks 中的后台任务日志(import、reposync 这类长任务)
- 培训和演示时展示对象之间的层级关系
局限:
- 功能覆盖不全,部分 CLI 参数(如某些
--virt-*、triggers 相关)在 Web 上没有入口 - 批量操作(一次登记 50 台 system)在 Web 上几乎不可用,必须用 CLI + 脚本
- 界面较老(Django 1.x 时代),部分浏览器下有兼容问题
- 自签名证书 + digest 认证,安全性一般,不建议暴露到公网
- 出错信息不如 CLI 直白,排错最终还是要回到 CLI 和
/var/log/cobbler/
结论:把 Web UI 当"查看器和演示工具",把 CLI 当"生产操作方式"。
二十一、使用 koan 实现客户端自动重装
客户端可使用 koan(Kickstart Over A Network)与服务器端的 Cobbler 通信,实现自动重装系统,不需要动 BIOS 启动顺序、不需要人到机房。
21.1 安装 koan
客户端需要安装 koan 软件包(需要 local 源和 EPEL 源):
yum install koan
21.2 列出服务器端可用的 profile
将 3.3.3.4 替换为实际的 Cobbler 服务器 IP,执行结果与在 Cobbler 服务器上执行 cobbler profile list 相同:
koan --server=3.3.3.4 --list=profiles
centos7.3-x86_64
new_centos7.3
# 列出可用的 system 与 distro
koan --server=3.3.3.4 --list=systems
koan --server=3.3.3.4 --list=distros
koan --server=3.3.3.4 --list=images
21.3 指定 profile 重装系统
执行重装时,系统当前需要以硬盘优先启动,而不是网络优先启动。
koan --replace-self --server=3.3.3.4 --profile=new_centos7.3
该命令会指定本客户端按照名为 new_centos7.3 的 profile 重装系统。它的实现原理是:从 Cobbler 拉取该 profile 的 vmlinuz/initrd 和渲染好的 ks,往本地 grub 里临时插入一个一次性的启动项,重启后从这个启动项进入 anaconda 完成重装。
执行完成后重启系统即开始重装:
reboot
若未执行上面的 koan 命令,
reboot仅为普通重启。
# 按 system 对象重装(会用到该 system 的固定 IP、主机名等设置)
koan --replace-self --server=3.3.3.4 --system=db01
# 只下载文件、不真正改 grub(试运行)
koan --replace-self --server=3.3.3.4 --profile=c7-min --nogfx --add-reinstall-entry
21.4 用 koan 创建虚拟机
koan 也能在一台 KVM/Xen 宿主机上直接创建并安装虚拟机:
# 在宿主机上执行,按 profile 的 --virt-* 规格创建一台新虚拟机
koan --virt --server=3.3.3.4 --profile=c7-vm --virt-name=vm-web01
koan --virt --server=3.3.3.4 --profile=c7-vm \
--virt-name=vm-web02 --virt-path=/var/lib/libvirt/images \
--virt-type=qemu
详见 15-01-KVM虚拟化.md
二十二、Cobbler 进阶功能
22.1 repo:本地 yum 仓库镜像
让装好的机器自动指向内网源,避免每台机器都去外网拉包。
# 添加一个 repo(同步远端源到本地)
cobbler repo add --name=epel7 \
--mirror=http://mirrors.aliyun.com/epel/7/x86_64/ \
--arch=x86_64 --breed=yum --keep-updated=1
cobbler repo add --name=base7 \
--mirror=http://mirrors.aliyun.com/centos/7/os/x86_64/ \
--arch=x86_64 --breed=yum
# 从本地目录建 repo(不联网)
cobbler repo add --name=local7 --mirror=/var/www/cobbler/ks_mirror/centos7.3-x86_64 --breed=yum
# 执行同步(第一次很慢,EPEL 有几个 G)
cobbler reposync
cobbler reposync --only=epel7 # 只同步指定的 repo
cobbler reposync --tries=3 --no-fail # 失败重试,个别失败不中断
# 查看
cobbler repo list
cobbler repo report --name=epel7
# 关键一步:把 repo 关联到 profile
cobbler profile edit --name=c7-min --repos="base7 epel7"
cobbler sync
关联后,Cobbler 自带的 ks 模板会通过 $SNIPPET('yum_config_stanza') 自动在装好的系统里生成指向 http://3.3.3.4/cobbler/repo_mirror/epel7/ 的 repo 文件——装完机器就已经指向内网源,不需要额外操作。
同步的内容放在:
ls /var/www/cobbler/repo_mirror/
配合 crontab 定期同步:
# Cobbler 自带的定时同步任务
cat /etc/cron.d/cobbler
# 0 5 * * * root /usr/bin/cobbler reposync --tries=3 --no-fail
22.2 电源管理:远程开机装机
配合 IPMI/BMC/iDRAC/iLO,实现"在 Cobbler 上敲一条命令就把远端机器开机并开始装系统",机房无人化的关键。
# 给 system 配置电源管理参数
cobbler system edit --name=db01 \
--power-type=ipmilan \
--power-address=192.168.200.61 \
--power-user=ADMIN \
--power-pass=ADMIN \
--power-id=1
# 支持的 power-type 来自 fence-agents:
# ipmilan / ipmitool / drac / drac5 / ilo / ilo2 / ilo3 / ilo4
# apc / wti / bladecenter / virsh / vmware ...
# 操作
cobbler system poweron --name=db01 # 开机
cobbler system poweroff --name=db01 # 关机
cobbler system reboot --name=db01 # 重启(最常用:改完 profile 直接远程重启触发重装)
cobbler system powerstatus --name=db01 # 查询电源状态
# 批量操作
cobbler system reboot --name=db01,db02,db03
典型的"全无人化装机"流程:登记 system(含 MAC 与 IPMI 信息)→ cobbler sync → cobbler system reboot → 机器自动网络启动、自动装完、自动关闭 netboot → Ansible 接手做后续配置。
22.3 cobbler replicate:多机房复制
把主 Cobbler 的对象和镜像同步到其他机房的从 Cobbler,避免每个机房都重新导入镜像。
# 在从服务器上执行,从 master 拉取
cobbler replicate --master=cobbler-master.example.com \
--distros="centos7*" \
--profiles="c7-*" \
--systems="" \
--repos="epel7" \
--omit-data=0 \
--prune
# 只同步元数据不同步镜像文件(镜像另行 rsync)
cobbler replicate --master=cobbler-master.example.com --omit-data=1
| 参数 | 说明 |
|---|---|
--master |
主 Cobbler 的地址 |
--distros/--profiles/--systems/--repos/--images |
用通配符指定要同步的对象,留空表示不同步该类 |
--omit-data=1 |
只同步对象定义,不同步 ks_mirror/repo_mirror 里的大文件 |
--prune |
删除本地存在而主端已删除的对象 |
--sync-all |
同步所有类型的对象 |
依赖 rsyncd,因此前面 cobbler check 里让你启动 rsyncd 是有实际意义的。
22.4 cobbler buildiso:生成引导 ISO
在没有 PXE 条件的环境(网络不允许广播 DHCP、机房二层被隔离、只有一台孤立机器、或客户端不支持 PXE)下,把引导菜单打包成一个小 ISO,用它启动后仍然从网络取安装源和 ks。
# 生成包含所有 profile 的引导 ISO
cobbler buildiso
# 只包含指定 profile,输出到指定路径
cobbler buildiso --iso=/root/cobbler-boot.iso --profiles=c7-min,c7-db
# 生成完全独立的 ISO(把安装源也打包进去,可离线安装,体积会很大)
cobbler buildiso --iso=/root/c7-standalone.iso --profiles=c7-min --standalone
# 只包含指定 system(自动带上其固定 IP 配置)
cobbler buildiso --iso=/root/db01.iso --systems=db01
生成的 ISO 可以刻盘、写 U 盘,或通过 IPMI 虚拟光驱远程挂载。
22.5 triggers:钩子机制
Cobbler 在特定事件前后会执行 /var/lib/cobbler/triggers/ 下的脚本,可用于与外部系统联动。
ls /var/lib/cobbler/triggers/
# add/ change/ delete/ install/ sync/ task/
ls /var/lib/cobbler/triggers/install/post/
# 例:装机完成后自动通知(发钉钉/写 CMDB/触发 Ansible)
cat > /var/lib/cobbler/triggers/install/post/notify.sh <<'EOF'
#!/bin/bash
# Cobbler 传入三个参数:$1=objtype(system/profile) $2=name $3=ip
OBJTYPE="$1"; NAME="$2"; IP="$3"
LOG=/var/log/cobbler/install-notify.log
echo "$(date '+%F %T') installed ${OBJTYPE} ${NAME} ${IP}" >> ${LOG}
# 通知钉钉机器人
curl -s -X POST 'https://oapi.dingtalk.com/robot/send?access_token=xxx' \
-H 'Content-Type: application/json' \
-d "{\"msgtype\":\"text\",\"text\":{\"content\":\"装机完成: ${NAME} ${IP}\"}}"
# 触发 Ansible 做装后初始化
/usr/bin/ansible-playbook -i "${IP}," /etc/ansible/playbooks/base-init.yml >> ${LOG} 2>&1
EOF
chmod +x /var/lib/cobbler/triggers/install/post/notify.sh
常用触发点:
| 目录 | 触发时机 |
|---|---|
triggers/install/pre/ |
客户端开始安装时(anaconda 的 %pre 里回调 Cobbler) |
triggers/install/post/ |
客户端安装完成时(%post 里回调) |
triggers/sync/pre/ sync/post/ |
cobbler sync 前后 |
triggers/add/system/pre|post/ |
添加 system 对象前后 |
triggers/change/* |
对象变更时 |
要让 install 触发器生效,ks 模板里必须包含
$SNIPPET('kickstart_start')和$SNIPPET('kickstart_done'),这两个片段负责回调 Cobbler 的 API 上报状态(cobbler status也依赖它们)。
22.6 与 Ansible / SaltStack 衔接:完整自动化链条
装机只是第一步,真正的自动化是"从上电到可交付业务"全程无人:
① 硬件上架、连网、记录 MAC
↓
② Cobbler 登记 system(MAC + 固定 IP + profile)→ cobbler sync
↓
③ cobbler system poweron(IPMI 远程开机)
↓
④ PXE 自动引导 → Kickstart 无人值守安装
(%post 中只做最小必要的事:配内网源、注入运维 SSH 公钥、装 python)
↓
⑤ Cobbler install/post trigger 触发:把新机器 IP 写入 Ansible inventory / CMDB
↓
⑥ Ansible playbook(或 SaltStack state)接手做完整初始化:
系统基线、内核参数、监控 agent、日志采集、时间同步、账号、堡垒机纳管
↓
⑦ 按角色部署业务组件(nginx/mysql/redis/k8s node)
↓
⑧ 注册到监控与负载均衡,交付
分工原则:ks 的 %post 只做"让配置管理工具能接管"的最小工作(网络通、源可用、SSH 公钥就位、Python 存在),其余全部交给 Ansible/Salt。这样 ks 文件保持稳定极少改动,业务配置的变更走配置管理工具的版本管理与灰度流程。
详见 14-02-Ansible自动化部署.md 详见 14-04-SaltStack配置管理.md 详见 14-03-Puppet配置管理.md
22.7 日志位置
ls /var/log/cobbler/
| 路径 | 内容 |
|---|---|
/var/log/cobbler/cobbler.log |
cobblerd 主日志,API 调用、对象变更 |
/var/log/cobbler/tasks/ |
每个后台任务(import、sync、reposync、replicate)一个日志文件,cobbler status 与 Web 的 Events 页读的就是这里 |
/var/log/cobbler/install.log |
客户端安装状态上报记录 |
/var/log/cobbler/anamon/<system>/ |
开启 anamon 后,客户端 anaconda 的日志会实时回传到这里(排查客户端装机失败的利器) |
/var/log/httpd/error_log |
Web UI 与 cobbler_api 的报错 |
/var/log/messages |
dhcpd、xinetd/tftp 的日志 |
开启 anamon(客户端 anaconda 日志回传):
# /etc/cobbler/settings
anamon_enabled: 1
二十三、UEFI 与新系统支持
23.1 UEFI 网络启动
现代服务器出厂默认 UEFI 模式(很多新机型甚至已取消 Legacy/CSM 选项),必须处理 UEFI PXE。
需要的文件与目录:
# 安装 UEFI 引导相关包
yum -y install grub2-efi-x64 grub2-efi-x64-modules shim-x64
# 拷贝到 tftpboot(Cobbler 中放到 loaders 让 sync 分发)
mkdir -p /var/lib/tftpboot/grub
cp /boot/efi/EFI/centos/grubx64.efi /var/lib/tftpboot/grub/grub-x86_64.efi
cp /boot/efi/EFI/centos/shimx64.efi /var/lib/tftpboot/grub/ 2>/dev/null
# 或从安装镜像取
cp /mnt/cdrom/EFI/BOOT/grubx64.efi /var/lib/tftpboot/grub/
cp /mnt/cdrom/EFI/BOOT/BOOTX64.EFI /var/lib/tftpboot/grub/
手工 PXE 下的 UEFI 菜单(grub 语法,与 syslinux 完全不同):
# /var/lib/tftpboot/grub/grub.cfg
set default="0"
set timeout=10
menuentry 'Auto Install CentOS 7 (Kickstart)' {
linuxefi /images/centos7-x86_64/vmlinuz inst.repo=http://192.168.100.10/centos7 inst.ks=http://192.168.100.10/ks/ks.cfg
initrdefi /images/centos7-x86_64/initrd.img
}
menuentry 'Boot from local drive' {
exit
}
Cobbler 中的处理:Cobbler 2.6+ 的 dhcp.template 已内置按 option 93 判断架构的逻辑(前文模板中已给出),cobbler sync 会自动在 /var/lib/tftpboot/grub/ 下生成 UEFI 菜单,只要确保:
cobbler get-loaders成功,或手工把 grub-x86_64.efi 放进/var/lib/cobbler/loaders/manage_dhcp: 1,让 Cobbler 生成含 UEFI 分支的 dhcpd.conf- 检查生成的 dhcpd.conf 里
filename "grub/grub-x86_64.efi"这一行确实存在 tftp <server> -c get grub/grub-x86_64.efi能取到
ks 侧的 UEFI 差异:必须有 EFI 系统分区,否则装完起不来:
part /boot/efi --fstype=efi --size=600 --fsoptions="umask=0077,shortname=winnt" --ondisk=sda
part /boot --fstype=xfs --size=1024 --ondisk=sda
安全启动(Secure Boot)开启时,必须走 shimx64.efi → grubx64.efi 的链路(shim 带微软签名),否则固件会拒绝加载。实验环境最简单的处理是在 BIOS 里关掉 Secure Boot。
23.2 CentOS 8 / Rocky / AlmaLinux 的 ks 语法变化
| 变化点 | CentOS 6/7 | CentOS 8 / Rocky 8+ / Alma 8+ |
|---|---|---|
| 仓库结构 | 单一 Packages/ 目录 |
拆成 BaseOS 与 AppStream 两个仓库,url --url= 指向 BaseOS,另需 repo --name=AppStream --baseurl=... |
install 指令 |
必需 | 已废弃,可省略(写了会警告) |
auth / authconfig |
使用 | 已移除,改用 authselect select sssd 或干脆不写 |
%packages 环境组 |
@^minimal |
@^minimal-environment(组名变了) |
--nobase |
支持 | 已移除(因为 @base 组不存在了) |
network |
--device=eth0 |
网卡名多为 ens*/eno*,建议用 MAC 或 --device=link |
| 分区 | ext4/xfs | 默认 xfs;Fedora/部分发行版默认 btrfs,btrfs 相关指令语法不同 |
firstboot |
--disable |
同样支持,但 initial-setup 包变化 |
| 时间同步 | ntpd/chrony | 只有 chrony |
| SELinux | 可 disabled | 官方更强调不要关闭 |
| 引导 | 多为 BIOS | 默认 UEFI,必须有 /boot/efi 分区 |
CentOS 8 / Rocky 8 的 ks 片段示例:
text
eula --agreed
reboot
url --url="http://192.168.100.10/rocky8/BaseOS"
repo --name="AppStream" --baseurl="http://192.168.100.10/rocky8/AppStream"
lang en_US.UTF-8
keyboard --vckeymap=us --xlayouts='us'
timezone Asia/Shanghai --utc
rootpw --iscrypted $6$xxxx
selinux --permissive
firewall --enabled --service=ssh
network --bootproto=dhcp --device=link --activate --hostname=node01
ignoredisk --only-use=sda
zerombr
clearpart --all --initlabel --drives=sda
part /boot/efi --fstype=efi --size=600 --fsoptions="umask=0077,shortname=winnt" --ondisk=sda
part /boot --fstype=xfs --size=1024 --ondisk=sda
part pv.01 --size=1 --grow --ondisk=sda
volgroup vg_sys pv.01
logvol / --vgname=vg_sys --name=lv_root --fstype=xfs --size=1 --grow
logvol swap --vgname=vg_sys --name=lv_swap --fstype=swap --size=4096
%packages --ignoremissing
@^minimal-environment
vim-enhanced
net-tools
%end
%post --log=/root/ks-post.log
authselect select sssd --force 2>/dev/null
%end
Cobbler 导入这些新发行版时如果报 breed 无法识别,先执行
cobbler signature update(需联网),或手工更新/var/lib/cobbler/distro_signatures.json。
23.3 现代替代方案
| 方案 | 定位 | 特点 |
|---|---|---|
| MAAS(Metal As A Service,Canonical) | 裸机生命周期管理 | 自带 DHCP/DNS/PXE,硬件自动发现(commissioning)、机器池化、REST API、Web UI 现代化;对 Ubuntu 支持最好,也支持 CentOS/RHEL |
| Foreman + Katello | 完整的生命周期管理平台 | Puppet 生态出身,装机(走 PXE/Kickstart)+ 配置管理 + 补丁管理 + 内容视图一体;功能最全但也最重。Red Hat Satellite 6 就基于它 |
| Tinkerbell(Equinix Metal 开源) | 云原生裸机provisioning | 工作流引擎 + 容器化的 provisioning 步骤,Kubernetes 友好,适合大规模裸机云 |
| Ironic(OpenStack Bare Metal) | 把裸机当虚拟机管理 | 通过 API 部署裸机,与 OpenStack/K8s(Metal3) 集成 |
| cloud-init + 自定义镜像 | 云环境事实标准 | 装机变成"起实例":先做好黄金镜像,实例首次启动时由 cloud-init 读取 user-data 完成主机名、网络、SSH key、初始化脚本。速度以秒计,是公有云/私有云的默认路径 |
| Packer | 镜像构建 | 把"装系统"变成"构建镜像",用 Kickstart + Packer 自动产出各平台(KVM/VMware/AWS AMI)的黄金镜像,然后靠克隆交付 |
Cobbler 项目现状说明:
- Cobbler 2.x(本文使用的版本,CentOS 7 时代的 EPEL 提供)是最广为流传的版本,资料最多,但已停止维护。
- Cobbler 3.x 做了较大重构:术语变化很大——
kickstart改叫autoinstall(--kickstart→--autoinstall),模板引擎从 Cheetah 转向 Jinja2 兼容,ks 目录从/var/lib/cobbler/kickstarts/变为/var/lib/cobbler/templates/,settings 从单一文件改为settings.d/目录。照抄 2.x 的命令在 3.x 上会报错。 - Cobbler 3.x 仍在 GitHub 上活跃,但社区热度不如当年;新项目选型时,裸机规模大的更多选 MAAS/Foreman/Tinkerbell,云上则根本不需要 PXE。
- 尽管如此,学 Cobbler 的价值仍然很高:它把 PXE+Kickstart 这套机制的每个环节都摊开在你面前,理解了它,再上手 MAAS/Foreman 只是换个界面的事。传统 IDC、政企内网、国产化环境里 Cobbler 至今仍在大量使用。
二十四、手工 PXE 与 Cobbler 方案对比
| 对比项 | 手工 PXE + Kickstart | Cobbler |
|---|---|---|
| 配置复杂度 | 高。需分别配置 dhcpd.conf、xinetd/tftp、pxelinux.cfg/default、httpd、ks.cfg 五处,且 IP 与路径要手工保持一致 | 低。只改 /etc/cobbler/settings + 模板,其余由 cobbler sync 自动生成 |
| 多版本管理 | 困难。每个版本手工建目录、拷内核、加菜单项 | 简单。cobbler import 一条命令搞定,自动生成 distro + profile + 菜单 |
| 一个镜像多方案 | 需手工写多个 ks 并逐个加菜单项 | 天然支持。一个 distro 派生任意多个 profile |
| 按 MAC 差异化 | 手工维护 pxelinux.cfg/01-<MAC> 文件,每台一个文件,无集中视图 |
cobbler system add --mac 一条命令,自动生成专属菜单和 dhcp host 段 |
| 固定 IP 下发 | 手工在 dhcpd.conf 写 host 段 | system 对象的 --ip-address --static=1 自动生成 |
| 可视化 | 无 | 有 Web UI(cobbler_web),可查看对象、编辑 ks、查看任务日志 |
| API 能力 | 无 | XML-RPC API(/cobbler_api),可被脚本/CMDB/koan 调用 |
| 本地 yum 源管理 | 需自己搭 reposync + httpd | cobbler repo add + reposync + --repos 关联,装完自动指向内网源 |
| 远程重装 | 需到机房改启动顺序,或自己写 grub 注入 | koan --replace-self 或 cobbler system reboot(配 IPMI)远程完成 |
| 多机房复制 | 手工 rsync + 重新配置 | cobbler replicate |
| 状态可见性 | 无。装了几台、成功几台全靠人看 | cobbler status + install trigger + anamon 日志回传 |
| 学习成本 | 中。但必须先学,因为 Cobbler 出问题时排错仍要回到 DHCP/TFTP/HTTP 这一层 | 中高。要额外学对象模型、Cheetah 模板、settings 与模板的关系 |
| 可控性/透明度 | 高。每个文件都是你写的,出问题一眼能看出 | 中。配置是生成的,改错地方(直接改 dhcpd.conf)会被覆盖 |
| 适用规模 | 一次性/临时装几台到十几台;或需要极致定制的特殊场景 | 长期维护的装机平台,几十台到几百台,多版本多角色 |
选型建议:
- 学习阶段:一定先手工搭一遍。只用 Cobbler 而不懂 PXE 的人,一旦
cobbler check通过但客户端仍装不上,就完全无从下手。 - 临时任务、装 1~5 台:直接 U 盘装,或手工 PXE,不值得部署 Cobbler。
- 长期装机平台、20 台以上、多版本多角色:用 Cobbler(或 MAAS/Foreman)。手工方案维护成本会随规模线性甚至超线性增长。
- 虚拟化为主的环境:优先"模板克隆 + cloud-init",比 PXE 快一个数量级;PXE 只留给宿主机/裸机。
- 云环境:不要用 PXE,用自定义镜像 + cloud-init + IaC(Terraform)。
- 新建大规模裸机平台:评估 MAAS / Foreman / Tinkerbell,它们的硬件发现和生命周期管理能力远超 Cobbler。
二十五、排错清单
排错的总原则:严格按 PXE 启动流程的顺序,一段一段往后推,确认这一段通了再看下一段。 不要跳着猜。
25.1 客户端根本不进 PXE 菜单
按顺序检查这四层:
第一层:网卡是否设为网络启动
现象:开机直接进入硬盘系统,或提示 "No bootable device",屏幕上完全没有出现 CLIENT MAC ADDR
检查:
- 进 BIOS/UEFI,确认 Network Boot / PXE / Boot from LAN 已启用(有的默认是 Disabled)
- 启动顺序里 Network 在硬盘之前,或开机按 F12/ESC 手工选择网络启动
- UEFI 机器:确认 "UEFI PXE IPv4" 已启用(有的机器默认只开了 IPv6 PXE,会一直超时)
- 虚拟机:VMware 需在虚拟机设置里确认网卡已"连接"且"启动时连接"勾选
- 网线是否插好、交换机端口是否 up、是否被划到了错误的 VLAN
第二层:是否有其他 DHCP 抢答
现象:拿到了一个 IP,但网关/掩码不是你规划的那个;或拿到 IP 后立刻报 PXE-E32/PXE-E53
检查(在服务端):
tcpdump -i eth0 -nn port 67 or port 68
# 看有几个不同的源 IP 在发 DHCP OFFER。超过一个就是抢答
nmap --script broadcast-dhcp-discover
# 直接列出网段内所有 DHCP 服务器
处理:
- 关闭虚拟化平台自带的 DHCP(VMware 虚拟网络编辑器 / VirtualBox 主机网络管理器 / libvirt default 网络)
- 把实验网段从桥接改为"仅主机"或"私有/隔离"网络
- 生产环境:让网络组在装机 VLAN 上做 DHCP snooping,只信任你的服务器
第三层:dhcpd 是否运行,且配了 next-server 和 filename
现象:客户端一直显示 "DHCP..." 然后超时,或报 PXE-E51 / PXE-E55
检查:
systemctl status dhcpd # 服务是否在跑
ss -anup | grep :67 # 是否监听 UDP 67
dhcpd -t -cf /etc/dhcp/dhcpd.conf # 配置语法
grep -E 'next-server|filename' /etc/dhcp/dhcpd.conf # 两行都必须有
tail -f /var/log/messages # 看有没有 DHCPDISCOVER/DHCPOFFER 记录
常见原因:
- 缺 next-server 或 filename(最常见):客户端拿到 IP 但不知道去哪下载什么
- "No subnet declaration for ethX":dhcpd 监听的网卡 IP 不在任何 subnet 段内
- 服务端网卡 IP 与 subnet 网段不一致
- 多网卡服务端上 dhcpd 监听在了错误的网卡上
第四层:tftp 是否能 get 到 pxelinux.0
现象:客户端显示 "PXE-E32: TFTP open timeout" 或 "PXE-T01: File not found"
检查:
ss -anup | grep :69 # tftp 是否监听
ls -l /var/lib/tftpboot/pxelinux.0 # 文件是否存在、权限是否 644
tftp 192.168.100.10 -c get pxelinux.0 # 本机能否取到
# 换一台机器再测一次,验证防火墙
systemctl status tftp.socket # CentOS 7
grep disable /etc/xinetd.d/tftp # CentOS 6,必须是 no
25.2 PXE 错误码含义与处理
| 错误码 | 含义 | 处理 |
|---|---|---|
| PXE-E32: TFTP open timeout | 向 next-server 发了 TFTP 请求但没有任何响应 | ① tftp 服务没启(CentOS 6 忘了 disable=no + 重启 xinetd;CentOS 7 忘了 systemctl start tftp.socket)② 防火墙挡了 UDP 69 ③ next-server 填的 IP 不对(多网卡填错网卡 IP,或 Cobbler 的 next_server 还是 127.0.0.1)④ 服务端与客户端不在同一二层,中间路由器没配 DHCP relay |
| PXE-E11: ARP timeout | 无法解析 next-server 的 MAC,二层不通 | ① 客户端与 TFTP 服务器不在同一网段/VLAN ② 网线/端口/网卡问题 ③ next-server 写了一个网段内不存在的 IP |
| PXE-T01: File not found / PXE-E3B: TFTP Error - File Not Found | TFTP 服务通了,但请求的文件不存在 | ① /var/lib/tftpboot/ 下没有 pxelinux.0(忘了从 syslinux 拷)② filename 拼错(写成 pxelinux.o 字母 O、或写了多余的路径前缀)③ Cobbler 场景:cobbler get-loaders 没执行且 loaders 目录为空,cobbler sync 没生成文件 ④ UEFI 客户端被下发了 pxelinux.0(应为 grubx64.efi) |
| PXE-E51: No DHCP or proxyDHCP offers were received | 没收到任何 DHCP 应答 | dhcpd 没起 / 不在同一广播域 / 防火墙挡 UDP 67 / 客户端网卡与服务端不在同一虚拟网络 |
| PXE-E52: proxyDHCP offers were received. No DHCP offers were received | 只收到 proxyDHCP(如 WDS)应答,没有正常 DHCP | 网段内有 Windows 部署服务在抢,关掉它 |
| PXE-E53: No boot filename received | 拿到了 IP,但 DHCP 没下发 filename | dhcpd.conf 里缺 filename "pxelinux.0";,或被别的 DHCP 抢答了 |
| PXE-E55: proxyDHCP service did not reply to request on port 4011 | proxyDHCP 相关 | 通常同 E52,网段内有其他部署服务 |
| PXE-E61: Media test failure, check cable | 物理链路不通 | 网线、交换机端口、虚拟机网卡未连接 |
| PXE-E78: Could not locate boot server | 找不到引导服务器 | next-server 配置错误或不可达 |
| Boot failed: press a key to retry / No bootable device | 所有启动项都失败 | 回到 25.1 第一层,确认 PXE 是否真的启用 |
25.3 菜单出来了,但下载 vmlinuz 卡住或失败
现象:进度条走到一半不动了;或很慢(几十 KB/s);或报 "Failed to load ldlinux.c32"
原因与处理:
1) vmlinuz / initrd.img 不在 tftpboot 下或路径与 default 里的 kernel 行不匹配
→ ls -l /var/lib/tftpboot/ ;核对 default 里 kernel/append 的相对路径
→ Cobbler 场景检查 /var/lib/tftpboot/images/<distro>/ 下是否有文件,没有就 cobbler sync
2) 缺少 syslinux 6.x 需要的库文件
→ 报 "Failed to load ldlinux.c32" / "Boot failed"
→ cp /usr/share/syslinux/{ldlinux.c32,libcom32.c32,libutil.c32,menu.c32,vesamenu.c32} /var/lib/tftpboot/
→ 注意:pxelinux.0 与 *.c32 必须来自同一个 syslinux 版本,混用会加载失败
(典型错误:pxelinux.0 从光盘 isolinux 拷,menu.c32 从系统 /usr/share/syslinux 拷)
3) TFTP 传输本来就慢(UDP 单包 512 字节,无窗口)
→ initrd.img 有 40~60MB,30~60 秒是正常的,别急着重启
→ 可开启 tsize/blksize 扩展:in.tftpd 加 -v -m 参数
→ 大文件建议改用 HTTP 引导(lpxelinux.0 支持 http:// 前缀的 kernel/initrd)
4) 交换机开启了 STP 导致端口前几十秒不转发
→ 端口配 portfast / edge port
5) 客户端内存太小,initrd 解压失败
→ 内存调到 2G 以上
25.4 进入 anaconda 但报找不到安装源
现象:出现 "Error setting up base repository" / "Failed to synchronize cache"
或停在 "Installation source" 让你手工填 URL
排查(按 Ctrl+Alt+F2 切到 tty2 执行):
ip a # 客户端有没有 IP?没有的话是 anaconda 阶段网卡没起
ping <server-ip> # 通不通
curl -I http://<server>/centos7/repodata/repomd.xml # 最关键的一条
常见原因:
1) url / inst.repo 写错
- 路径大小写、少写或多写结尾斜杠、目录名与实际不符
- 指向的目录下没有 repodata/(拷贝镜像时漏了隐藏文件,要用 cp -a /mnt/cdrom/. /目标/)
2) httpd 没启动
→ systemctl status httpd ; systemctl start httpd
3) SELinux 阻止
→ 用软链接发布时最典型,报 403
→ setenforce 0 ;或 chcon -R -t httpd_sys_content_t /var/www/html/ ;restorecon -Rv /var/www/html
→ tail -f /var/log/audit/audit.log 能看到 avc denied
4) 防火墙未放行 TCP 80
→ firewall-cmd --add-service=http --permanent ; firewall-cmd --reload
5) 挂载点掉了
→ 服务端 df -h 看 /mnt/cdrom 还在不在(ISO 被 umount 或虚拟机 ISO 被断开)
6) anaconda 阶段网卡没配置
→ append 里加 ip=dhcp 或 ksdevice=bootif(配合 ipappend 2)
→ 多网卡机器不指定网卡时,anaconda 可能选了没插线的那块
7) Cobbler 场景:ks 里用了 $tree 但 settings 的 server 还是 localhost
→ cobbler profile getks --name=xxx 看渲染出来的 url 是什么
25.5 报找不到 ks 文件
现象:安装启动后直接进入交互式安装界面(完全无视你的 ks),
或屏幕上闪过 "Error downloading kickstart file" / "unable to retrieve"
排查思路:从客户端环境用 curl 验证 ks 的 URL——这是最高效的一招
Ctrl+Alt+F2 切到 tty2,执行:
curl http://192.168.100.10/ks/ks.cfg
- 返回 404 → 路径/文件名错,或文件不在 /var/www/html/ks/ 下
- 返回 403 → 权限或 SELinux(chmod 644 + restorecon)
- 连接被拒/超时 → httpd 没起 或 防火墙
- 能返回内容 → 说明 URL 没问题,问题在 ks 内容本身(见 25.6)
其他常见原因:
- 内核参数用错版本:CentOS 6 用 ks=,CentOS 7 用 inst.ks=(写 ks= 也兼容,但写成 iks=/kss= 就无效)
- URL 里写了 https 但服务端只有 http
- Cobbler 的 ks URL 格式写错,正确是:
http://<server>/cblr/svc/op/ks/profile/<profile-name>
http://<server>/cblr/svc/op/ks/system/<system-name>
在服务端先 curl 验证一次
- ks 文件用 Windows 记事本编辑过,带了 CRLF 换行或 UTF-8 BOM
→ dos2unix ks.cfg ;sed -i '1s/^\xEF\xBB\xBF//' ks.cfg
25.6 ks 语法错误导致中途停在交互界面
现象:安装走到某一步(选语言/设密码/分区)就停下来等人,或直接报 "There was an error running the kickstart script"
定位方法:
1) 先在服务端用 ksvalidator 校验(注意指定版本)
ksvalidator -v RHEL7 /var/www/html/ks/ks.cfg
ksvalidator http://192.168.100.10/ks/ks.cfg
Cobbler 场景:
cobbler validateks
cobbler profile getks --name=xxx | ksvalidator /dev/stdin
2) 看客户端的 tty 上的报错
Ctrl+Alt+F1 主安装界面(错误提示通常在这里)
Ctrl+Alt+F2 shell
Ctrl+Alt+F3 安装日志(/tmp/anaconda.log)
Ctrl+Alt+F4 存储日志(/tmp/storage.log)
Ctrl+Alt+F5 程序日志(/tmp/program.log)
在 tty2 里:
less /tmp/anaconda.log ; less /tmp/syslog ; less /tmp/storage.log
less /tmp/ks-script*.log # %pre/%post 脚本的输出
3) 高频语法问题清单:
- 漏写 %end(CentOS 7 起每个段都必须闭合)—— 排第一
- ks 文件里有中文字符(包括注释)—— 会直接无法启动安装
- 缺少必答项:漏了 rootpw / 漏了 timezone / 漏了 lang / 漏了分区 → 停在那一步
- CentOS 7 没写 eula --agreed → 停在许可协议确认
- 用了目标版本不支持的指令(如在 CentOS 8 上写 auth/authconfig)
- 包名写错且没加 --ignoremissing → 停在软件包依赖错误
- Cobbler 场景:ks 里 shell 的 $VAR 没写成 \$VAR 或没用 #raw 包起来
→ Cheetah 渲染时报 NotFound 错误,getks 就能看出来
25.7 分区失败
现象:报 "Could not allocate requested partitions" / "specified nonexistent disk sda"
/ "insufficient space" / 停在手工分区界面
原因与处理:
1) 磁盘名不符(最常见)
- 物理机 SATA/SAS:sda
- KVM virtio 磁盘:vda(写 sda 必然失败)
- NVMe:nvme0n1,分区名是 nvme0n1p1(不是 nvme0n11)
- 部分 RAID 卡:sda,也可能是 cciss/c0d0 或 mmcblk0(嵌入式/SD 卡)
→ 在 tty2 里 lsblk / cat /proc/partitions 看真实盘符
→ ks 里避免硬编码,用 %pre 动态探测(见 7.6 的例子),或用 ignoredisk --only-use= 配合
2) --asprimary 超过 4 个(MBR 最多 4 个主分区)
→ 去掉多余的 --asprimary,或改用 GPT/LVM
3) --size 之和超过磁盘容量
→ 减小 size,或用 --grow 让最后一个分区吃剩余空间
4) UEFI 机器缺 /boot/efi 分区
→ 加 part /boot/efi --fstype=efi --size=600
5) BIOS + GPT 缺 biosboot 分区
→ 加 part biosboot --fstype=biosboot --size=1
6) 磁盘上有残留的 RAID/LVM 元数据,clearpart 清不掉
→ %pre 里先 dd if=/dev/zero of=/dev/sda bs=1M count=10
或 wipefs -a /dev/sda ;vgremove -f / mdadm --zero-superblock
7) clearpart 把数据盘也清了(事故)
→ 永远加 --drives= 限定范围,配合 ignoredisk --only-use=
8) 磁盘太小装不下选中的软件包组
→ 减少 %packages,或加大磁盘
25.8 装完不重启 / 反复重启
1) 装完停在 "Complete!" 不动
→ ks 里没写 reboot(默认是 halt,等人按回车)
→ 加 reboot 或 poweroff
2) 反复无限重装(装完重启又进 PXE 又装一遍)—— 高频坑
→ 原因:ks 里写了 reboot,而客户端 BIOS 第一启动顺序仍是网络启动
→ 解法一:pxelinux.cfg/default 里让 local(localboot 0xffff)成为 menu default,
timeout 设短(如 30 = 3 秒),超时自动从硬盘启动
→ 解法二:ks 里改用 poweroff,装完关机,人工确认后改启动顺序
→ 解法三(Cobbler,推荐):settings 里 pxe_just_once: 1
或手工 cobbler system edit --name=xx --netboot-enabled=0
这样该 MAC 的专属菜单会变成 localboot
→ 解法四:装完后从交换机上把该端口的 PXE VLAN 撤掉
3) 装完起不来,报 "no bootable device" / grub rescue
→ bootloader --location=mbr 漏写,或 --boot-drive 指到了错误的盘
→ UEFI 机器缺 /boot/efi 分区
→ 多磁盘时 grub 装到了 sdb,而 BIOS 从 sda 启动
25.9 cobbler check 报错逐项对应
| check 报的项 | 对应处理 |
|---|---|
'server' field ... must be set to something other than localhost |
改 /etc/cobbler/settings 的 server: 为本机真实 IP(多网卡填装机网段的 IP) |
'next_server' field ... other than 127.0.0.1 |
改 next_server: 为本机真实 IP |
SELinux is enabled |
setenforce 0 + 改 /etc/selinux/config 为 disabled |
change 'disable' to 'no' in /etc/xinetd.d/tftp |
sed -i '/disable/s/yes/no/' /etc/xinetd.d/tftp 然后 systemctl restart xinetd |
Some network boot-loaders are missing from /var/lib/cobbler/loaders |
cobbler get-loaders;无外网则装新版 syslinux 并手工拷 pxelinux.0/menu.c32 到 loaders |
enable and start rsyncd.service |
systemctl enable --now rsyncd |
comment out 'dists' on /etc/debmirror.conf |
注释 @dists="sid"; |
comment out 'arches' on /etc/debmirror.conf |
注释 @arches="i386"; |
default_password_crypted ... still set to 'cobbler' |
openssl passwd -1 -salt 'xxx' 'yourpass' 生成后替换 settings 中该行 |
service cobblerd is not running |
systemctl start cobblerd;起不来看 /var/log/cobbler/cobbler.log |
httpd does not appear to be running |
systemctl start httpd |
fencing tools were not found |
yum -y install fence-agents(不做电源管理可忽略) |
dhcpd.conf is not managed |
settings 里 manage_dhcp: 1 |
cannot find /usr/bin/cobbler-ext-nodes |
装 cobbler 完整包,或忽略(Puppet ENC 才用) |
修完每一项后:systemctl restart cobblerd → cobbler check → cobbler sync。
25.10 Cobbler 其他常见问题
1) cobbler sync 后 dhcpd.conf 被覆盖,自定义配置丢失
→ 症状:昨天手工加的第二个网段、改的网关,今天没了
→ 原因:manage_dhcp:1 时 sync 会用 /etc/cobbler/dhcp.template 重新生成 dhcpd.conf
→ 正确做法:所有 DHCP 改动都做在 /etc/cobbler/dhcp.template 上,然后 cobbler sync
→ 同理适用于 pxedefault.template / rsync.template / named.template
2) cobbler import 报错
- "The path ... does not exist" → ISO 没挂载,或 --path 写错;先 df -h 确认挂载点
- "No space left on device" → /var 空间不足(一张 DVD 要 4~9G)
→ df -h /var ;清理旧 distro(cobbler distro remove)或给 /var 扩容
→ 或用 --available-as 避免拷贝
- "ProtocolError ... 503 Service Unavailable" → SELinux 没关,或 httpd/cobblerd 没启动
- "distro ... already exists" → 换 --name,或先 remove 旧的
- "Unknown breed" / 签名不识别 → cobbler signature update
3) Web UI 打不开或登录失败
- 打不开:确认用 https 不是 http;systemctl status httpd;
tail -f /var/log/httpd/error_log;rpm -q cobbler-web 是否装了
- 502/500:cobblerd 没启动,或 Django 依赖有问题(看 error_log)
- 登录失败:htdigest 的 realm 必须是 "Cobbler"(大写 C);
检查 /etc/cobbler/users.digest 内容;
/etc/cobbler/modules.conf 的 authentication 模块是否为 authn_configfile;
用户是否在 /etc/cobbler/users.conf 的 [admins] 里;
改完重启 httpd 与 cobblerd
- 能登录但操作报权限错误:authorization 模块设为 authz_allowall
4) 多网卡服务端上 server / next_server 填错网卡 IP
→ 症状:客户端拿到 IP 但 TFTP 超时(E32),或进了 anaconda 取不到源
→ 必须填"装机网段那块网卡"的 IP,不是管理网/外网那块
→ 检查:grep -E '^server:|^next_server:' /etc/cobbler/settings
→ 同时确认 dhcpd 监听在装机网段的网卡上
→ 单个 profile 可用 --server 覆盖全局设置(多网段场景)
5) 客户端进了菜单但选了 profile 后立刻回到菜单
→ tftpboot/images/<distro>/ 下没有 vmlinuz/initrd → cobbler sync
→ distro 的 kernel/initrd 路径指向了已删除的 ks_mirror 目录 → 重新 import
6) 装机很慢
→ 检查安装源是 HTTP 还是 NFS/TFTP;用 HTTP
→ /var/www/cobbler 所在磁盘 IO 是否打满(iostat -x 1)
→ 并发装机台数过多时给 httpd 调 MaxRequestWorkers
7) cobbler status 里任务一直是 running
→ 看 /var/log/cobbler/tasks/ 下最新的日志文件,里面有真实报错
二十六、附录:装机后的自动初始化脚本
本节内容来自源文件
自动装机脚本(无后缀,实际是一个 Bash 交互式初始化脚本)。它并非 PXE/Kickstart 级别的自动装机方案,而是新机装好系统后做"一键初始化配置"的菜单脚本:静态 IP 配置、自动安装 tmux/VNC-Viewer 并配置 vim/tmux、自动安装搜狗输入法、安装 Flash 插件。脚本依赖内网 NFS 共享192.168.2.183:/(脚本中称为 soul)。它与本文的关系:这类脚本做的事,在 PXE/Cobbler 方案中应当尽量前移到 Kickstart 的
%post段(见 7.7 节)或交给 Ansible/SaltStack,从而彻底免除装完机还要逐台手工跑脚本的步骤。作为对照阅读的反面/过渡示例保留在此。详见 05-02-常用软件安装与yum源配置.md 详见 09-02-NFS与autofs.md
26.1 脚本作用概述
执行脚本后进入一个循环菜单,用户通过序号选择要执行的功能:
1. 配置你的 IP 地址
2. 自动安装 tmux 和 vncviewer 软件并且配置 tmux 和 vim 编辑器
3. 自动安装搜狗输入法
4. 安装 Flash 插件
Q|q 退出
前置条件:
- 以具有
sudo权限的用户执行; - 能访问内网 NFS 服务器
192.168.2.183,并能挂载其根目录到/guazai; - 系统为 CentOS 7(使用
systemctl、yum、网络配置文件路径/etc/sysconfig/network-scripts/)。
26.2 关键步骤说明
1. 自动识别网卡名称
network_name=$(ifconfig | egrep '^e[a-zA-Z0-9]' | sed -re 's/^([a-zA-Z0-9]+):(.*)/\1/')
net_path="/etc/sysconfig/network-scripts/ifcfg-$network_name"
通过 ifconfig 抓取以 e 开头的网卡名(如 ens33、eth0),并拼接出对应的网卡配置文件路径。
修正:原正则
e[a-Z0-9]在某些 locale 下范围不合法,这里规范为e[a-zA-Z0-9]。
2. 静态 IP 配置函数
set_ip 函数交互式读取用户输入的 NM_CONTROLLED、IP 地址、网关,调用 static_ip 生成配置内容,确认后写入网卡配置文件并重启网络:
sudo chmod 777 $net_path
static_ip > $net_path
sudo chmod 644 $net_path
sudo systemctl restart network
生成的配置项固定为:
DEVICE=<网卡名>
BOOTPROTO=static
NM_CONTROLLED=<用户输入 yes|no>
ONBOOT=yes
TYPE=Ethernet
IPADDR=<用户输入>
NETMASK=255.255.255.0
GATEWAY=<用户输入>
DNS1=223.5.5.5
3. 自动安装 tmux、VNC-Viewer 并配置 vim/tmux
automatic 函数挂载 NFS 共享,从共享中拷贝 vim 配置目录、VNC-Viewer RPM 包和 tmux 配置文件,再用 yum 安装 tmux 和 VNC-Viewer,最后调用 vim 的安装脚本:
sudo mkdir /guazai
sudo mkdir $HOME/0_important
sudo mount 192.168.2.183:/ /guazai
sudo cp /guazai/soul/software/vim $HOME/0_important/ -r
sudo cp /guazai/soul/software/VNC-Viewer-6.18.907-Linux-x64.rpm $HOME/0_important/
sudo cp /guazai/soul/software/tmux.conf $HOME/.tmux.conf
sudo yum install tmux -y
sudo yum install $HOME/0_important/VNC-Viewer-6.18.907-Linux-x64.rpm -y
source $HOME/0_important/vim/linux_install.sh
4. 自动安装搜狗输入法
install_sougou 函数从内网共享拷贝搜狗 RPM 包,添加 EPEL 与第三方 mosquito 源,安装 fcitx 及配置工具,两次执行 rpm -ivh 解决依赖,最后切换输入法框架:
sudo yum install epel-release.noarch
sudo yum-config-manager --add-repo=https://copr.fedoraproject.org/coprs/mosquito/myrepo/repo/epel-7/mosquito-myrepo-epel-7.repo
sudo rpm -ivh $HOME/0_important/sogoupinyin-1.2.0.0056-1.fc22.x86_64.rpm
sudo yum install fcitx
sudo yum install fcitx-configtool.x86_64
sudo rpm -ivh $HOME/0_important/sogoupinyin-1.2.0.0056-1.fc22.x86_64.rpm
gsettings set org.gnome.settings-daemon.plugins.keyboard active false
sudo imsettings-switch fcitx
输入 y 后重启使配置生效。该流程与《01-常用软件安装与环境配置》中的搜狗输入法章节对应。
5. 安装 Flash 插件
install_flash 从内网共享拷贝 libflashplayer.so 到 Firefox 插件目录:
sudo cp /guazai/works/8_唐旭/libflashplayer.so $HOME/0_important/
sudo mv $HOME/0_important/libflashplayer.so /lib64/mozilla/plugins/
26.3 使用方法
-
将脚本保存到新机,例如
/usr/local/bin/auto-init.sh; -
添加可执行权限:
chmod +x /usr/local/bin/auto-init.sh -
确保能访问 NFS 服务器
192.168.2.183后执行:./auto-init.sh -
根据菜单输入序号执行对应功能,输入
Q或q退出。
26.4 完整脚本
#!/bin/bash
#截取本机网卡名称
network_name=$(ifconfig | egrep '^e[a-zA-Z0-9]' | sed -re 's/^([a-zA-Z0-9]+):(.*)/\1/')
#网络配置文件路径
net_path="/etc/sysconfig/network-scripts/ifcfg-$network_name"
#显示配置的信息
function static_ip () {
clear
echo "DEVICE=$network_name"
echo "BOOTPROTO=static"
echo "NM_CONTROLLED=$NM_CONTROLLED"
echo "ONBOOT=yes"
echo "TYPE=Ethernet"
echo "IPADDR=$ipaddr"
echo "NETMASK=255.255.255.0"
echo "GATEWAY=$gateway"
echo "DNS1=223.5.5.5"
}
#输入自己要配置的ip,并重启网卡生效
function set_ip () {
clear
echo "设置是否托管网络输入:yes|no"
read -p " " NM_CONTROLLED
echo "设置你的ip地址:"
read -p " " ipaddr
echo "设置你的网关:"
read -p " " gateway
clear
echo "你的配置文件如下:"
echo "--------------------------"
static_ip
echo "--------------------------"
echo "确认无误后请输入y生效,输入其他退出"
read -p " " answer
if [ $answer == y ]; then
sudo chmod 777 $net_path
static_ip > $net_path
sudo chmod 644 $net_path
sudo systemctl restart network
echo "ip配置成功"
else
continue
fi
}
#自动安装VNC和tmux,并配置vim和tmux
function automatic () {
clear
sudo mkdir /guazai
sudo mkdir $HOME/0_important
sudo mount 192.168.2.183:/ /guazai
sudo cp /guazai/soul/software/vim $HOME/0_important/ -r
sudo cp /guazai/soul/software/VNC-Viewer-6.18.907-Linux-x64.rpm $HOME/0_important/
sudo cp /guazai/soul/software/tmux.conf $HOME/.tmux.conf
sudo yum install tmux -y
sudo yum install $HOME/0_important/VNC-Viewer-6.18.907-Linux-x64.rpm -y
source $HOME/0_important/vim/linux_install.sh
echo "配置成功"
}
function install_sougou () {
clear
sudo mount 192.168.2.183:/ /guazai
sudo cp /guazai/works/z_安装搜狗输入法教程和rpm包/sogoupinyin-1.2.0.0056-1.fc22.x86_64.rpm $HOME/0_important/
sudo yum install epel-release.noarch
sudo yum-config-manager --add-repo=https://copr.fedoraproject.org/coprs/mosquito/myrepo/repo/epel-7/mosquito-myrepo-epel-7.repo
sudo rpm -ivh $HOME/0_important/sogoupinyin-1.2.0.0056-1.fc22.x86_64.rpm
sudo yum install fcitx
sudo yum install fcitx-configtool.x86_64
sudo rpm -ivh $HOME/0_important/sogoupinyin-1.2.0.0056-1.fc22.x86_64.rpm
gsettings set org.gnome.settings-daemon.plugins.keyboard active false
sudo imsettings-switch fcitx
echo "输入y重启,使搜狗生效"
read -p " " re
[ $re == y ] && reboot
}
function install_flash () {
clear
sudo cp /guazai/works/8_唐旭/libflashplayer.so $HOME/0_important/
sudo mv $HOME/0_important/libflashplayer.so /lib64/mozilla/plugins/
echo "flash插件安装成功"
}
#本脚本能执行的功能
function something () {
echo "----------------------------------------------------"
echo "1.配置你的ip地址"
echo "----------------------------------------------------"
echo "2.自动安装tmux和vncviewer软件并且配置tmux和vim编辑器"
echo "----------------------------------------------------"
echo "3.自动安装搜狗输入法"
echo "----------------------------------------------------"
echo "4.安装flash插件"
echo "----------------------------------------------------"
}
while : ; do
echo "-----------------欢迎使用本脚本---(需要挂载soul)-------------------"
echo "请输入序号来选择你要做的事Q|q退出:"
echo
something
read -p " " operation
case $operation in
1)
set_ip
;;
2)
automatic
;;
3)
install_sougou
;;
4)
install_flash
;;
Q|q)
echo "-----------------------谢谢您的使用-----------------------------"
exit
;;
*)
clear
echo "错误的输入,请重新输入"
continue
;;
esac
done
练习
两份源文档均未附带练习题,以下练习围绕本章内容新编。
练习 1:画出 PXE 完整启动流程并标注每步用到的服务与端口
要求:用文字或图形画出从客户端加电到 anaconda 开始安装的完整链路,每一步标明使用的协议、端口、传输的文件。
参考答案:
步骤 服务/协议 端口 传输内容
1. 网卡 PXE ROM 广播 DHCP DISCOVER DHCP/UDP 68→67 无(广播请求)
2. DHCP 返回 OFFER/ACK DHCP/UDP 67→68 IP、掩码、网关、
next-server、filename
3. 客户端向 next-server 下载引导程序 TFTP/UDP 69 pxelinux.0
4. pxelinux.0 读取菜单配置 TFTP/UDP 69 pxelinux.cfg/<UUID>
→ 01-<MAC> → <IP-hex>
→ default
+ vesamenu.c32 + boot.msg
5. 按所选 LABEL 下载内核与初始内存盘 TFTP/UDP 69 vmlinuz、initrd.img
6. 内核启动,initrd 中 anaconda 运行 无 — —
7. anaconda 下载 Kickstart 应答文件 HTTP/TCP 80 ks.cfg
(或 FTP 21 / NFS 2049+111)
8. anaconda 按 ks 中 url 获取安装源 HTTP/TCP 80 repodata/、Packages/*.rpm
9. 分区→格式化→装包→%post→reboot 无 — —
关键点:
- TFTP 只传"小而必要"的引导文件(pxelinux.0、菜单、vmlinuz、initrd.img)
- HTTP/FTP/NFS 传"大"的安装源与 ks 文件
- next-server + filename 是 DHCP 与 TFTP 之间的桥梁,缺一不可
- UEFI 客户端第 3 步下载的是 grubx64.efi/shimx64.efi,第 4 步读的是 grub.cfg
练习 2:手工搭建 PXE + Kickstart,完成一台虚拟机的无人值守安装
要求:服务端 192.168.100.10/24,用 HTTP 提供安装源与 ks,客户端 PXE 启动后全程无人干预装完 CentOS 7 最小化系统。
参考答案:完整操作清单见本文第 9.1 节,验证过程见 9.2 节。要点自查:
# 五项必须逐一验证通过
dhcpd -t -cf /etc/dhcp/dhcpd.conf # 1. DHCP 语法
grep -E 'next-server|filename' /etc/dhcp/dhcpd.conf # 2. PXE 两行关键配置
tftp 192.168.100.10 -c get pxelinux.0 # 3. TFTP 可取引导文件
curl -I http://192.168.100.10/centos7/repodata/repomd.xml # 4. 安装源可访问
ksvalidator -v RHEL7 /var/www/html/ks/ks.cfg # 5. ks 语法正确
curl http://192.168.100.10/ks/ks.cfg | head # 且 URL 可访问
# 确认虚拟化平台自带的 DHCP 已关闭(否则一定失败)
nmap --script broadcast-dhcp-discover
练习 3:编写一份带 LVM 分区与 %post 初始化的 ks 文件并用 ksvalidator 校验
要求:LVM 卷组名 vg_sys,含 /boot(1G 标准分区)、/(30G)、swap(4G)、/var(20G)、/data(剩余全部);%post 中配置内网 yum 源、注入 SSH 公钥、关闭 postfix 与 firewalld、设置时间同步;必须通过 ksvalidator。
参考答案:
install
text
skipx
eula --agreed
firstboot --disable
reboot
url --url="http://192.168.100.10/centos7"
lang en_US.UTF-8
keyboard --vckeymap=us --xlayouts='us'
timezone Asia/Shanghai --utc
rootpw --iscrypted $6$abcdefgh$REPLACE_WITH_YOUR_OWN_HASH
user --name=devops --groups=wheel --iscrypted --password=$6$abcdefgh$REPLACE_ME
auth --useshadow --passalgo=sha512
selinux --permissive
firewall --enabled --service=ssh
network --bootproto=dhcp --device=eth0 --onboot=yes --noipv6
bootloader --location=mbr --boot-drive=sda --append="net.ifnames=0 biosdevname=0 crashkernel=auto"
ignoredisk --only-use=sda
zerombr
clearpart --all --initlabel --drives=sda
part /boot --fstype=xfs --size=1024 --asprimary --ondisk=sda
part pv.01 --size=1 --grow --ondisk=sda
volgroup vg_sys pv.01
logvol / --vgname=vg_sys --name=lv_root --fstype=xfs --size=30720
logvol swap --vgname=vg_sys --name=lv_swap --fstype=swap --size=4096
logvol /var --vgname=vg_sys --name=lv_var --fstype=xfs --size=20480
logvol /data --vgname=vg_sys --name=lv_data --fstype=xfs --size=1 --grow
%packages --nobase --ignoremissing
@^minimal
@core
vim-enhanced
net-tools
wget
lsof
tcpdump
chrony
bash-completion
-postfix
%end
%post --log=/root/ks-post.log
#!/bin/bash
set -x
# 内网 yum 源
mkdir -p /etc/yum.repos.d/bak
mv /etc/yum.repos.d/CentOS-*.repo /etc/yum.repos.d/bak/ 2>/dev/null
cat > /etc/yum.repos.d/local.repo <<'EOF'
[base]
name=local-base
baseurl=http://192.168.100.10/centos7/
enabled=1
gpgcheck=0
EOF
yum clean all
# SSH 公钥
mkdir -p /root/.ssh && chmod 700 /root/.ssh
cat > /root/.ssh/authorized_keys <<'EOF'
ssh-rsa AAAAB3NzaC1yc2EAAAADAQABAAABgQC... ops@jumpserver
EOF
chmod 600 /root/.ssh/authorized_keys
# 关闭无用服务
for svc in postfix firewalld; do systemctl disable ${svc} 2>/dev/null; done
# 时间同步
sed -i '/^server /d' /etc/chrony.conf
echo "server ntp1.aliyun.com iburst" >> /etc/chrony.conf
systemctl enable chronyd
echo "Installed at $(date '+%F %T')" > /etc/motd
%end
校验:
ksvalidator -v RHEL7 /var/www/html/ks/lvm.cfg
# 无输出即通过
# 常见失败点自查:
# - 漏 %end
# - /boot 被放进了 LVM(必须是标准分区)
# - logvol 的 --vgname 与 volgroup 名字不一致
# - part pv.01 与 volgroup vg_sys pv.01 的标识符不匹配
# - 文件里出现了中文字符
练习 4:部署 Cobbler 并通过 cobbler check 全部检查项
要求:在 CentOS 7 上部署 Cobbler,让 cobbler check 输出 No configuration problems found. All systems go.
参考答案:
yum -y install epel-release
yum -y install cobbler cobbler-web tftp tftp-server rsync xinetd httpd httpd-devel \
httpd-tools syslinux dhcp dhcp-common dhcp-libs pykickstart fence-agents \
debmirror system-config-kickstart
systemctl enable --now httpd cobblerd
# 逐项修复(IP 换成自己的)
sed -i 's/^server:.*/server: 3.3.3.4/' /etc/cobbler/settings
sed -i 's/^next_server:.*/next_server: 3.3.3.4/' /etc/cobbler/settings
sed -i 's/^manage_dhcp:.*/manage_dhcp: 1/' /etc/cobbler/settings
sed -i 's/^pxe_just_once:.*/pxe_just_once: 1/' /etc/cobbler/settings
setenforce 0 ; sed -i 's/^SELINUX=.*/SELINUX=disabled/' /etc/selinux/config
sed -i '/disable/s/yes/no/' /etc/xinetd.d/tftp
cobbler get-loaders || cp /usr/share/syslinux/{pxelinux.0,menu.c32} /var/lib/cobbler/loaders/
systemctl enable --now rsyncd
sed -i 's/^@dists=/#@dists=/' /etc/debmirror.conf
sed -i 's/^@arches=/#@arches=/' /etc/debmirror.conf
NEWPASS=$(openssl passwd -1 -salt 'mysalt01' 'MyStrongPass')
sed -i "s|^default_password_crypted:.*|default_password_crypted: \"${NEWPASS}\"|" /etc/cobbler/settings
systemctl restart cobblerd xinetd
cobbler check # 期望:No configuration problems found. All systems go.
cobbler sync
练习 5:导入镜像并创建自定义 profile
要求:导入 CentOS 7.3 ISO,创建一个使用自定义 ks 的 profile new_centos7.3,并验证渲染结果。
参考答案:
mkdir -p /yum && mount -o loop /root/CentOS-7-x86_64-DVD-1611.iso /yum
cobbler import --path=/yum/ --name=centos7.3 --arch=x86_64
cobbler distro list # centos7.3-x86_64
cobbler profile list # centos7.3-x86_64
# 准备自定义 ks(用 $tree 而非硬编码 IP)
cp /root/anaconda-ks.cfg /var/lib/cobbler/kickstarts/centos7.3.ks
vim /var/lib/cobbler/kickstarts/centos7.3.ks
# 把 url 行改为:url --url=$tree
# 把 rootpw 行改为:rootpw --iscrypted $default_password_crypted
cobbler profile add --name=new_centos7.3 \
--distro=centos7.3-x86_64 \
--kickstart=/var/lib/cobbler/kickstarts/centos7.3.ks \
--kopts="net.ifnames=0 biosdevname=0 text"
cobbler profile list # 应出现 new_centos7.3
cobbler profile report --name=new_centos7.3 | grep -i kickstart
cobbler profile getks --name=new_centos7.3 # 查看渲染后的最终 ks
cobbler validateks
systemctl restart cobblerd ; cobbler sync ; systemctl restart xinetd
curl http://3.3.3.4/cblr/svc/op/ks/profile/new_centos7.3 | head
练习 6:用 system 按 MAC 绑定,让两台机器装成不同分区方案
要求:web01(MAC 00:0c:29:aa:bb:cc)装标准分区固定 IP .51;db01(MAC 00:0c:29:dd:ee:ff)装 LVM 大 /data 分区固定 IP .61。两台机器 PXE 启动后不出现菜单,直接装各自的方案。
参考答案:
# 1. 两份 ks(分区方案不同)
# /var/lib/cobbler/kickstarts/c7-web.ks → 标准分区
# /var/lib/cobbler/kickstarts/c7-db.ks → LVM,/data 占剩余全部
# 2. 两个 profile
cobbler profile add --name=c7-web --distro=centos7.3-x86_64 \
--kickstart=/var/lib/cobbler/kickstarts/c7-web.ks
cobbler profile add --name=c7-db --distro=centos7.3-x86_64 \
--kickstart=/var/lib/cobbler/kickstarts/c7-db.ks
# 3. 两个 system,按 MAC 绑定 + 固定 IP
cobbler system add --name=web01 --profile=c7-web \
--interface=eth0 --mac=00:0c:29:aa:bb:cc \
--ip-address=192.168.100.51 --subnet=255.255.255.0 \
--gateway=192.168.100.1 --name-servers="223.5.5.5" \
--hostname=web01.example.com --static=1 --netboot-enabled=1
cobbler system add --name=db01 --profile=c7-db \
--interface=eth0 --mac=00:0c:29:dd:ee:ff \
--ip-address=192.168.100.61 --subnet=255.255.255.0 \
--gateway=192.168.100.1 --name-servers="223.5.5.5" \
--hostname=db01.example.com --static=1 --netboot-enabled=1
cobbler sync
# 4. 验证:应生成两个 MAC 专属菜单,且 dhcpd.conf 里有两个 host 段
ls /var/lib/tftpboot/pxelinux.cfg/
# 01-00-0c-29-aa-bb-cc 01-00-0c-29-dd-ee-ff default
cat /var/lib/tftpboot/pxelinux.cfg/01-00-0c-29-dd-ee-ff
grep -A6 'host db01' /etc/dhcp/dhcpd.conf
cobbler system report --name=db01
curl http://3.3.3.4/cblr/svc/op/ks/system/db01 | grep -E 'logvol|part'
# 5. 两台虚拟机的 MAC 改成对应值后 PXE 启动,应各自直接开始安装、不出现菜单
# 6. 装完后确认 netboot 已自动关闭(pxe_just_once: 1 生效)
cobbler system report --name=db01 | grep -i netboot
练习 7:把 DHCP 网关改动正确地做在模板上,并验证 sync 后不丢失
要求:把装机网段的网关从 192.168.100.1 改为 192.168.100.254,并证明多次 cobbler sync 后改动依然存在。
参考答案:
# 错误做法(会被覆盖):直接改 /etc/dhcp/dhcpd.conf
# 正确做法:改模板
vim /etc/cobbler/dhcp.template
# option routers 192.168.100.254;
cobbler sync
# 验证改动已生效
grep 'option routers' /etc/dhcp/dhcpd.conf # 应为 192.168.100.254
# 反复 sync 两次再验证,证明不会丢失
cobbler sync ; cobbler sync
grep 'option routers' /etc/dhcp/dhcpd.conf # 依然是 192.168.100.254
# 对照实验(理解为什么不能改 dhcpd.conf):
sed -i 's/192.168.100.254/192.168.100.99/' /etc/dhcp/dhcpd.conf
grep 'option routers' /etc/dhcp/dhcpd.conf # 此时是 .99
cobbler sync
grep 'option routers' /etc/dhcp/dhcpd.conf # 变回 .254 —— 手工改动被模板覆盖了
# 结论:dhcpd.conf 是生成物,只读;所有改动必须做在 /etc/cobbler/dhcp.template
练习 8:故意写错 ks 的 url,完成一次完整排错
要求:把 ks 里的 url --url= 改成一个不存在的路径,触发失败,然后按分层排查法定位并修复,记录每一步的判断依据。
参考答案:
【制造故障】
sed -i 's|http://192.168.100.10/centos7|http://192.168.100.10/centos77|' /var/www/html/ks/ks.cfg
【现象】
客户端 PXE 菜单正常出现 → 内核和 initrd 加载正常 → 进入 anaconda 后报
"Error setting up base repository" 并停下来要求手工填写安装源
【排查步骤与判断依据】
1) 菜单出现了 → 说明 DHCP、TFTP、pxelinux.0、菜单文件都正常,
故障点必在第 7 步之后(获取 ks / 安装源)
2) 内核和 initrd 加载成功、进入了 anaconda
→ 说明 TFTP 传输 vmlinuz/initrd.img 也正常
3) anaconda 起来了说明 ks 被读到了(否则会直接进交互式安装向导,
而不是报"安装源错误")→ 故障点定位在"安装源"而不是"ks 文件本身取不到"
4) Ctrl+Alt+F2 切到 tty2,从客户端环境实测:
ip a → 有 IP,网络正常
ping 192.168.100.10 → 通,二层三层正常
curl -I http://192.168.100.10/ks/ks.cfg → 200,ks 可取
curl -I http://192.168.100.10/centos77/repodata/repomd.xml → 404 ← 找到了
curl -I http://192.168.100.10/centos7/repodata/repomd.xml → 200
结论:ks 里的 url 路径写错(centos77 应为 centos7)
5) Ctrl+Alt+F3 看 /tmp/anaconda.log,能看到对 centos77 的 404 请求,
与上面的判断互相印证
【修复】
服务端:
sed -i 's|/centos77|/centos7|' /var/www/html/ks/ks.cfg
ksvalidator -v RHEL7 /var/www/html/ks/ks.cfg
curl -I http://192.168.100.10/centos7/repodata/repomd.xml # 确认 200
客户端重启重装即可。
【延伸练习:另外三种同类故障的现象差异(用于建立"现象→根因"的映射)】
a) 把 ks 的 URL 写错(inst.ks 指向不存在的文件)
→ 现象:直接进入交互式安装向导(anaconda 完全没拿到应答文件)
b) 停掉 httpd(systemctl stop httpd)
→ 现象:ks 和安装源同时不可用,客户端 curl 报 Connection refused
c) 打开 SELinux 且用软链接发布安装源
→ 现象:curl 返回 403 而不是 404,服务端 /var/log/audit/audit.log 有 avc denied
牢记:404=路径错,403=权限/SELinux,拒绝连接=服务没起,超时=防火墙或网络不通
本章小结
PXE 启动流程速查图
客户端加电
│
├─① DHCP DISCOVER (UDP 68→67) ──────────→ dhcpd
│ ←── OFFER/ACK:IP + 网关 + next-server + filename
│
├─② TFTP get pxelinux.0 (UDP 69) ───────→ tftp-server
│ (UEFI 则是 grubx64.efi / shimx64.efi)
│
├─③ TFTP get pxelinux.cfg/01-<MAC> → …… → pxelinux.cfg/default
│ + vesamenu.c32 + boot.msg → 显示引导菜单
│
├─④ TFTP get vmlinuz + initrd.img ──────→ tftp-server
│
├─⑤ 内核启动 → anaconda 运行 → 解析内核参数 inst.ks= / inst.repo=
│
├─⑥ HTTP GET /ks/ks.cfg (TCP 80) ───────→ httpd
│
├─⑦ HTTP GET /centos7/{repodata,Packages} → httpd
│
└─⑧ 分区 → 格式化 → 装包 → %post → reboot/poweroff 完成
四个服务与端口清单
| 服务 | 端口/协议 | 负责 | 关键配置文件 |
|---|---|---|---|
| dhcpd | UDP 67 | 分配 IP + 告知引导文件位置 | /etc/dhcp/dhcpd.conf(next-server + filename) |
| tftp | UDP 69 | 传输引导文件 | CentOS 6:/etc/xinetd.d/tftp(disable=no);CentOS 7:tftp.socket;根目录 /var/lib/tftpboot |
| httpd | TCP 80 | 提供安装源 + ks 文件 | /etc/httpd/conf.d/,目录 /var/www/html/ |
| (可选)vsftpd / nfs | TCP 21 / 2049+111 | 同上,二选一 | /etc/vsftpd/vsftpd.conf / /etc/exports |
| rsyncd | TCP 873 | Cobbler 镜像同步/多机房复制 | /etc/rsyncd.conf(模板 /etc/cobbler/rsync.template) |
Kickstart 常用配置项速查表
| 类别 | 配置项 |
|---|---|
| 安装源 | url --url= / nfs --server= --dir= / cdrom / harddrive / repo --name= --baseurl= |
| 模式 | install text graphical cmdline skipx eula --agreed firstboot --disable |
| 本地化 | lang keyboard --vckeymap= --xlayouts= timezone Asia/Shanghai --utc |
| 账号 | rootpw --iscrypted user --name= --groups=wheel --iscrypted --password= |
| 安全 | auth/authconfig --useshadow --passalgo=sha512 selinux --disabled|--permissive|--enforcing firewall --disabled|--enabled --service=ssh |
| 网络 | network --bootproto=dhcp|static --device= --ip= --netmask= --gateway= --nameserver= --onboot=yes --hostname= --noipv6 --nodefroute |
| 引导 | bootloader --location=mbr --boot-drive=sda --append="net.ifnames=0 rhgb quiet" |
| 清盘 | zerombr clearpart --all --initlabel --drives=sda ignoredisk --only-use=sda |
| 分区 | part <挂载点> --fstype= --size= --grow --maxsize= --asprimary --ondisk= --onpart= --noformat |
| LVM | part pv.01 --grow → volgroup vg_sys pv.01 → logvol / --vgname=vg_sys --name=lv_root --fstype=xfs --size= |
| UEFI | part /boot/efi --fstype=efi --size=600 --fsoptions="umask=0077,shortname=winnt" |
| 结束 | reboot / poweroff / halt |
| 段 | %packages --nobase --ignoremissing %pre %post --nochroot --log= %addon com_redhat_kdump + %end |
| 校验 | ksvalidator -v RHEL7 ks.cfg / ksflatten / ksverdiff -f RHEL6 -t RHEL7 |
Cobbler 常用命令速查表
# ---- 检查与同步 ----
cobbler check # 部署检查(必做)
cobbler sync # 生成 dhcpd.conf + tftpboot 菜单(改完必做)
cobbler sync --systems=db01 # 只同步单个 system
cobbler status # 查看装机任务状态
cobbler list / cobbler report # 列出/详报所有对象
cobbler version / cobbler signature update
# ---- distro ----
cobbler import --path=/yum/ --name=centos7.3 --arch=x86_64
cobbler distro list / report --name=xx / edit --name=xx --kopts="..." / remove --name=xx
# ---- profile ----
cobbler profile add --name=c7-min --distro=centos7.3-x86_64 \
--kickstart=/var/lib/cobbler/kickstarts/xx.ks --kopts="text" --ksmeta="k=v" --repos="epel7"
cobbler profile list / report --name=xx / edit --name=xx --kickstart=yy.ks
cobbler profile copy --name=a --newname=b / remove --name=xx
cobbler profile getks --name=xx # 查看渲染后的 ks(排错神器)
# ---- system(按 MAC 绑定)----
cobbler system add --name=db01 --profile=c7-db --interface=eth0 \
--mac=00:0c:29:aa:bb:cc --ip-address=192.168.100.61 --subnet=255.255.255.0 \
--gateway=192.168.100.1 --hostname=db01 --static=1
cobbler system list / report --name=xx / find --mac=xx / remove --name=xx
cobbler system edit --name=xx --netboot-enabled=0 # 装完关闭网络安装
cobbler system poweron|poweroff|reboot|powerstatus --name=xx
# ---- repo ----
cobbler repo add --name=epel7 --mirror=http://... --arch=x86_64 --breed=yum
cobbler reposync [--only=epel7]
cobbler profile edit --name=c7-min --repos="base7 epel7"
# ---- 其他 ----
cobbler validateks # 校验所有 ks
cobbler get-loaders # 下载引导文件
cobbler buildiso --iso=/root/x.iso --profiles=c7-min [--standalone]
cobbler replicate --master=<ip> --distros="*" --profiles="*"
cobbler aclsetup --adduser=devops / cobbler hardlink
# ---- 客户端 koan ----
koan --server=3.3.3.4 --list=profiles
koan --replace-self --server=3.3.3.4 --profile=new_centos7.3 && reboot
koan --virt --server=3.3.3.4 --profile=c7-vm --virt-name=vm01
cobbler check 常见项修复速查表
| 报的项 | 一句话修复 |
|---|---|
| server 是 localhost | settings 的 server: 改本机真实 IP |
| next_server 是 127.0.0.1 | settings 的 next_server: 改本机真实 IP |
| SELinux is enabled | setenforce 0 + 改 /etc/selinux/config |
| change 'disable' to 'no' in /etc/xinetd.d/tftp | sed -i '/disable/s/yes/no/' + 重启 xinetd |
| boot-loaders missing from loaders | cobbler get-loaders,或装新版 syslinux 手工拷 pxelinux.0/menu.c32 |
| enable and start rsyncd | systemctl enable --now rsyncd |
| comment out 'dists' / 'arches' in debmirror.conf | 注释 @dists="sid"; 和 @arches="i386"; |
| default_password_crypted 仍是 cobbler | openssl passwd -1 -salt 'xx' 'pass' 替换该行 |
| dhcpd.conf is not managed | settings 的 manage_dhcp: 1 |
| fencing tools not found | yum -y install fence-agents |
| cobblerd / httpd not running | systemctl start cobblerd httpd |
修完每项:systemctl restart cobblerd → cobbler check → cobbler sync。
危险操作警示清单
| 操作 | 风险 | 防护 |
|---|---|---|
clearpart --all --initlabel |
无提示清空所有磁盘的全部数据,包括数据盘 | 必须加 --drives=sda,配合 ignoredisk --only-use=sda |
zerombr |
清空 MBR | 同上,限定盘符 |
| 盘符写错(sda / vda / nvme0n1) | 清错盘或分区失败 | %pre 里用 lsblk 动态探测 |
| ks 里写明文密码 | ks 通过 HTTP 公开,任何人 curl 可见 | 用 --iscrypted + openssl passwd -6;限制 ks 目录访问;装完改密 |
default_password_crypted 保持默认 |
装出的每台机器 root 密码都是 cobbler |
部署时必须替换 |
| 在桥接网络/办公网搭 DHCP | 污染生产网,同事机器网关被改,属于事故 | 只在"仅主机/私有/隔离"网络做实验 |
直接改 /etc/dhcp/dhcpd.conf(manage_dhcp=1) |
下次 cobbler sync 后改动全部丢失 |
改 /etc/cobbler/dhcp.template |
ks 里 reboot + 客户端网络优先启动 |
无限重装循环 | pxe_just_once: 1、localboot 设为默认项、或改用 poweroff |
对生产机器执行 koan --replace-self |
重启即被重装,数据全失 | 只在确认要重装的机器上执行 |
htdigest -c |
-c 会清空整个 users.digest 重建 |
修改已有用户不要加 -c |
cobbler import 前不看磁盘空间 |
/var 被打满,服务异常 |
先 df -h /var,每个镜像预留 5~10G |
| ks 文件含中文(含注释) | 无法启动安装 | 全文只用 ASCII |
漏写 %end |
ks 解析失败,停在交互界面 | ksvalidator 校验 |
排错口诀
一看菜单出不出——不出:查网卡启动顺序 → 有无别的 DHCP 抢答 → dhcpd 的 next-server/filename → tftp 能否 get
二看内核加不加——卡住:tftpboot 下文件在不在、路径对不对、*.c32 与 pxelinux.0 是否同版本
三看 ks 读不读——直接进交互界面就是 ks 没读到:curl 那个 URL
四看源通不通——报安装源错误:curl repodata/repomd.xml,404 路径错 / 403 SELinux / 拒绝连接服务没起
五看分区对不对——lsblk 确认盘符 sda vda nvme0n1,clearpart 一定带 --drives
六看装完转不转——无限重装看 netboot 与启动顺序,起不来看 bootloader 与 /boot/efi
状态码记忆:404=路径错,403=权限或 SELinux,Connection refused=服务没起,timeout=防火墙或网络不通
Cobbler 记忆:改配置改模板,改完必 sync;出问题先 check,再看 /var/log/cobbler/tasks/
此处评论已关闭