拓十年匠心定制 · 商业建站与技术教学双线并行 咨询热线:400-886-1026 service@lmnt.cn
ARTICLE DETAIL

资讯详情

深耕网站建设与运营推广的一线实战洞察。

基于Ubuntu部署PXE Server实现网络批量安装与无人值守

基于Ubuntu部署PXE Server实现网络批量安装与无人值守

1. 先聊清楚:为什么我要折腾 PXE Server

机房那排机柜里躺着十二台二手服务器,老板一句"下周全部换 Ubuntu 24.04",我当时头皮是麻的。一台台插 U 盘、进 BIOS 改启动顺序、盯着进度条、装完再改回来,单台保守估计四十分钟,中间还得有人守着。更别提有几台机器挂在机柜最上面,键盘显示器够不着,每次都得拖个 KVM 小车过来。所以这次我下定决心,把 Ubuntu 的网络安装环境搭起来,让机器自己从网卡启动、自己拉内核、自己装系统。这就是标题里说的基于 Ubuntu 部署 PXE Server 用于网络安装 Ubuntu这套东西。

PXE 全称是 Preboot Execution Environment,直白讲就是网卡里内置了一小段固件程序,机器开机时如果被设成网卡启动,它就会朝局域网喊一句"谁有启动文件",然后从服务器把引导程序和系统内核拉下来跑。整个过程不需要 U 盘、不需要光驱、不需要本地磁盘上预先放任何东西。对于手里有十几台以上机器、或者机器放在伸手够不着的地方、又或者同一个型号反复重装的场景,一次搭好能省下成吨的时间。

这套方案适合谁?我按经验分三类。第一类是运维和 IT 支持,尤其负责机房批量交付的;第二类是自己在家搞了几台小主机、NAS、软路由,喜欢折腾多系统的;第三类是做嵌入式或者开发板相关的,需要频繁给 x86 设备刷系统的。这三类人诉求不一样,前两类更看重"省事、可自动化",第三类更看重"可定制、能塞自己的脚本"。所以下面我会把搭建过程讲全,同时把可以裁剪、可以定制的点单独标出来,你按自己的场景取用就行。

开头先给个心理预期:PXE 这东西门槛不在原理,原理十分钟能讲完,坑全在细节——网卡固件差异、UEFI 和传统 BIOS 的引导文件不一样、DHCP 和 TFTP 的配置稍有不慎就连不上、防火墙默默拦包。我踩过的坑基本都在第 4 章里列全了,你可以先跳到那里看看心里有没有底,再回来按顺序搭。

2. 方案选型:U 盘、克隆和 PXE 到底怎么挑

2.1 几种批量装机路子的真实对比

在动手之前,我建议你先想清楚自己到底需不需要 PXE。因为我见过太多人为了装三台机器去搭 PXE,结果配置 DHCP 花了一整天,还不如手工。下面这张表是我这几年实际用下来的体感总结,不是理论值,是"真干活时"的耗时。

方案首次搭建成本单台装机耗时批量效率自动化程度适用场景
U 盘启动盘10 分钟30-50 分钟(含人工盯守)差,串行低1-3 台,偶尔装
Ventoy 多合一 U 盘30 分钟25-40 分钟一般,仍需人工中低多版本切换,5 台以内
磁盘克隆(dd/再生龙)半天10-20 分钟好,但一致性要求高中同型号大批量,配置完全一致
PXE 网络安装半天到一天10-25 分钟优秀,可并行高,可零接触10 台以上,或机器难接触
PXE + 自动化应答一天以上8-15 分钟无人值守优秀,可并行极高机房交付、标准化环境

看这张表你会发现,PXE 的首次搭建成本其实不低,如果你一年只装两三台机器,那纯属自找麻烦。但一旦上了规模,边际成本几乎为零——第二十台和第一台花的功夫一模一样,而且不用人在旁边守着。

2.2 为什么我选 dnsmasq 而不是分开装 DHCP 和 TFTP

搭建 PXE 有两条主流路线,我在两台环境上分别试过,各有取舍。

