UDS 正式发布:从“手动维护 200 个配置文件“到“一条命令生成全集群 PXE 配置
两个月前,我们还在用文本编辑器逐个维护每台裸金属节点的grub.cfg菜单项和user-data文件。那时完成一个 50 节点的上架批次,运维同事需要复制粘贴、修改 IP、检查 YAML 缩进三小时以上。
今天,这个过程被压缩到了30 秒。
—
上一次的痛点,为什么手动方案走不远
如果你读过上篇关于 PXE + Ubuntu Autoinstall 的基础方案,应该记得结尾我们预告了 UDS 并列出几个硬伤:
- 菜单爆炸:每换一种 OS 版本或分区策略,就得在
grub.cfg里新增一组菜单项。 - User-Data 碎片化:每台机器一个
user-data,文件名靠 MAC 地址区分,改一个全局参数(比如 DNS)要批量 sed。 - 网卡名称踩坑:Ubuntu 20.04 识别为
ens17f0,升级到 22.04 HWE 内核变成ens17f0np0,Netplan 配置直接失效。 - 装机后二次配置:IP 地址虽然在装机时通过 DHCP 获取,但业务 Bond 网络还是得 SSH 进去手动改 Netplan 再重启。
这些问题在节点量少的时候还能忍,但当你的集群要从 50 台扩展到 200 台、横跨两个 IDC、涉及 A100 和 4090 两种异构机型时,手动维护就是一颗定时炸弹。
我们需要一个配置即代码的渲染引擎,而不是一堆需要手工缝合的静态文件。
UDS 是什么:一个约定优于配置的 PXE 配置生成器
UDS(Unified Deployment System)是我们针对异构 GPU 数据中心开发的自动化部署配置引擎。它不替代你的 DHCP、TFTP 或 Nginx,而是坐在这些基础设施之上,把"节点清单"翻译成"可执行的 PXE 配置"。
核心设计哲学只有一条:约定优于配置(Convention over Configuration)。
你不需要记住某台机器的网卡叫ens111f0np0还是ens13f0np0。只要它的 hostname 是XJ-DC1-R4090-106,UDS 就知道它是一期机房的一台 4090,默认使用 G13 网卡模型,存储布局是sda+sdb,NVLink 关闭。
# conf/nodes.yaml —— 你只需维护这一份清单nodes:-mac:"68:91:D0:70:17:97"hostname:"XJ-DC1-R4090-106"os:version:"ubuntu24043"filesystem:"ext4"network:bond0:ip:"10.2.23.11"netmask:"255.255.255.192"gateway:"10.2.23.62"UDS 会基于这 10 行配置,自动生成:
- 该节点的完整
user-data(含 Netplan、存储分区、late-commands) - TFTP 目录下
grub.cfg中对应的引导菜单项 - 按 MAC 地址隔离的节点配置目录结构
运行方式只有一行:
python bin/uds.py\--output-res-dir /usr/share/nginx/html/res\--output-tftp-dir /var/lib/tftpboot\--server-ip10.1.8.5运行后,TFTP 目录下的grub.cfg会自动生成按节点区分的引导菜单,PXE 启动时可直接选择目标节点:
关键技术决策:我们是怎么做到的
1. Hostname 作为唯一事实来源
在多机型、多 IDC 环境中,最容易出错的不是配置语法,而是把 A 机型的网络模板套到了 B 机型上。
UDS 的解决方案是把 hostname 当作唯一标识,通过模式匹配推断所有硬件参数:
| Hostname 模式 | 推断结果 | 影响 |
|---|---|---|
包含DC1 | 一期机房 | 单 Bond 网络、直连存储策略 |
包含DC2 | 二期机房 | 双 Bond 网络、需配置静态路由 |
包含A100 | 训练节点 | 开启 NVLink、加载 Fabric Manager |
包含R4090 | 推理节点 | 关闭 NVLink、标准 CUDA 安装 |
variant: g12 | 旧款网卡 | 网卡映射为ens111f0np0/ens121f0np0 |
这意味着运维同学只需要按照命名规范填写 hostname,系统就会自动拉取正确的网络 Profile 和存储布局,不需要去查 wiki 里的"某机型网卡对照表"。
2. 网络拓扑完全外置:profiles.yaml
把网络配置写死在代码里是 many IaC 工具的早期陷阱。UDS 把网络拓扑定义完全剥离到conf/profiles.yaml:
idc2-4090:ethernets:-ens17f0-ens20f0-ens17f1-ens20f1bonds:bond0:interfaces:[ens17f0,ens20f0]parameters:{mode:802.3ad,lacp-rate:fast}bond1:interfaces:[ens17f1,ens20f1]parameters:{mode:802.3ad,lacp-rate:fast}这样做有两个好处。一是新机型上架时,不需要改 Python 代码,加一段 YAML 即可。二是网络团队可以直接维护这份文件,无需了解生成器的内部逻辑。
3. 网卡名称兼容性:Match & Rename 机制
这是我们踩过最多的坑。同一个硬件平台,Ubuntu 20.04.6 的内核识别网卡为ens17f0,而 24.04.3 的内核识别为ens17f0np0。如果 Netplan 里写死了名称,装机后直接失联。
UDS 的解决方式是在生成的 Netplan 配置中自动注入match/set-name规则:
ethernets:ens17f0:match:name:"ens17f0*"set-name:ens17f0无论底层实际名称是ens17f0还是ens17f0np0,Netplan 都会将其统一重命名为ens17f0,确保 Bond 配置始终生效。
这个功能通过network_unified_naming参数控制,默认关闭(显式优于隐式),仅在你确认需要跨内核版本兼容时开启。
4. 无锚点 YAML 生成策略
Cloud-init 对 YAML 的解析器比较挑剔,YAML 锚点(&id001)和别名(*id001)在某些版本下会导致解析失败。
UDS 的 YAML 生成器强制继承yaml.SafeDumper并重写ignore_aliases方法,确保输出的user-data100% 是无锚点的扁平结构。这是我们从早期测试中不断试错后加上的防御性设计。
classNoAliasDumper(yaml.SafeDumper):defignore_aliases(self,data):returnTrue5. 动态 URL 路径计算:支持多期项目共存
在真实生产环境中,一期项目和二期项目可能共用同一台 PXE 服务器,但静态资源放在不同子目录下。UDS 根据--output-res-dir参数动态计算user-data的 HTTP URL:
- 输出到
/usr/share/nginx/html/res→ URL 指向/res/nodes/<mac>/ - 输出到
/usr/share/nginx/html/res/cxn→ URL 指向/res/cxn/nodes/<mac>/
这不需要你在代码里写 if-else,生成器会自动根据路径的相对位置拼接出正确的 URL。
Excel 导入:从采购清单到 nodes.yaml
对于批量上架场景,手动编辑 YAML 仍然不够快。UDS 提供了excel_to_nodes.py工具,允许你从采购部门提供的 Excel 表格直接生成配置。
# 1. 生成标准模板python bin/excel_to_nodes.py--template# 2. 采购部填完 MAC、IP、Hostname 后发回# 3. 一键转换python bin/excel_to_nodes.py-iinventory.xlsx-oconf/nodes.yaml模板中包含智能默认值:OS 版本默认ubuntu22044,文件系统默认xfs,NVIDIA 驱动默认575。你只需要填写关键列(MAC、Hostname、IP),其余留空即可。
生成器内部架构
UDS 的架构刻意保持极简,没有数据库、没有守护进程、没有 Web UI,只有三个核心组件:
uds.py:主生成逻辑,负责推断、渲染、输出。user-data.template:Jinja2 模板,定义了 Autoinstall 的完整结构。profiles.yaml:网络拓扑定义,纯数据无逻辑。
我们尝试过但没走的路
在决定自研 UDS 之前,我们评估过 MAAS 和 Ironic:
| 维度 | UDS | MAAS | Ironic |
|---|---|---|---|
| 架构复杂度 | 无状态脚本 | PostgreSQL + Region/Rack 控制器 | 依赖 OpenStack 组件群 |
| 网络管控 | 依赖外部 DHCP,专注配置生成 | 内置 DHCP/DNS/IPAM | 依赖 Neutron |
| 上手成本 | 5 分钟 | 数小时到数天 | 数周 |
MAAS 的功能确实更全,但在我们的场景里,网络基础设施(交换机、DHCP Relay)已经由网络团队维护好了,我们只需要一个"把操作系统和驱动装上去"的工具。引入 MAAS 意味着多一套需要监控和排错的分布式系统,收益不成正比。
如果你的需求是"从零构建一个完整的数据中心网络",MAAS 是合理的选择。但如果你已经有网络,只想快速批量装机,UDS 这种轻量级配置引擎更划算。
从手动到自动:效率对比
过去维护 50 个节点需要:
- 手动编辑 50 个
user-data文件 - 手动维护
grub.cfg中的 50 个菜单项 - 每次改全局参数都要批量 sed
现在只需要维护一份nodes.yaml或一个 Excel 表格,一条命令生成全部配置。改 DNS、换 ISO 镜像、调整 Bond 参数,都只需要改一处。
已知限制和后续规划
UDS 目前不是万能药,有几个明确的边界:
- 无状态管理:UDS 只负责生成配置,不追踪节点的装机进度或健康状态。装机后的监控仍需配合现有监控系统。
- 无 Web UI:所有操作通过命令行和 YAML 完成。如果需要图形界面,目前得自己包一层。
- DHCP 外部依赖:UDS 不替代 DHCP 服务,你需要确保网络侧的 DHCP Relay 已经指向 PXE 服务器。
后续我们计划在 UDS 的基础上增加:
- GPU 交付验收报告:装机完成后自动检查 GPU 拓扑、CUDA 版本、驱动状态,输出 HTML 报告。
- 批量巡检脚本:跨节点的配置一致性校验。
如何开始
项目已开源,核心代码只有约 700 行 Python。
gitclone https://gitee.com/path_fly/unified-deployment-system.gitcdunified-deployment-system python-mvenv .venvsource.venv/bin/activate pipinstall-rrequirements.txt# 编辑 conf/nodes.yaml,填入你的节点信息# 运行生成器python bin/uds.py\--output-res-dir /usr/share/nginx/html/res\--output-tftp-dir /var/lib/tftpboot\--server-ip YOUR_PXE_IP详见项目中的 QUICKSTART.md 获取完整操作指南,包括 Excel 工具的使用方法和多机型场景的进阶配置。
FAQ
Q: UDS 能管理装机后的节点状态吗?
A: 不能。UDS 只生成配置,不监控装机进度。装机完成后建议配合现有监控系统使用。
Q: 支持 Red Hat / CentOS 吗?
A: 目前只支持 Ubuntu Autoinstall。如果要支持 Kickstart,需要新增一套模板和渲染逻辑。
Q: 新机型上架需要改代码吗?
A: 不需要。只要新机型遵循 hostname 命名规范,在conf/profiles.yaml中新增一段网络拓扑定义即可。
Q: 为什么默认关闭network_unified_naming?
A: 显式优于隐式。如果你的 Profile 已经精确匹配了硬件网卡名称,不需要额外的 match 规则。只有在跨内核版本出现命名不一致时才建议开启。
相关阅读
- 上篇:PXE + Ubuntu Autoinstall 基础方案详解(DHCP / TFTP / Nginx 手动配置全流程)
