1. 方案概述
1.1 为什么需要批量网络安装?
传统方式——U盘/CD-ROM 逐台安装 20 台服务器:
每台耗时约 30~60 分钟(含人工插拔介质、选单、等待)
20 台 × 45 分钟 ≈ 15 小时人工工时
易出错(选错分区、漏配网络、忘记配置时区)
批量网络安装(PXE 网络引导):
20 台服务器同时开机,并行安装
40~60 分钟完成全部部署
无需任何物理介质
配置完全一致,零人工误操作
1.2 架构图
┌─────────────────────────────────────────────────────────────┐│ 管理网络 (eth0/管理网段) ││ 192.168.100.0/24 ││ ││ ┌──────────────┐ ┌──────────────┐ ┌──────────────┐ ││ │ DHCP Server │ │ TFTP Server │ │ HTTP Server │ ││ │ (dnsmasq) │ │ (tftp-hpa) │ │ (nginx) │ ││ │ 192.168.100.10│ │ 192.168.100.10│ │ 192.168.100.10│ ││ │ PXE + IP池 │ │ 引导文件+内核 │ │ 安装源+KS │ ││ └──────┬───────┘ └──────┬───────┘ └──────┬───────┘ ││ │ │ │ ││ └────────────────────┼────────────────────┘ ││ │ ││ ┌────────┴────────┐ ││ │ Core Switch │ ││ │ (管理交换机) │ ││ └────────┬────────┘ ││ │ ││ ┌────────────────────┼────────────────────┐ ││ │ │ │ ││ ┌──────┴──────┐ ┌───────┴──────┐ ┌───────┴──────┐ ││ │ Server 01 │ │ Server 02 │ │ Server 20 │ ││ │ (PXE Boot) │ │ (PXE Boot) │ │ (PXE Boot) │ ││ └─────────────┘ └──────────────┘ └──────────────┘ ││ ││ 注意:服务器 BMC/iBMC 带外管理建议使用独立管理口 ││ 部署网络与管理网复用或独立均可,建议单独 VLAN │└─────────────────────────────────────────────────────────────┘
1.3 推荐方案对比
| 方案 | 服务组件 | 优点 | 缺点 |
|---|---|---|---|
| dnsmasq 一体化 | dnsmasq(DHCP+TFTP+ProxyDHCP) | 配置简单,单服务搞定 | 功能有限,大规模可能不够 |
| dnsmasq + tftp-hpa + nginx | 各专一服务 | 灵活、稳定、适合生产 | 组件多,配置稍繁琐 |
| Cobbler | Cobbler 统一管理 | 自动化程度最高 | 学习曲线略高,生态变化快 |
| PXE + iPXE | iPXE 链式加载 | 支持 HTTP 直接下载内核 | 需要额外编译/配置 |
本文采用方案二(dnsmasq + tftp-hpa + nginx),兼顾稳定性与灵活性,推荐生产环境使用。
2. 环境准备与拓扑规划
2.1 硬件规划
| 项目 | 规格 |
|---|---|
| 部署服务器(PXE Server) | 1 台(虚拟机或物理机均可) |
| 目标服务器 | 20 台(同型号最佳) |
| 管理交换机 | 1 台,建议支持 VLAN |
| 磁盘 | 每台目标机建议 ≥240GB SSD + ≥1TB HDD |
| 内存 | 每台目标机建议 ≥32GB |
| CPU | x86_64 架构(ARM64 鲲鹏需额外配置) |
2.2 网络规划模板
| 网段 | 用途 | IP 范围 | 说明 |
|---|---|---|---|
| 192.168.100.0/24 | PXE 部署网 | 192.168.100.10-200 | 部署专用,安装完成后可更改 |
| 192.168.1.0/24 | 业务网 | 视现场分配 | 安装后配置 |
| 10.0.0.0/8 | 存储网 | 视现场分配 | 可选,安装后配置 |
| 角色 | IP | 备注 |
|---|---|---|
| PXE Server | 192.168.100.10/24 | 固定 |
| 网关 | 192.168.100.1 | 交换机接口或转发设备 |
| DNS | 192.168.100.10 或 114.114.114.114 | PXE 部署阶段用部署服务器 |
2.3 PXE 部署服务器推荐配置
| 硬件 | 最低配置 | 推荐配置 |
|---|---|---|
| CPU | 2 核 | 4 核 |
| 内存 | 4 GB | 8 GB |
| 磁盘 | 100 GB | 200 GB(用于存储安装源镜像) |
| 网卡 | 1 GbE | 1 GbE × 2(一管理一部署) |
| OS | CentOS 7+ / openEuler / Ubuntu 20.04+ | openEuler 22.03 LTS SP4 |
2.4 目标服务器 BIOS/UEFI 设置检查清单
⚠️ 在 PXE 部署前,必须逐台进入 BIOS/UEFI 确认以下设置:
| 设置项 | 要求 | 说明 |
|---|---|---|
| 启动模式 | 统一(全部 UEFI 或全部 Legacy) | 混用会导致部分机器无法 PXE 启动 |
| 启动顺序 | PXE / Network Boot 设为第一优先 | 部分服务器需开启 UEFI Network Stack |
| 安全启动 | 关闭 | 否则可能拒绝加载 PXE 引导 |
| 磁盘控制器 | AHCI 或 RAID(统一) | RAID 模式需提前创建好虚拟磁盘 |
| 虚拟化 | VT-x / AMD-V 开启 | 如果后续跑虚拟机 |
| BMC/iBMC | 配置好带外 IP | 用于远程强制重启和串口控制 |
配置技巧: 对于 20 台同型号服务器,可以通过 BMC 批量配置 BIOS(如华为 iBMC、Dell iDRAC 等),无需逐台手动。
3. 部署前硬件与网络检查清单
3.1 硬件检查
# 在每台目标机上,通过 BMC 或本地检查:# 1. CPU 和内存dmidecode -t processor | grep "Version\|Max Speed"dmidecode -t memory | grep "Size\|Speed"# 2. 磁盘状态(前置条件:RAID 已做好)lsblk -o NAME,SIZE,TYPE,MOUNTPOINTfdisk -l | grep "Disk /dev"# 3. 网卡型号与 MAC 地址ip link show# 记录所有网卡的 MAC 地址,后续可用于 DHCP 固定 IP 绑定
3.2 网络连通性检查
# 在 PXE Server 上测试:ping -c 4 192.168.100.1 # 网关ping -c 4 8.8.8.8 # 外网(可选)# 在目标机 BMC 上:# 确认管理口 IP 可达ping 192.168.100.10 # PXE Server# 确认 PXE 服务端口正常(在部署服务器上检查):ss -tulpn | grep -E "67|68|69|80"# DHCP:67, DHCP客户端:68, TFTP:69, HTTP:80
3.3 防火墙与 SELinux 检查
# 关闭防火墙(部署阶段)systemctl stop firewalldsystemctl disable firewalld# 或放行端口firewall-cmd --add-service=dhcp --permanentfirewall-cmd --add-service=tftp --permanentfirewall-cmd --add-service=http --permanentfirewall-cmd --reload# 关闭 SELinux 或设为 permissivesetenforce 0sed -i 's/^SELINUX=.*/SELINUX=permissive/' /etc/selinux/config
4. 基础服务搭建 — DHCP
4.1 安装 dnsmasq
dnsmasq 集成了 DHCP、TFTP、DNS 功能,配置简单。我们使用它来提供 DHCP 服务。
# 安装yum install -y dnsmasq# 验证安装dnsmasq --version
4.2 配置 dnsmasq
编辑 /etc/dnsmasq.conf:
# 基础设置port=0 # 关闭 DNS 功能(本例不需)domain-neededbogus-privstrict-order# 接口绑定 — 指定提供服务的网卡interface=enp0s3bind-interfaces# DHCP 地址池dhcp-range=192.168.100.50,192.168.100.200,255.255.255.0,12h# DHCP 选项 — 告诉客户端如何找到 TFTP 和引导文件dhcp-option=3,192.168.100.1 # 默认网关dhcp-option=6,192.168.100.10 # DNS 服务器# UEFI x86_64 引导文件(BIOS/Legacy 用不同文件)dhcp-boot=grubx64.efi# 可选:BIOS/Legacy PXE 客户端(如需要同时支持 Legacy)# dhcp-match=set:bios,option:client-arch,0# dhcp-boot=tag:bios,undionly.kpxe# TFTP 根目录enable-tftptftp-root=/var/lib/tftpboot# DHCP 静态绑定(按 MAC 分配固定IP,可选)# dhcp-host=00:1a:4a:16:01:01,192.168.100.101,srv-node01# dhcp-host=00:1a:4a:16:01:02,192.168.100.102,srv-node02# dhcp-host=00:1a:4a:16:01:20,192.168.100.120,srv-node20# 日志log-dhcplog-querieslog-facility=/var/log/dnsmasq.log
4.3 启动 DHCP
systemctl enable --now dnsmasqsystemctl status dnsmasq# 检查监听端口ss -tulpn | grep dnsmasq# 应看到 UDP 67 (DHCP) 和 UDP 69 (TFTP)
5. 基础服务搭建 — TFTP
注意:如果使用 dnsmasq 的 TFTP 功能(已在上面的配置中开启
enable-tftp),则不需要再单独安装 tftp-hpa。这里仅为方法二(分离部署)提供参考。
5.1 安装 tftp-hpa
yum install -y tftp-server tftp5.2 配置 tftp
# 创建 TFTP 根目录mkdir -p /var/lib/tftpbootchmod -R 755 /var/lib/tftpboot# 编辑 /etc/xinetd.d/tftpcat > /etc/xinetd.d/tftp << 'EOF'service tftp{socket_type = dgramprotocol = udpwait = yesuser = rootserver = /usr/sbin/in.tftpdserver_args = -s /var/lib/tftpboot -cdisable = noper_source = 11cps = 100 2flags = IPv4}EOF
5.3 启动 tftp
systemctl enable --now xinetdsystemctl status xinetd# 验证ss -tulpn | grep :69
⚠️ 如果使用 dnsmasq 的内置 TFTP,不要再启用 xinetd/tftp 服务,避免端口冲突。
6. 基础服务搭建 — HTTP
HTTP 用于向目标服务器传输安装源和 Kickstart 文件。速度远快于 TFTP,是部署的关键优化。
6.1 安装 Nginx
yum install -y nginxsystemctl enable --now nginx
6.2 配置 Nginx 站点
编辑 /etc/nginx/conf.d/pxe-install.conf:
server {listen 80 default_server;server_name _;# 安装源文件(ISO 镜像解压内容)root /var/www/html;# 自动索引,方便测试访问autoindex on;autoindex_exact_size off;autoindex_localtime on;# 大文件传输优化sendfile on;tcp_nopush on;keepalive_timeout 65;# 日志access_log /var/log/nginx/pxe-access.log;error_log /var/log/nginx/pxe-error.log;}
6.3 测试 HTTP 服务
# 创建一个测试文件echo "PXE Test OK" > /var/www/html/test.txt# 验证curl http://127.0.0.1/test.txt# 应输出: PXE Test OK# 从另一台机器验证(可选)curl http://192.168.100.10/test.txt
7. 准备 PXE 引导文件
7.1 获取引导文件
方式一:从 openEuler ISO 中解压
# 挂载 ISOmount -o loop /opt/iso/openEuler-22.03-LTS-SP4-x86_64-dvd.iso /mnt# 复制 UEFI 引导文件cp /mnt/EFI/BOOT/grubx64.efi /var/lib/tftpboot/cp /mnt/images/pxeboot/vmlinuz /var/lib/tftpboot/cp /mnt/images/pxeboot/initrd.img /var/lib/tftpboot/# 复制 grub 配置文件目录cp -r /mnt/EFI/BOOT/grub /var/lib/tftpboot/# 卸载 ISOumount /mnt
方式二:从麒麟 ISO 中解压
# 麒麟 V10 SP3 示例mount -o loop /opt/iso/Kylin-Server-V10-SP3-x86_64-dvd.iso /mntcp /mnt/EFI/BOOT/grubaa64.efi /var/lib/tftpboot/ # ARM64# 或cp /mnt/EFI/BOOT/grubx64.efi /var/lib/tftpboot/ # x86_64cp /mnt/images/pxeboot/vmlinuz /var/lib/tftpboot/cp /mnt/images/pxeboot/initrd.img /var/lib/tftpboot/umount /mnt
7.2 获取 iPXE 引导文件(推荐 — 加速方案)
使用标准 grub 引导时,内核和 initrd 通过 TFTP 传输(约 40MB,UDP 慢速)。改用 iPXE 链式加载内核可通过 HTTP 传输,速度提升 10~20 倍。
# 下载编译好的 ipxe.eficurl -o /var/lib/tftpboot/ipxe.efi \https://boot.ipxe.org/ipxe.efi# 或者下载脚本引导版本curl -o /var/lib/tftpboot/ipxe-script.efi \https://boot.ipxe.org/ipxe-script.efi
git clone https://github.com/ipxe/ipxe.gitcd ipxe/srcmake bin-x86_64-efi/ipxe.efi EMBED=embed.ipxecp bin-x86_64-efi/ipxe.efi /var/lib/tftpboot/
embed.ipxe 文件内容示例:#!ipxedhcpchain http://192.168.100.10/boot.ipxe
7.3 目录结构检查
安装后的 /var/lib/tftpboot/ 应包含以下文件:
/var/lib/tftpboot/├── grubx64.efi # UEFI 引导管理器├── vmlinuz # 内核├── initrd.img # 初始 ramdisk├── ipxe.efi # (可选) iPXE 引导├── grub/│ └── grub.cfg # grub 菜单配置└── boot.ipxe # (可选) iPXE 脚本
8. 准备操作系统安装源
8.1 解压 ISO 到 HTTP 目录
mkdir -p /var/www/html/{openEuler,kylin}# openEulermount -o loop /opt/iso/openEuler-22.03-LTS-SP4-x86_64-dvd.iso /mntcp -a /mnt/* /var/www/html/openEuler/umount /mnt# 麒麟 V10mount -o loop /opt/iso/Kylin-Server-V10-SP3-x86_64-dvd.iso /mntcp -a /mnt/* /var/www/html/kylin/umount /mnt
8.2 验证 HTTP 访问安装源
# 列表检查curl http://192.168.100.10/openEuler/curl http://192.168.100.10/kylin/# 验证关键文件存在curl -I http://192.168.100.10/openEuler/images/pxeboot/vmlinuzcurl -I http://192.168.100.10/kylin/images/pxeboot/vmlinuz
8.3 设置防火墙(如未关闭)
firewall-cmd --add-service=http --permanentfirewall-cmd --reload
9. 编写 Kickstart 无人值守应答文件
Kickstart 是整个自动化部署的核心。它定义了安装过程中所有问题的答案。
9.1 openEuler Kickstart 示例
保存为 /var/www/html/ks/openEuler-ks.cfg:
mkdir -p /var/www/html/ks# version=RHEL8# openEuler 22.03 LTS SP4 无人值守安装应答文件# ============================================================# 1. 安装源与安装类型# ============================================================# 安装源 — HTTP 协议,速度远快于 NFS/FTPurl --url="http://192.168.100.10/openEuler/"# 安装类型:text 文本模式(全自动,无交互)text# 安装日志logging --level=info --host=192.168.100.10# ============================================================# 2. 语言与时区# ============================================================lang zh_CN.UTF-8keyboard 'us'timezone Asia/Shanghai --isUtc --nontp# ============================================================# 3. Root 密码与用户# ============================================================# root 密码(使用 openssl passwd -6 生成更安全的 hash)rootpw --iscrypted $6$rounds=4096$k7d8f3a9$AbCdEfGhIjKlMnOpQrStUvWxYz1234567890AbCdEfGhIjKlMn# 创建普通运维用户user --name=ops --iscrypted --password=$6$rounds=4096$k7d8f3a9$AbCdEfGhIjKlMnOpQrStUvWxYz1234567890AbCdEfGhIjKlMn# 加入 wheel 组(sudo 权限)group --name=wheeluser --name=ops --groups=wheel# 写入 sudo 免密码配置(%post 中处理)# %post 中执行: echo "ops ALL=(ALL) NOPASSWD:ALL" >> /etc/sudoers.d/ops# ============================================================# 4. 分区方案# ============================================================# 清除所有分区clearpart --all --initlabel# 自动分区(适用于不做精细分区需求的场景)# autopart --type=lvm# 手动精细分区(推荐生产环境)part /boot/efi --fstype="vfat" --size=1024 --ondisk=sdapart /boot --fstype="xfs" --size=2048 --ondisk=sdapart pv.00 --size=1 --grow --ondisk=sdavolgroup vg00 pv.00logvol / --fstype="xfs" --name=root --vgname=vg00 --size=30720logvol /var --fstype="xfs" --name=var --vgname=vg00 --size=10240logvol /var/log --fstype="xfs" --name=varlog --vgname=vg00 --size=10240logvol swap --fstype="swap" --name=swap --vgname=vg00 --size=16384# ============================================================# 5. 网络配置# ============================================================# 部署阶段使用 DHCP,安装完成后再配置固定 IP(通过 %post 处理)# 或者直接配置固定 IP(如果 DHCP 绑定固定地址)# network --bootproto=static --ip=192.168.100.101 --netmask=255.255.255.0 \# --gateway=192.168.100.1 --nameserver=192.168.100.10 \# --hostname=node01 --device=eth0 --activate# DHCP 方式(安装完成后在 %post 中重新配置固定 IP)network --bootproto=dhcp --hostname=node-template --device=link --activatenetwork --bootproto=dhcp --hostname=node-template --device=link --activate --noipv6# ============================================================# 6. 软件包选择# ============================================================%packages@^minimal-environment@standard@server@developmentvimwgetcurlnet-toolsbind-utilstcpdumplsofstracesysstatiotopiftoplvm2nfs-utilschronybash-completionpolicycoreutils-python-utilsopenssh-clientsopenssh-serverrsynctelnet-alsa-firmware-alsa-sof-firmware-ivtv-firmware%end# ============================================================# 7. 安装后脚本(关键!自动化配置核心)# ============================================================%post --interpreter=/bin/bash --log=/root/post-install.log# 7.1 生成 SSH 主机密钥(确保首次启动时已存在)rm -f /etc/ssh/ssh_host_*ssh-keygen -t rsa -f /etc/ssh/ssh_host_rsa_key -N '' -qssh-keygen -t ecdsa -f /etc/ssh/ssh_host_ecdsa_key -N '' -qssh-keygen -t ed25519 -f /etc/ssh/ssh_host_ed25519_key -N '' -q# 7.2 配置 SSH 安全加固cat >> /etc/ssh/sshd_config.d/99-hardening.conf << SSHEOFPermitRootLogin yesPasswordAuthentication yesPubkeyAuthentication yesAuthorizedKeysFile .ssh/authorized_keysMaxAuthTries 3ClientAliveInterval 300ClientAliveCountMax 2SSHEOF# 7.3 注入运维公钥(免密码登录)mkdir -p /root/.ssh /home/ops/.sshchmod 700 /root/.ssh /home/ops/.sshcat >> /root/.ssh/authorized_keys << KEYEOFssh-rsa AAAAB3NzaC1yc2EAAAADAQABAAABAQ... 你的运维公钥ssh-ed25519 AAAAC3NzaC1lZDI1NTE5AAAAI... 备用公钥KEYEOFcp /root/.ssh/authorized_keys /home/ops/.ssh/chmod 600 /root/.ssh/authorized_keys /home/ops/.ssh/authorized_keyschown -R ops:ops /home/ops/.ssh# 7.4 配置 sudo 免密码echo "ops ALL=(ALL) NOPASSWD:ALL" > /etc/sudoers.d/opschmod 440 /etc/sudoers.d/ops# 7.5 配置 NTP 时间同步cat > /etc/chrony.conf << CHRONYEOFserver ntp.aliyun.com iburstserver ntp.tencent.com iburstserver 192.168.100.1 iburstpool pool.ntp.org iburstdriftfile /var/lib/chrony/driftmakestep 1.0 3rtcsynclogdir /var/log/chronyCHRONYEOF# 7.6 配置内核参数优化cat > /etc/sysctl.d/99-performance.conf << SYSCTLEOF# TCP 优化net.ipv4.tcp_tw_reuse = 1net.ipv4.tcp_fin_timeout = 30net.ipv4.tcp_keepalive_time = 1200net.core.somaxconn = 65535net.ipv4.tcp_max_syn_backlog = 65535net.ipv4.ip_local_port_range = 1024 65535# 内存管理vm.swappiness = 10vm.dirty_ratio = 40vm.dirty_background_ratio = 10# 文件描述符限制fs.file-max = 6553500SYSCTLEOF# 7.7 配置 limitscat > /etc/security/limits.d/99-app.conf << LIMSEOF* soft nofile 6553500* hard nofile 6553500* soft nproc 6553500* hard nproc 6553500LIMSEOF# 7.8 禁用不需要的服务systemctl disable postfix 2>/dev/null || truesystemctl disable avahi-daemon 2>/dev/null || truesystemctl disable firewalld 2>/dev/null || truesystemctl disable kdump 2>/dev/null || true# 7.9 安装 ansible(方便后续批量管理)dnf install -y ansible-core 2>/dev/null || yum install -y ansible 2>/dev/null || true# 7.10 配置主机名(使用 IP 最后一段作为标识)IP_ADDR=$(ip route get 1 | awk '{print $7; exit}')HOST_SUFFIX=$(echo $IP_ADDR | awk -F. '{print $4}')hostnamectl set-hostname "node-${HOST_SUFFIX}.ops.internal"# 7.11 写入 /etc/hostscat >> /etc/hosts << HOSTSEOF# PXE 部署服务器192.168.100.10 pxeserver.ops.internal pxeserver# 本机127.0.1.1 node-${HOST_SUFFIX}.ops.internal node-${HOST_SUFFIX}HOSTSEOF# 7.12 完成标记echo "Post-installation completed at $(date)" >> /root/post-install.log%end# ============================================================# 8. 重启与 SELinux# ============================================================# 安装完成后自动重启reboot --eject# SELinux 设为 permissive(生产环境建议 enforcing,首次部署可宽松)selinux --permissive# ============================================================# 9. 固件包# ============================================================%addon com_redhat_kdump --disable --reserve-mb=256%end# 跳过非必要交互firstboot --disableskipx
9.2 麒麟 V10 SP3 Kickstart 示例
保存为 /var/www/html/ks/kylin-ks.cfg:
# version=RHEL8# Kylin Server V10 SP3 无人值守安装应答文件# 安装源url --url="http://192.168.100.10/kylin/"# 文本模式text# 语言与时区lang zh_CN.UTF-8keyboard ustimezone Asia/Shanghai --isUtc# Root 密码(生产环境务必更换)rootpw --iscrypted $6$rounds=4096$k7d8f3a9$AbCdEfGhIjKlMnOpQrStUvWxYz1234567890AbCdEfGhIjKlMn# 用户user --name=ops --groups=wheel --iscrypted --password=$6$rounds=4096$k7d8f3a9$AbCdEfGhIjKlMnOpQrStUvWxYz1234567890AbCdEfGhIjKlMn# 分区clearpart --all --initlabelautopart --type=lvm# 网络network --bootproto=dhcp --hostname=kylin-template --device=link --activate# 软件包%packages@^kylin-server@server@developmentvimwgetcurlnet-toolsbind-utilstcpdumplsofstracesysstatiotopnfs-utilschronybash-completionopenssh-clientsopenssh-serverrsync%end# 安装后配置%post --interpreter=/bin/bash --log=/root/post-install.log# SSH 密钥生成rm -f /etc/ssh/ssh_host_*ssh-keygen -t rsa -f /etc/ssh/ssh_host_rsa_key -N '' -qssh-keygen -t ecdsa -f /etc/ssh/ssh_host_ecdsa_key -N '' -qssh-keygen -t ed25519 -f /etc/ssh/ssh_host_ed25519_key -N '' -q# SSH 配置sed -i 's/^#PermitRootLogin.*/PermitRootLogin yes/' /etc/ssh/sshd_configsed -i 's/^PasswordAuthentication.*/PasswordAuthentication yes/' /etc/ssh/sshd_config# 注入公钥mkdir -p /root/.sshchmod 700 /root/.sshecho "ssh-rsa AAAAB3NzaC1yc2EAAAADAQABAAABAQ... 你的运维公钥" >> /root/.ssh/authorized_keyschmod 600 /root/.ssh/authorized_keys# sudo 免密码echo "ops ALL=(ALL) NOPASSWD:ALL" > /etc/sudoers.d/opschmod 440 /etc/sudoers.d/ops# NTPcat > /etc/chrony.conf << EOFserver ntp.aliyun.com iburstserver ntp.tencent.com iburstdriftfile /var/lib/chrony/driftmakestep 1.0 3rtcsyncEOF# 性能优化cat > /etc/sysctl.d/99-performance.conf << EOFnet.ipv4.tcp_tw_reuse = 1net.ipv4.tcp_fin_timeout = 30net.core.somaxconn = 65535vm.swappiness = 10fs.file-max = 6553500EOF# 禁用防火墙systemctl disable firewalld 2>/dev/null || true# 主机名标识IP_ADDR=$(ip route get 1 | awk '{print $7; exit}')HOST_SUFFIX=$(echo $IP_ADDR | awk -F. '{print $4}')hostnamectl set-hostname "kylin-node-${HOST_SUFFIX}.ops.internal"echo "Post-installation completed at $(date)" >> /root/post-install.log%end# 重启reboot --eject# SELinuxselinux --permissivefirstboot --disableskipx
9.3 生成密码哈希
# 生成安全的密码哈希(加密强度 rounds = 4096)openssl passwd -6 -rounds 4096# 输入密码后复制输出到 ks 文件中# 或使用 python3python3 -c "import cryptprint(crypt.crypt('你的密码', crypt.mksalt(crypt.METHOD_SHA512)))"
10. Grub 引导菜单配置
10.1 UEFI Grub 菜单
编辑 /var/lib/tftpboot/grub/grub.cfg:
set default="0"set timeout=60if [ ${grub_platform} = "efi" ]; then# 设置字体和显示set gfxpayload=keepterminal_output gfxtermfi# ============================================================# 菜单项 1:安装 openEuler 22.03 LTS SP4# ============================================================menuentry "Install openEuler 22.03 LTS SP4 (x86_64) - Automated" {set root=(http,192.168.100.10)linuxefi /openEuler/images/pxeboot/vmlinuz \inst.repo=http://192.168.100.10/openEuler/ \inst.ks=http://192.168.100.10/ks/openEuler-ks.cfg \inst.stage2=http://192.168.100.10/openEuler/ \console=tty0 console=ttyS0,115200n8 \rd.debug=0 \quietinitrdefi /openEuler/images/pxeboot/initrd.img}# ============================================================# 菜单项 2:安装麒麟 V10 SP3# ============================================================menuentry "Install Kylin Server V10 SP3 (x86_64) - Automated" {set root=(http,192.168.100.10)linuxefi /kylin/images/pxeboot/vmlinuz \inst.repo=http://192.168.100.10/kylin/ \inst.ks=http://192.168.100.10/ks/kylin-ks.cfg \console=tty0 console=ttyS0,115200n8 \quietinitrdefi /kylin/images/pxeboot/initrd.img}# ============================================================# 菜单项 3:安装 openEuler(带调试输出)# ============================================================menuentry "Install openEuler 22.03 LTS SP4 (Debug mode)" {set root=(http,192.168.100.10)linuxefi /openEuler/images/pxeboot/vmlinuz \inst.repo=http://192.168.100.10/openEuler/ \inst.ks=http://192.168.100.10/ks/openEuler-ks.cfg \console=tty0 console=ttyS0,115200n8 \inst.debug=1 \rd.shell=1initrdefi /openEuler/images/pxeboot/initrd.img}# ============================================================# 菜单项 4:从本地磁盘启动# ============================================================menuentry "Boot from local disk" {chainloader (hd0,1)/efi/BOOT/grubx64.efi || chainloader (hd0,2)/efi/BOOT/grubx64.efi || exit}# ============================================================# 菜单项 5:救援模式(openEuler)# ============================================================menuentry "Rescue mode - openEuler" {set root=(http,192.168.100.10)linuxefi /openEuler/images/pxeboot/vmlinuz \inst.repo=http://192.168.100.10/openEuler/ \inst.rescue \console=tty0 console=ttyS0,115200n8initrdefi /openEuler/images/pxeboot/initrd.img}
10.2 iPXE 引导脚本(可选)
如果使用 iPXE 链式加载,编辑 /var/lib/tftpboot/boot.ipxe:
#!ipxeecho "============================================"echo " iPXE Network Install Menu"echo "============================================"echo " Server IP: ${net0/ip}"echo " MAC: ${net0/mac}"echo "============================================"menu "Select OS to install"item --key o openEuler Install openEuler 22.03 LTS SP4item --key k kylin Install Kylin Server V10 SP3item --key d debug openEuler Debug Modeitem --key l local Boot from Local Diskitem --key s shell iPXE Shellchoose --timeout 30000 selected && goto ${selected}:openEulerkernel http://192.168.100.10/openEuler/images/pxeboot/vmlinuz \inst.repo=http://192.168.100.10/openEuler/ \inst.ks=http://192.168.100.10/ks/openEuler-ks.cfg \console=tty0 console=ttyS0,115200n8 quietinitrd http://192.168.100.10/openEuler/images/pxeboot/initrd.imgbootgoto start:kylinkernel http://192.168.100.10/kylin/images/pxeboot/vmlinuz \inst.repo=http://192.168.100.10/kylin/ \inst.ks=http://192.168.100.10/ks/kylin-ks.cfg \console=tty0 console=ttyS0,115200n8 quietinitrd http://192.168.100.10/kylin/images/pxeboot/initrd.imgbootgoto start:debugkernel http://192.168.100.10/openEuler/images/pxeboot/vmlinuz \inst.repo=http://192.168.100.10/openEuler/ \inst.ks=http://192.168.100.10/ks/openEuler-ks.cfg \console=tty0 console=ttyS0,115200n8 \inst.debug=1 rd.shell=1initrd http://192.168.100.10/openEuler/images/pxeboot/initrd.imgbootgoto start:localexitgoto start:shellshellgoto start
10.3 Legacy BIOS 配置(兼容参考)
如果部分服务器是 Legacy BIOS 不支持 UEFI:
# 下载 syslinux 提供的 PXELINUX 引导yum install -y syslinux# 复制引导文件cp /usr/share/syslinux/pxelinux.0 /var/lib/tftpboot/cp /usr/share/syslinux/ldlinux.c32 /var/lib/tftpboot/cp /usr/share/syslinux/vesamenu.c32 /var/lib/tftpboot/cp /usr/share/syslinux/libcom32.c32 /var/lib/tftpboot/cp /usr/share/syslinux/libutil.c32 /var/lib/tftpboot/# 创建 pxelinux.cfg 配置目录mkdir -p /var/lib/tftpboot/pxelinux.cfg# 默认配置cat > /var/lib/tftpboot/pxelinux.cfg/default << 'PXEMENU'DEFAULT vesamenu.c32PROMPT 0TIMEOUT 300ONTIMEOUT 1MENU TITLE ⚡ 批量网络安装启动菜单MENU BACKGROUNDLABEL 1MENU LABEL ^1. Install openEuler 22.03 LTS SP4KERNEL openEuler/images/pxeboot/vmlinuzAPPEND initrd=openEuler/images/pxeboot/initrd.img inst.repo=http://192.168.100.10/openEuler/ inst.ks=http://192.168.100.10/ks/openEuler-ks.cfg console=tty0 console=ttyS0,115200n8 quietLABEL 2MENU LABEL ^2. Install Kylin V10 SP3KERNEL kylin/images/pxeboot/vmlinuzAPPEND initrd=kylin/images/pxeboot/initrd.img inst.repo=http://192.168.100.10/kylin/ inst.ks=http://192.168.100.10/ks/kylin-ks.cfg console=tty0 console=ttyS0,115200n8 quietLABEL localMENU LABEL ^L. Boot from local diskLOCALBOOT 0PXEMENU
11. 批量部署执行流程
11.1 部署前最终检查清单
#!/bin/bash# preflight-check.sh — 部署前完整性检查echo "=== PXE 部署前检查 ==="# 1. 检查 DHCP 服务echo -n "DHCP: "systemctl is-active dnsmasq 2>/dev/null || systemctl is-active dhcpd 2>/dev/null# 2. 检查 TFTPecho -n "TFTP: "test -f /var/lib/tftpboot/grubx64.efi && echo "OK (grubx64.efi found)" || echo "MISSING grubx64.efi"# 3. 检查 HTTPecho -n "HTTP: "curl -s -o /dev/null -w "%{http_code}" http://localhost/openEuler/ && echo " (openEuler repo OK)"# 4. 检查 Kickstartecho -n "KS: "test -f /var/www/html/ks/openEuler-ks.cfg && echo "OK" || echo "MISSING"# 5. 检查 Grub 配置echo -n "Grub: "test -f /var/lib/tftpboot/grub/grub.cfg && echo "OK" || echo "MISSING"# 6. 检查防火墙echo -n "Firewall: "systemctl is-active firewalld 2>/dev/null || echo "disabled"# 7. 检查 SELinuxecho -n "SELinux: "getenforce# 8. 检查目标机连通性(示例前 5 台 BMC)for i in 101 102 103 104 105; doping -c 1 -W 2 192.168.100.${i} >/dev/null 2>&1 \&& echo "Server ${i}: REACHABLE" \|| echo "Server ${i}: UNREACHABLE (check BMC)"doneecho "=== 检查完成 ==="
11.2 部署步骤
阶段一:服务端确认
# 1. 确保所有服务正常运行systemctl status dnsmasqsystemctl status nginxss -tulpn | grep -E ":67|:69|:80"# 2. 检查关键文件完整性ls -lh /var/lib/tftpboot/grubx64.efils -lh /var/www/html/openEuler/images/pxeboot/vmlinuzls -lh /var/www/html/ks/openEuler-ks.cfg# 3. 查看日志(新开窗口实时监控)tail -f /var/log/dnsmasq.log
阶段二:逐台/批量启动 PXE 安装
方式一:通过 BMC 批量远程开机(推荐)
#!/bin/bash# batch-pxe-install.sh — 通过 BMC 批量重启并强制 PXE 启动# 服务器 IP 列表(BMC/iBMC/iDRAC 管理口地址)BMC_HOSTS=("192.168.100.101""192.168.100.102""192.168.100.103""192.168.100.104""192.168.100.105""192.168.100.106""192.168.100.107""192.168.100.108""192.168.100.109""192.168.100.110""192.168.100.111""192.168.100.112""192.168.100.113""192.168.100.114""192.168.100.115""192.168.100.116""192.168.100.117""192.168.100.118""192.168.100.119""192.168.100.120")BMC_USER="admin"BMC_PASS="your_bmc_password"INSTALL_OS="openEuler" # 或 "kylin"echo "===== 批量 PXE 安装启动 ====="echo "目标系统: ${INSTALL_OS}"echo "服务器数量: ${#BMC_HOSTS[@]}"echo "启动时间: $(date '+%Y-%m-%d %H:%M:%S')"echo "================================"for BMC_IP in "${BMC_HOSTS[@]}"; doecho "[$(date '+%H:%M:%S')] 正在处理 ${BMC_IP}..."# 获取服务器序列号(可选,用于日志)# SN=$(ipmitool -I lanplus -H ${BMC_IP} -U ${BMC_USER} -P ${BMC_PASS} fru print 2>/dev/null | grep "Product Serial" | awk -F: '{print $2}' | tr -d ' ')# echo " 序列号: ${SN}"# 设置下一次启动为 PXEipmitool -I lanplus -H ${BMC_IP} -U ${BMC_USER} -P ${BMC_PASS} chassis bootdev pxe options=persistent# 强制重启ipmitool -I lanplus -H ${BMC_IP} -U ${BMC_USER} -P ${BMC_PASS} power resetif [ $? -eq 0 ]; thenecho " ✅ PXE 启动设置成功,已发送重启命令"elseecho " ❌ 失败!请检查 BMC 连接"fi# 每台间隔 5 秒,避免 DHCP 瞬间洪泛sleep 5doneecho ""echo "===== 所有服务器已发送 PXE 重启命令 ====="echo "预计 40-60 分钟后完成部署"echo "监控命令: tail -f /var/log/dnsmasq.log"
方式二:人工逐台操作(适用于无 BMC 环境)
开机按 F12 / F2 / Del 进入 BIOS
选择 PXE / Network Boot
等待引导菜单出现
默认 60 秒倒计时后自动安装(或手动选择目标系统)
每台间隔 1-2 分钟,避免 DHCP 拥堵
阶段三:监控安装过程
# 在 PXE Server 上监控 DHCP 请求tail -f /var/log/dnsmasq.log | grep -E "DHCPDISCOVER|DHCPACK"# 查看 HTTP 请求tail -f /var/log/nginx/pxe-access.log# 批量 Ping 监控安装进度for i in 50 51 52 53 54; doping -c 1 -W 1 192.168.100.${i} >/dev/null 2>&1 \&& echo "192.168.100.${i} online" \|| echo "192.168.100.${i} installing..."done
阶段四:安装完成验证
#!/bin/bash# post-deploy-check.sh — 部署后自动化验证echo "===== 部署后验证 ====="echo "检查时间:$(date)"# 待检测的服务器列表(部署后分配的 IP 范围)NODE_IPS=("192.168.100.50""192.168.100.51"# ... 全部 20 台)TOTAL=0SUCCESS=0FAILED=0for IP in "${NODE_IPS[@]}"; doTOTAL=$((TOTAL + 1))# 1. SSH 可达性ssh -o StrictHostKeyChecking=no -o ConnectTimeout=5 -o BatchMode=yes root@${IP} "hostname" 2>/dev/nullif [ $? -eq 0 ]; thenecho "[${IP}] ✅ SSH OK"elseecho "[${IP}] ❌ SSH FAIL (可能正在重启或安装中)"FAILED=$((FAILED + 1))continuefi# 2. 收集系统信息INFO=$(ssh -o StrictHostKeyChecking=no root@${IP} "echo \"OS: \$(cat /etc/os-release | grep PRETTY_NAME | cut -d'\"' -f2)\"echo \"Hostname: \$(hostname)\"echo \"Kernel: \$(uname -r)\"echo \"CPU: \$(nproc) cores\"echo \"Memory: \$(free -h | grep Mem | awk '{print \$2}')\"echo \"Disk: \$(df -h / | tail -1 | awk '{print \$2}')\"echo \"IP: \$(ip -4 addr show | grep inet | grep -v 127.0.0.1 | awk '{print \$2}' | tr '\n' ' ')\"echo \"Uptime: \$(uptime -p)\"" 2>/dev/null)if [ $? -eq 0 ]; thenecho "[${IP}] ✅ 信息采集成功:"echo "${INFO}" | sed 's/^/ /'SUCCESS=$((SUCCESS + 1))elseecho "[${IP}] ⚠️ SSH 连通但信息采集失败"FAILED=$((FAILED + 1))fidoneecho ""echo "===== 验证汇总 ====="echo "总计: ${TOTAL} | 成功: ${SUCCESS} | 失败: ${FAILED}"echo "成功率: $((SUCCESS * 100 / TOTAL))%"
11.3 部署时序参考
| 阶段 | 时间 | 说明 |
|---|---|---|
| DHCP 获取 IP | 5-10 秒 | PXE 启动后自动获取 |
| 下载引导文件 | 10-30 秒 | 通过 TFTP 下载 grubx64.efi |
| 显示引导菜单 | 60 秒 | 默认倒计时后自动安装 |
| 下载内核 + initrd | 10-20 秒 | HTTP 传输(约 80MB) |
| 安装阶段 | 20-30 分钟 | 取决于磁盘 I/O 和 HTTP 带宽 |
| Post-install 脚本 | 1-3 分钟 | 配置 SSH、公钥、优化等 |
| 重启 | 30-60 秒 | 自动重启进入新系统 |
| 总计 | 25-35 分钟/台 | 20 台并行 ≈ 35-60 分钟 |
12. 部署后自动初始化脚本
12.1 ansible 批量初始化
部署完成后,可以用 ansible 执行进一步的标准化配置。
创建 /root/ansible/init-playbook.yml:
---- name: 批量初始化新部署的服务器hosts: new_deploygather_facts: yesvars:timezone: "Asia/Shanghai"admin_email: "admin@example.com"ntp_servers:- ntp.aliyun.com- ntp.tencent.comdns_servers:- 223.5.5.5- 114.114.114.114tasks:- name: 确保所有包最新dnf:name: "*"state: latesttags: update- name: 安装常用工具dnf:name:- git- jq- tmux- htop- python3-pip- podman- conntrack-toolsstate: present- name: 配置主机名解析lineinfile:path: /etc/hostsline: "{{ item }}"loop:- "192.168.100.10 pxeserver"- "192.168.100.50 node01"- "192.168.100.51 node02"- "# 后续节点请补充"- name: 配置时区timezone:name: "{{ timezone }}"- name: 配置 NTPtemplate:src: chrony.conf.j2dest: /etc/chrony.confnotify: restart chronyd- name: 配置 DNS 解析lineinfile:path: /etc/resolv.confline: "nameserver {{ item }}"create: yesloop: "{{ dns_servers }}"- name: 关闭不必要的服务systemd:name: "{{ item }}"state: stoppedenabled: noloop:- postfix- avahi-daemon- bluetoothignore_errors: yes- name: 配置日志轮转template:src: logrotate.conf.j2dest: /etc/logrotate.conf- name: 创建监控用户user:name: monitorgroups: wheelshell: /bin/bashcreate_home: yes- name: 部署监控脚本copy:src: scripts/healthcheck.shdest: /usr/local/bin/healthcheck.shmode: '0755'handlers:- name: restart chronydsystemd:name: chronydstate: restarted
12.2 主机清单
创建 /root/ansible/inventory.ini:
[new_deploy]192.168.100.50 hostname=node01192.168.100.51 hostname=node02192.168.100.52 hostname=node03192.168.100.53 hostname=node04192.168.100.54 hostname=node05192.168.100.55 hostname=node06192.168.100.56 hostname=node07192.168.100.57 hostname=node08192.168.100.58 hostname=node09192.168.100.59 hostname=node10192.168.100.60 hostname=node11192.168.100.61 hostname=node12192.168.100.62 hostname=node13192.168.100.63 hostname=node14192.168.100.64 hostname=node15192.168.100.65 hostname=node16192.168.100.66 hostname=node17192.168.100.67 hostname=node18192.168.100.68 hostname=node19192.168.100.69 hostname=node20[new_deploy:vars]ansible_user=rootansible_ssh_private_key_file=/root/.ssh/id_rsaansible_ssh_common_args='-o StrictHostKeyChecking=accept-new'
12.3 执行 ansible 初始化
cd /root/ansibleansible-playbook -i inventory.ini init-playbook.yml
13. 常见故障排查
13.1 DHCP 阶段
| 现象 | 原因 | 解决方法 |
|---|---|---|
| 目标机长时间停留在 "DHCP..." | DHCP 服务未运行 | systemctl status dnsmasq,检查端口 67/68 |
| 目标机获取到错误的 IP | 网络中存在其他 DHCP 服务器 | 关闭其他 DHCP,或在 dnsmasq 配置中 dhcp-ignore |
| 部分机器获取 IP 慢 | DHCP 池太小或者冲突 | 确保地址池足够大(20 台建议至少 50 个地址) |
| DHCP 日志显示 "no address available" | 地址池耗尽 | 扩展 dhcp-range |
| 日志中 "DHCPDISCOVER" 很多但无 "DHCPACK" | 接口绑定错误 | 检查 interface= 设置是否对应正确的网卡 |
调试命令:
# 在目标机上 dhclient 测试dhclient -v eth0# 在 server 端监控 DHCPtcpdump -i any port 67 or port 68 -n -e -v# 测试 DHCP 响应dhcping -s 192.168.100.10 -c 00:1a:4a:16:01:01
13.2 TFTP 阶段
| 现象 | 原因 | 解决方法 |
|---|---|---|
| PXE 挂载 TFTP 超时 | TFTP 路径错误或文件权限 | chmod 755 /var/lib/tftpboot,检查 SELinux |
| "File not found" | 文件名大小写不匹配 | UEFI 文件名为 grubx64.efi,不是 GRUBX64.EFI |
| TFTP 传输非常慢 | TFTP 块大小默认 512 字节 | dnsmasq 中设置 tftp-blksize=1468 |
| UEFI 引导报 "invalid file" | 架构不匹配 | 检查是 x86_64 还是 aarch64,使用对应引导文件 |
| 引导到 grub 后找不到配置文件 | grub.cfg 路径错误 | 确保 /var/lib/tftpboot/grub/grub.cfg 存在 |
# 模拟 TFTP 下载测试tftp 192.168.100.10tftp> get grubx64.efitftp> quit# server 端抓包tcpdump -i any port 69 -n -e -X
13.3 HTTP / 安装源阶段
| 现象 | 原因 | 解决方法 |
|---|---|---|
| "Failed to fetch URL" | HTTP 路径错误 | 检查 inst.repo= 路径是否对应 HTTP 目录结构 |
| 下载速度极慢 | 带宽瓶颈或 Nginx 未优化 | 确认 sendfile on,使用千兆以上网络 |
| 安装到一半卡住 | HTTP 连接断开 | 检查 Nginx 日志,增大 keepalive_timeout |
| kernel panic / init: not found | 内核和 initrd 版本不匹配 | 确保来自同一 ISO |
| 找不到安装源 repo data | 未正确解压 ISO | ls /var/www/html/openEuler/repodata/ 确认存在 |
# 测试 HTTP 访问curl -I http://192.168.100.10/openEuler/images/pxeboot/vmlinuz# 验证 repo 完整性curl -s http://192.168.100.10/openEuler/repodata/repomd.xml | head -20# 查看 Nginx 访问日志tail -f /var/log/nginx/pxe-access.log
13.4 Kickstart 阶段
| 现象 | 原因 | 解决方法 |
|---|---|---|
| 安装卡在交互界面等待输入 | KS 文件未找到或解析失败 | 检查 inst.ks= URL 是否正确,浏览器访问测试 |
| 分区失败 | 磁盘设备名不一致 | 使用 --ondisk=sda 而非 --ondisk=/dev/sda |
| RAID 卡不可识别 | 缺少驱动 | 安装前确认 kernel 支持该 RAID 卡 |
| Post 脚本报错 | 脚本语法错误 | 在 %post 开头加 set -x,完成后检查 /root/post-install.log |
| 安装后无法 SSH | SSH 密钥未生成或防火墙 | %post 中显式生成 SSH 密钥,关闭 firewalld |
| 主机名未设置 | %post 脚本未执行 | 检查 Kickstart 格式,确保 %post 缩进无异常 |
# 当安装失败时,在目标机上按 Ctrl+Alt+F2/F3 切换至 Shell 终端# 查看安装日志tail -f /tmp/anaconda.logtail -f /tmp/syslogtail -f /tmp/program.log# 或重启时在 grub 菜单按 e 编辑,加入如下参数获取详细日志:inst.debug=1 rd.shell=1 rd.break=pre-mount# 查看 HTTP KS 文件是否可访问(在目标机的安装 shell 中)curl http://192.168.100.10/ks/openEuler-ks.cfg# 手动触发安装python3 /usr/sbin/anaconda --text --kickstart http://192.168.100.10/ks/openEuler-ks.cfg
13.5 硬件兼容性
| 问题 | 原因 | 解决方案 |
|---|---|---|
| 华为鲲鹏 920 CPU | aarch64 架构 | 使用对应 ARM64 的引导文件和 ISO |
| NVMe SSD 不可见 | 缺少 nvme 驱动 | kernel 参数加 nvme_core.default_ps_max_latency_us=0 |
| 特定网卡不驱动 | 固件或驱动缺失 | 找厂商提供 driver rpm,通过 inst.dd= 加载 |
| BMC 不稳导致重启失败 | 固件问题 | 分批重启,每批 5 台,间隔 30 秒 |
常见硬件 BMC PXE 唤醒命令
华为 iBMC / iBMC 2.0:
# 华为 FusionServer 系列ipmitool -I lanplus -H 192.168.100.101 -U root -P Huawei12#$ chassis bootdev pxe options=efibootipmitool -I lanplus -H 192.168.100.101 -U root -P Huawei12#$ power reset
ipmitool -I lanplus -H 192.168.100.101 -U admin -P password chassis bootdev pxeipmitool -I lanplus -H 192.168.100.101 -U admin -P password power reset
racadm -r 192.168.100.101 -u root -p calvin set iDRAC.ServerBoot.BootOnce 1racadm -r 192.168.100.101 -u root -p calvin set iDRAC.ServerBoot.FirstBootDevice PXEracadm -r 192.168.100.101 -u root -p calvin serveraction powercycle
ipmitool -I lanplus -H 192.168.100.101 -U USERID -P PASSW0RD chassis bootdev pxeipmitool -I lanplus -H 192.168.100.101 -U USERID -P PASSW0RD power reset
安全建议
部署网络使用独立 VLAN,部署完成后断开或限制访问Kickstart 中的 Root 密码使用高复杂度密码,上线后立即更改SSH 公钥注入后建议关闭密码登录POST 脚本中安装完 OS 后记录序列号 → IP → 主机名对应关系保留每台机器的初始安装日志(anaconda.log)部署完成后通过网络审计所有 20 台机器的一致性(包版本、内核参数、配置等)将本文的 KS 文件和配置纳入版本控制(GitLab/Gitee)
夜雨聆风