第一条是dnsmasq 一把梭。dnsmasq 本身是个轻量 DNS/DHCP 服务,但它同时支持 TFTP,还支持在 DHCP 响应里塞引导文件名。也就是说,一台机器、一个配置文件、一个 systemd 服务,DHCP、DNS、TFTP 全齐了。配置文件不过二三十行,改完systemctl restart dnsmasq就生效。对个人和中小规模场景,这是最省心的。

第二条是isc-dhcp-server + tftpd-hpa 分工。DHCP 归 DHCP,TFTP 归 TFTP,职责清晰。好处是如果公司网络里已经有一台 DHCP 服务器在跑,你不想再起一台抢生意的,可以让现有 DHCP 只负责发引导参数,TFTP 单独跑。这种"已有 DHCP、只加引导信息"的需求,dnsmasq 也能做,但用 isc-dhcp 的next-server和filename指令更符合老运维的习惯。

我这次选 dnsmasq,理由很实在:环境是我自己的实验网段,没有现成 DHCP,也不需要复杂的作用域策略。如果你是要在生产办公网里插一脚,我的建议是别动现有 DHCP,单独划一个 VLAN 出来跑 PXE,或者用 dnsmasq 的"只发引导信息不发地址"模式,避免把整个办公网的地址分配搞乱。这一点后面 4.3 节我会细说,那是我见过最刺激的一次事故。

2.3 整个链路的数据流:先搞懂谁跟谁说话

很多人配完连不上,就是因为不清楚"机器开机那几秒到底发生了什么"。我用送快递打个比方:

  1. 客户端开机,网卡固件发一个DHCP Discover广播,内容大意是"我在这,有启动文件给我吗",里面带了一个关键字段client-arch,标明自己是传统 BIOS 还是 UEFI、是 x86 还是 ARM。
  2. PXE 服务器(dnsmasq)收到后回DHCP Offer/ACK,除了给 IP 地址,还附带三样东西:TFTP 服务器地址(next-server)、引导文件名(filename)、以及一些 PXE 专属选项。
  3. 客户端拿到信息,用TFTP去服务器把引导程序(传统 BIOS 是pxelinux.0,UEFI 是grubx64.efi或ipxe.efi)下载到内存里执行。
  4. 引导程序再去读它的配置菜单,把Linux 内核 vmlinuz 和初始内存盘 initrd拉下来。
  5. 内核启动安装器,安装器再通过HTTP 或 NFS去取真正的安装镜像(squashfs 之类),然后开始装。

关键点来了:TFTP 只负责传小文件,大文件走 HTTP。TFTP 是 UDP 协议,没有窗口机制,传几百兆的镜像能慢到让你怀疑人生。所以标准做法是引导阶段用 TFTP,安装阶段切 HTTP。这条经验值一条命,很多人卡在安装器加载慢,就是没做这个切换。

3. 服务端搭建:从装包到能引导的完整过程

3.1 基础环境准备和 IP 规划

我用的服务端是一台装了 Ubuntu 22.04 LTS 的旧机器,配置不高,4 核 8G 内存,一块 128G 的 SSD 装系统,另外挂了一块 1T 的盘专门放镜像文件。这里强调两点:服务端必须是静态 IP,而且这个网段不能有别的 DHCP 在跑,否则客户端可能拿到别人发的地址,引导直接失败。

先把网络规划定死,别一边配一边改,改一处忘一处最容易出错:

项目取值说明
服务端网卡enp3s0用ip a确认实际名字
服务端 IP192.168.100.10/24静态,写进 netplan
网段192.168.100.0/24建议单独划出来
DHCP 地址池192.168.100.100 - 192.168.100.200避开服务端自身
TFTP 根目录/srv/tftp建议独立分区或大盘
HTTP 根目录/srv/www放镜像和应答文件
网关/路由下发给客户端192.168.100.10(不给了就不给,见后文)看是否需要外网

静态 IP 用 netplan 配,Ubuntu 22.04/24.04 都适用:

# /etc/netplan/01-pxe.yaml network: version: 2 ethernets: enp3s0: dhcp4: false addresses: - 192.168.100.10/24

改完执行sudo netplan apply,再用ip a确认地址生效。这里有个小坑:如果你之前用 NetworkManager 管过这块网卡,netplan 和 NM 可能打架,表现为地址配了但不生效。检查/etc/netplan/下有没有多余的文件,以及/etc/NetworkManager/conf.d/里有没有把这个网卡设为 unmanaged。

提示:实验阶段我建议把服务端和客户端接在同一台交换机上,物理上隔离,别接到办公室的大网里。等你确认整套流程跑通,再考虑要不要接入生产网。

3.2 引导文件从哪来:netboot 和 iPXE 两条路线

引导文件是 PXE 的"启动钥匙",这块最容易被版本差异坑到。Ubuntu 目前有两条拿引导文件的路子。

路线 A:传统 netboot(debian-installer 系)

这条路用的安装器是老的 d-i,体积小,非常适合做自动化安装,缺点是界面朴素、对新硬件支持略慢。文件从官方源的legacy-images/netboot目录取,以 jammy(22.04)为例:

sudo mkdir -p /srv/tftp cd /srv/tftp sudo wget http://archive.ubuntu.com/ubuntu/dists/jammy/main/installer-amd64/current/legacy-images/netboot/netboot.tar.gz sudo tar xzf netboot.tar.gz sudo chown -R dnsmasq:dnsmasq /srv/tftp

解压后目录结构大致是这样:传统 BIOS 用的pxelinux.0加ldlinux.c32、pxelinux.cfg/菜单目录,UEFI 用的ubuntu-installer/amd64/grubx64.efi和grub/grub.cfg,以及真正安装用的ubuntu-installer/amd64/下的linux(内核)和initrd.gz。

路线 B:iPXE 链式加载(我更推荐)

iPXE 是个开源的 PXE 实现,比网卡自带的 PXE 固件强太多——它支持 HTTP 下载引导文件(比 TFTP 快几十倍)、支持脚本、支持菜单变量、支持 UEFI 和传统 BIOS 用同一套配置。Ubuntu 仓库里就有:

sudo apt install ipxe ls /usr/lib/ipxe/ # 通常能看到 ipxe.efi、undionly.kpxe、snponly.efi 等文件 sudo cp /usr/lib/ipxe/ipxe.efi /usr/lib/ipxe/undionly.kpxe /srv/tftp/

ipxe.efi给 UEFI 机器用,undionly.kpxe给传统 BIOS 用。注意,仓库里的预编译版可能不带网卡驱动或者被剪裁过,如果客户端网卡比较新、加载后报"no such device",你得自己去 iPXE 官方源码编译一份带驱动的。我一般先用仓库版试,不行再编译。

用 iPXE 的好处是,客户端第一次通过 TFTP 拿到一个小小的 iPXE 程序(也就几百 KB),之后所有引导文件、内核、镜像全部走 HTTP,速度直接起飞。后面 3.4 节的菜单也会用 iPXE 脚本写,比 grub 配置顺手。

注意:不管你用哪条路线,传统 BIOS 和 UEFI 需要的引导文件名完全不同,配置文件必须靠client-arch区分。UEFI 是option 93值为 7(x86_64 UEFI)或 9(x86_64 UEFI HTTP),传统 BIOS 是 0。这个数字写错一个,机器就卡在启动画面。

3.3 dnsmasq 配置文件逐行拆解

现在到核心了。装包:

sudo apt update sudo apt install dnsmasq sudo systemctl stop dnsmasq

先停掉它,因为默认配置会监听所有接口、还会读/etc/resolv.conf,跟我们想要的行为冲突。Ubuntu 桌面版可能自带 systemd-resolved 占着 53 端口,如果你不需要这台机器做 DNS,可以在 dnsmasq 里关掉 DNS 功能。完整配置如下,我按块拆:

# /etc/dnsmasq.d/pxe.conf # 只监听 PXE 那块的网卡,千万别写 all interface=enp3s0 bind-interfaces # 关掉 DNS 功能,避免和 systemd-resolved 抢 53 端口 port=0 # DHCP 地址池,租期 12 小时 dhcp-range=192.168.100.100,192.168.100.200,255.255.255.0,12h # 下发路由器(也就是这台机器自己),不需要上网可以删掉这行 dhcp-option=3,192.168.100.10 # 下发 DNS,装系统后要能解析域名 dhcp-option=6,192.168.100.10 # 开启 TFTP enable-tftp tftp-root=/srv/tftp # 传统 BIOS 机器和 UEFI 机器给不同的引导文件 dhcp-match=set:bios,option:client-arch,0 dhcp-match=set:efi64,option:client-arch,7 dhcp-match=set:efi64,option:client-arch,9 dhcp-boot=tag:bios,undionly.kpxe dhcp-boot=tag:efi64,ipxe.efi # 已经跑过 iPXE 的机器再发 DHCP 时,直接给脚本地址 dhcp-userclass=set:ipxe,iPXE dhcp-boot=tag:ipxe,http://192.168.100.10/boot.ipxe # 详细日志,排查阶段必开,稳定后可去掉 log-dhcp log-queries

逐块解释几个容易写错的地方。

interface和bind-interfaces必须成对出现。只写interface的话,dnsmasq 在某些情况下仍会监听通配地址;加上bind-interfaces才是真正的"只绑这块网卡"。如果你的服务端有多张网卡,这里写错会直接把 DHCP 发到不该发的网段,这就是 4.3 节那个事故的根源。

port=0是关掉 DNS 的写法。但如果你的客户端装系统时需要解析主机名(比如从网上拉包),那就别关,改成port=53并把 systemd-resolved 停掉,否则两个服务抢端口,dnsmasq 起不来。

dhcp-userclass=set:ipxe,iPXE这一行是 iPXE 链式加载的关键。iPXE 启动后会再发一次 DHCP 请求,并在请求里带上user-class=iPXE。我们用这个特征把它和第一次请求区分开:第一次给引导文件(ipxe.efi),第二次给脚本地址(boot.ipxe)。没有这行,机器就会陷入"不断加载 iPXE 又不断重启"的死循环,这个现象非常常见。

配置写好后:

sudo systemctl restert dnsmasq # 注意这里是 restart,别学我打错 sudo systemctl status dnsmasq sudo journalctl -u dnsmasq -f

(上面那行restert是我故意留的错,第一次搭的时候我确实打错过,还纳闷为什么配置没生效。命令要写restart。)

3.4 HTTP 服务、iPXE 菜单和自动应答文件

TFTP 只管引导,真正的镜像和应答文件走 HTTP。服务端起个 nginx,配置极简:

sudo apt install nginx sudo mkdir -p /srv/www sudo ln -s /srv/www /var/www/html/pxe

然后把 boot.ipxe 脚本放到/srv/www/下:

#!ipxe dhcp set base http://192.168.100.10/pxe menu Ubuntu 网络安装菜单 item --gap -- ------------------------------ item ubuntu2204 安装 Ubuntu 22.04 LTS (自动应答) item ubuntu2404 安装 Ubuntu 24.04 LTS (自动应答) item shell 进入 iPXE 命令行 choose --default ubuntu2404 --timeout 15000 target && goto ${target} :ubuntu2204 kernel ${base}/jammy/vmlinuz initrd=initrd.gz auto=true priority=critical url=http://192.168.100.10/pxe/jammy-preseed.cfg --- initrd ${base}/jammy/initrd.gz boot :ubuntu2404 kernel ${base}/noble/vmlinuz initrd=initrd.gz auto=true priority=critical url=http://192.168.100.10/pxe/noble-autoinstall.yaml --- initrd ${base}/noble/initrd.gz boot :shell shell

这里我把 22.04 和 24.04 的内核、initrd 分别下载到/srv/www/jammy/和/srv/www/noble/。它们从哪来?netboot 包里就有,也可以从 live-server ISO 里把casper/vmlinuz和casper/initrd抠出来。用 live-server 的镜像装出来的是现在那种图形/半图形安装器,体验更接近你手工装系统,种子文件格式也不同(autoinstall的 YAML)。

给 22.04 的 preseed 片段示例:

# /srv/www/jammy-preseed.cfg d-i debian-installer/locale string en_US.UTF-8 d-i keyboard-configuration/xkb-keymap select us d-i netcfg/choose_interface select auto d-i netcfg/get_hostname string node d-i netcfg/get_domain string local d-i mirror/country string manual d-i mirror/http/hostname string archive.ubuntu.com d-i mirror/http/directory string /ubuntu d-i mirror/http/proxy string d-i passwd/root-login boolean false d-i passwd/user-fullname string ops d-i passwd/username string ops d-i passwd/user-password-crypted password $6$xxxxxxxx$yyyyyyyy d-i clock-setup/utc boolean true d-i time/zone string Asia/Shanghai d-i partman-auto/method string lvm d-i partman-auto/choose_recipe select atomic d-i partman/confirm_write_new_label boolean true d-i partman/choose_partition select finish d-i partman/confirm boolean true d-i pkgsel/include string openssh-server curl vim d-i grub-installer/only_debian boolean true d-i finish-install/reboot_in_progress note

密码那行用openssl passwd -6 你的明文密码生成。别直接写明文,d-i 虽然也吃明文,但一旦配置泄露就麻烦了。

给 24.04 的 autoinstall YAML:

#cloud-config autoinstall: version: 1 locale: en_US.UTF-8 keyboard: layout: us network: version: 2 ethernets: all-en: match: name: "en*" dhcp4: true identity: hostname: node01 username: ops password: "$6$xxxxxxxx$yyyyyyyy" ssh: install-server: true allow-pw: true storage: layout: name: lvm match: size: largest packages: - curl - vim - htop late-commands: - curtin in-target -- timedatectl set-timezone Asia/Shanghai shutdown: reboot

YAML 对缩进极其敏感,必须用空格,绝不能用 Tab。我见过有人复制粘贴的时候带进去一个 Tab,结果安装器报"invalid cloud-config",然后退回到交互模式,你还得手动点一遍。写完用python3 -c "import yaml,sys; yaml.safe_load(open('/srv/www/noble-autoinstall.yaml'))"校验一下语法,这个习惯能救命。

4. 客户端验证与故障排查实录

4.1 排错顺序:先用抓包确认"谁没说话"

客户端开机进网卡启动画面,然后就卡住了——这时候最忌讳的是瞎改配置。我的固定套路是,先确认链路哪一环断了,再对症下药。抓包命令如下:

# 看 DHCP 有没有来回 sudo tcpdump -i enp3s0 -n port 67 or port 68 # 看 TFTP 请求到达和响应 sudo tcpdump -i enp3s0 -n port 69 # 服务端日志,最直接 sudo journalctl -u dnsmasq -f

判断逻辑很清晰:

  • 完全看不到客户端的 DHCP 包:物理问题。网线、交换机端口、客户端没把网卡设成第一启动项、或者客户端和服务端不在同一个二层网络。
  • 看到 DHCP Discover 但没有 Offer:服务端的 dnsmasq 没在听这块网卡,或者配置报错没起来。先systemctl status dnsmasq看是否 active。
  • 有 Offer、客户端也拿到了 IP,但 TFTP 超时:TFTP 根目录路径写错、权限不对、防火墙拦了 UDP 69、或者filename指向的文件根本不存在。
  • TFTP 拿到了引导文件,但引导程序加载后找不到内核:菜单配置里的路径写错,或者内核文件权限是 root 只有 dnsmasq 读不到(nginx 管的 HTTP 就没这问题,所以大文件走 HTTP 也规避了不少权限坑)。

这套顺序我用下来,八成的问题三步之内能定位。别一上来就全量重装,那是浪费时间。

4.2 常见问题速查表

现象最可能的原因快速验证方法处理方式
客户端拿不到 IPdnsmasq 没监听正确网卡 / 有第二个 DHCP 在抢tcpdump port 67看有没有外来 Offer检查interface,隔离网段
拿到 IP 后卡在 "PXE-E32: TFTP open timeout"TFTP 根目录错 / 防火墙tftp 192.168.100.10手动 get 一个文件放行 UDP 69,检查tftp-root
报 "PXE-E53: No boot filename received"dhcp-boot没匹配上 client-arch日志里看客户端 arch 值补全dhcp-match
UEFI 机器卡在 grub 命令行只给了 BIOS 的引导文件看抓包里 client-arch 是不是 7单独配 UEFI 分支
反复重启、循环加载iPXE 链式加载没做 user-class 区分看是否重复收到同一下载请求加dhcp-userclass=set:ipxe,iPXE
内核加载后 panic 找不到 initrd内核和 initrd 版本不匹配看是不是从不同版本目录混着拿的同一版本目录一起取出
安装器启动但拉不到镜像HTTP 路径 404 / nginx 没起浏览器直接访问那个 URL检查软链接和权限
安装到分区阶段卡死自动化种子文件语法错看屏幕有没有报 yaml/parse error用 yaml 校验器查一遍
Secure Boot 报验证失败引导程序没签名BIOS 里 Secure Boot 状态关掉或换官方签名引导
装完系统连不上网下发了错误的网关/DNS客户端ip a和ip r修正dhcp-option=3/6

4.3 几个只有踩过才知道的坑

第一个坑,也是最危险的:多网卡 +interface写错,把 DHCP 发到了办公网。

我当时那台服务端有两块网卡,一块接办公网(有现成 DHCP),一块接实验网。配置里我图省事写了interface=all,重启 dnsmasq 的瞬间,办公网里开始出现 192.168.100.x 的地址——因为我的地址池跟办公网段不冲突,客户端拿到后照样能用,但网关被我下成了 192.168.100.10,导致一大批同事莫名其妙上不了网。这个事故被发现是因为有人喊"我的机器 IP 变成 192.168 了"。教训是:只要是多网卡环境,interface必须精确到那一块,并且加bind-interfaces。现在我还养成了习惯,改完配置先ss -lunp | grep :67确认监听地址,再重启。

第二个坑:ufw 默认开着,TFTP 和 DHCP 全被拦。

Ubuntu 服务版默认 ufw 是不启用的,但如果你之前开过,规则就得补。DHCP 服务端用 UDP 67,TFTP 用 UDP 69,而且 TFTP 的数据传输是动态端口,光放行 69 不够。最省事的做法是只针对那块网卡放行:

sudo ufw allow in on enp3s0

或者干脆把 PXE 那块网卡设为信任接口。别去精细放行一堆端口,TFTP 的动态端口能把你逼疯。

第三个坑:Ubuntu 24.04 的 netboot 目录和 22.04 不一样。

我一开始照着旧教程去 archive 上找 noble 的legacy-images/netboot,路径对不上,折腾半天。后来确认了版本差异:如果你走 live-server 路线,就别去翻 netboot 目录了,直接从 ISO 里抠casper/vmlinuz和casper/initrd,配 autoinstall 的 YAML。这也是为什么我在 3.4 节把两条路线分开写——版本越新,越倾向 live-server 那套。这个差异官方文档不会在显眼处提醒你,只能自己试出来。

第四个坑:TFTP 传大文件慢得离谱。

前面提过,但值得再强调。TFTP 是 UDP,没有拥塞控制和窗口,一个 100MB 的文件在百兆网里能传好几分钟,还容易丢包重传。解决办法就是别用 TFTP 传大文件。我甚至建议内核和 initrd 都走 HTTP,只把引导程序留在 TFTP 里。iPXE 天生支持 HTTP 的kernel和initrd指令,速度差别是数量级的。

第五个坑:客户端机器上启用了 Secure Boot,引导直接被拒。

UEFI 的 Secure Boot 会校验引导程序签名。iPXE 和自编译的 grub 通常没签名,会被拦。iPXE 官方提供签过名的ipxe.efi版本(在官方发布包里带signed字样),用它就能过;或者最简单,进 BIOS 把 Secure Boot 关掉。机房机器如果 BIOS 密码被前人设过,这一关可能比配置 PXE 还难,提前确认好权限。

5. 进阶玩法:从"能装"到"装得漂亮"

5.1 多版本共存与菜单定制

真实的运维环境里,你不可能只用一种 Ubuntu 版本。老业务跑 20.04,新业务上 24.04,测试环境还想试 26.04。所以菜单得支持多版本共存。做法很简单,在/srv/www/下按版本建子目录,把各自的内核和 initrd 分开放,然后在boot.ipxe里加 menu item 就行。

菜单还可以做得更聪明一点。比如让客户端根据 MAC 地址或者机器型号自动选择版本:iPXE 支持条件判断,可以用${net0/mac}变量来判断。我做过一个场景,同一批机器里有两种型号,一种需要额外加载网卡驱动,另一种不需要,就用 MAC 前缀在脚本里做了分支。菜单 timeout 也别设太短,默认 15 秒比较合适,机房里的机器启动慢,太短了还没来得及选就自动进了。另外 iPXE 的菜单支持子菜单,item --gap可以做分隔线,做出来比 grub 的菜单清爽。

5.2 配合 cloud-init 做真正的零接触安装

前面 3.4 节的 autoinstall 是个起点,真正要做到"插上电就走人",还得靠 cloud-init 把后期的初始化也一并做掉。比如你想让所有机器装完后自动注册到监控、自动挂载 NFS、自动配置内部源,这些都可以塞进 late-commands 或者 user-data 里。

具体怎么做?把 cloud-init 的 user-data 也放一份到 HTTP 上,安装器装完系统第一次启动时会去读它。常见的初始化动作包括:

#cloud-config package_update: true packages: - qemu-guest-agent - chrony write_files: - path: /etc/apt/sources.list.d/internal.list content: | deb http://192.168.100.10/ubuntu jammy main restricted runcmd: - systemctl enable --now chrony - echo "installed at $(date)" > /etc/install-stamp

需要注意的是,cloud-init 的执行是分阶段的,runcmd里如果依赖网络,得确保network段配好了。还有,write_files写入的文件权限默认是 root,如果服务要以普通用户读,得显式加owner和permissions。这些细节不做自动化的时候感受不到,一旦上量,一个字段写错就是几十台机器全要重装。

5.3 稳定性和性能上的一些调优经验

搭好能跑是一回事,跑得稳是另一回事。几个我实际调过的点:

第一,把镜像和 TFTP 目录放在 SSD 或者内存盘上。TFTP 本身不怕读慢,怕的是多客户端并发时的磁盘 IO 抖动。如果你一次要装二十台,服务端的磁盘很容易成瓶颈,用 nginx 的sendfile加缓存能缓解不少。

第二,服务端 dnsmasq 的dhcp-lease-max要设够。默认值有时候不够用,并发装机时会出现部分客户端拿不到地址。设成比你实际机器数多一倍比较保险。

第三,日志别一直开着 debug 级别。log-dhcp在排查时是神器,但稳定运行后每台客户端启动都刷一堆日志,磁盘几周就写满。我的做法是排查完就把这行注释掉,只留正常日志。

第四,做个健康检查脚本。写个简单的 shell,每隔几分钟检查 dnsmasq 是否 active、HTTP 目录里的关键文件是否还在、TFTP 能否正常读取,异常就给你发通知。PXE 服务是那种"平时没人管、出事就全员停工"的服务,加个监控成本很低,收益很高。

最后分享一个我个人最看重的经验:先在一台淘汰的笔记本上把全流程跑通,再去机房。因为 PXE 的坑集中在"第一次",而第一次最可能碰上的是物理连接问题、网卡固件差异、BIOS 设置细节。在办公室用一台能被你随便重启的旧机器反复试,比在机房里弯腰插拔网线试高效太多。我那次在实验室用一台十年前的笔记本整整调了一下午,等到机房真机部署时,十二台机器一个半小时全部装完,中间只处理了一台 Secure Boot 没关的问题。那种"配置一次、批量收割"的感觉,才是这套方案真正的价值所在。

返回列表