- 运维
- DevOps
- IaC
【免费下载链接】puppet
Server automation framework and application
导读
本文以 Puppet 仓库中的 examples/hiera 完整示例为骨架,系统讲解 Hiera 5(hiera.yaml 版本 5)配合 YAML 数据后端的配置方法、层级(hierarchy)解析顺序、模块默认值、站点级覆盖与 Fact 驱动的节点差异化配置。读完本文后,你将能独立搭建一套"模块默认值 → 站点公共数据 → 按 Fact 分层的环境数据"的多层数据体系,并理解lookup()函数、data_hash提供者与 EPP 模板在其中的实际协作方式。
一、示例概览:一个可直接运行的 Hiera YAML Demo
examples/hiera目录是 Puppet 官方仓库中一个"可直接运行"的 Hiera + YAML backend 演示,它由四部分构成:
| 组成 | 位置 | 作用 |
|---|---|---|
| NTP 模块 | examples/hiera/modules/ntp | 通过默认参数管理/tmp/ntp.conf,默认使用pool.ntp.org服务器 |
| YAML 数据源 | examples/hiera/data | 站点级 YAML 数据,供用户在文件中覆盖模块默认值 |
| Users 模块 | examples/hiera/modules/users | 一组仅做notify的演示类,用于验证"哪些类被包含进 catalog" |
| classes 键 | 各 YAML 数据文件 | 用 Hiera 数据键classes决定节点上要 include 的类集合 |
整个示例的入口清单为:
examples/hiera/ ├── hiera.yaml # Hiera 5 配置:定义层级与数据目录 ├── site.pp # node default { include lookup('classes') } ├── data/ │ ├── common.yaml # 站点级公共数据 │ └── dc1.yaml # dc1 位置专用数据 └── modules/ ├── ntp/ # NTP 模块(含模块内 hiera.yaml 与 data/common.yaml) └── users/ # users::common / users::dc1 演示类所有示例均假设:已安装 puppet-agent、已克隆本仓库,并且以examples/hiera为当前工作目录(cwd)执行命令。
二、Hiera 5 配置解析:hierarchy 层级与 data_hash
2.1 站点级 hiera.yaml
examples/hiera/hiera.yaml 是站点级配置,采用 Hiera 5 格式:
--- version: 5 defaults: datadir: data data_hash: yaml_data hierarchy: - name: 'Per Location' path: "%{facts.location}.yaml" - name: 'Per Environment' path: "%{facts.environment}.yaml" - name: 'Common Data' path: 'common.yaml'关键点说明:
version: 5:声明使用 Hiera 5 配置格式,层级中的path支持插值(interpolation),这是 Hiera 5 相较旧版本的核心增强。defaults:为层级统一定义默认值。datadir: data表示数据文件目录相对当前配置文件的data/子目录;data_hash: yaml_data指定数据加载方式为 YAML。hierarchy顺序即查找顺序:Per Location → Per Environment → Common Data,自上而下,第一个命中数据的层级生效(first found wins)。
关于yaml_data:在 Puppet 源码中,它是注册在 lib/puppet/functions/yaml_data.rb 里的一个 Hiera 5data_hash数据提供者函数,与json_data、hocon_data等同属一类。其实现逻辑为:根据options中的path/paths/glob/globs/mapped_paths定位数据文件并解析为 Hash。若配置中未声明这些路径选项,函数会抛出"must be declared in hiera.yaml"的校验错误(见 yaml_data.rb 附近),因此示例中datadir+path的组合是必须的。
2.2 层级顺序的源码级印证
Hiera 配置的解析与层级遍历由lib/puppet/pops/lookup/目录下的源码支撑,例如 hiera_config.rb 负责读取并结构化 hiera.yaml,而层级查找遵循"第一个有数据的层级即返回"的语义。也就是说,层级越靠前,优先级越高。
在本文示例中,由于data/common.yaml已经声明了ntpservers键,查找ntp::config::ntpservers时 Per Location / Per Environment 层级若无数据,最终必然命中 Common Data 层级,模块类内默认值永远不会被搜索到(详见下文"查找顺序总结")。
三、模块默认值:从 Forge 式模块到本地 Hiera
3.1 NTP 模块内部的默认数据
NTP 模块遵循"模块自带默认数据"的现代 Puppet 实践。模块内同样有一份独立的 Hiera 配置 modules/ntp/hiera.yaml:
--- version: 5 defaults: datadir: data data_hash: yaml_data hierarchy: - name: 'Common Data' path: 'common.yaml'其数据文件 modules/ntp/data/common.yaml 定义了模块级默认值:
--- ntp::config::ntpservers: - '1.pool.ntp.org' - '2.pool.ntp.org'3.2 类与模板如何消费数据
modules/ntp/manifests/config.pp 定义了带参数的类:
class ntp::config( Array[String[1], 1] $ntpservers = undef, ) { file { '/tmp/ntp.conf': content => epp('ntp/ntp.conf.epp') } }参数类型约束为Array[String[1], 1](至少一个非空字符串组成的数组),默认值undef意味着如果 Hiera 中查不到ntp::config::ntpservers,类参数会保持 undef,而 EPP 模板 modules/ntp/templates/ntp.conf.epp 遍历该数组逐行生成server指令:
<% $ntp::config::ntpservers.each |$server| { -%> server <%= $server %> <% } -%>说明:该模板直接引用类参数
$ntp::config::ntpservers(类变量全局可见),因此只要 Hiera 提供了该键,/tmp/ntp.conf就会按数据渲染出对应服务器地址。
3.3 场景 A:只使用模块默认值
操作:注释掉 data/common.yaml 的第 6–8 行(即ntp::config::ntpservers声明),让站点级数据不再覆盖模块默认值:
$ sed -i '6,8 s/^/#/' data/common.yaml $ puppet apply site.pp --hiera_config=hiera.yaml --modulepath=modules预期输出(实际以你环境中的时间为准):
Notice: Compiled catalog for node.corp.com in environment production in 0.04 seconds Notice: Adding users::common Notice: /Stage[main]/Users::Common/Notify[Adding users::common]/message: defined 'message' as 'Adding users::common' Notice: /Stage[main]/Ntp::Config/File[/tmp/ntp.conf]/ensure: defined content as '{sha256}949c7247dbe0870258c921418cc8b270afcc57e1aa6f9d9933f306009ede60d0' Notice: Applied catalog in 0.02 seconds $ cat /tmp/ntp.conf server 1.pool.ntp.org server 2.pool.ntp.org结果验证:
/tmp/ntp.conf包含pool.ntp.org的两个地址(来自模块默认数据);users::common类出现在 catalog 中(来自common.yaml中的classes列表)。
关键认知:即便注释了站点级ntpservers,Hiera 查找仍会命中模块自带的data/common.yaml——这正是"模块默认值 + 站点覆盖"两层数据模型的落地。
四、站点级覆盖:data/common.yaml 的优先级
4.1 数据文件内容
data/common.yaml 是站点级公共数据,同时承担两类职责:
--- classes: - users::common - ntp::config ntp::config::ntpservers: - 'ntp1.example.com' - 'ntp2.example.com' lookup_options: classes: merge: uniqueclasses:由site.pp中include lookup('classes')消费,决定节点默认包含哪些类;ntp::config::ntpservers:站点级 NTP 服务器覆盖;lookup_options:声明classes键在跨层级合并时的策略为unique(取并集、去重),这正是下文 dc1 场景中users::common与users::dc1同时出现的原因。
4.2 场景 B:恢复覆盖,验证生效
操作:恢复common.yaml第 6–8 行的注释:
$ sed -i '6,8 s/^#//' data/common.yaml $ puppet apply site.pp --hiera_config=hiera.yaml --modulepath=modules预期输出:
Notice: Compiled catalog for node.corp.com in environment production in 0.04 seconds Notice: Adding users::common Notice: /Stage[main]/Users::Common/Notify[Adding users::common]/message: defined 'message' as 'Adding users::common' Notice: /Stage[main]/Ntp::Config/File[/tmp/ntp.conf]/content: content changed '{sha256}949c7247dbe0870258c921418cc8b270afcc57e1aa6f9d9933f306009ede60d0' to '{sha256}28ced955a8ed9efd7514b2364fe378ba645ab947f26e8c0b4d84e8368f1257a0' Notice: Applied catalog in 0.02 seconds $ cat /tmp/ntp.conf server ntp1.example.com server ntp2.example.com结果验证:
- 内容校验和由
949c72...变为28ced9...,/tmp/ntp.conf更新为ntp1.example.com/ntp2.example.com; - 站点级数据覆盖了模块默认值,但
users::common依然在 catalog 中。
这说明:模块默认值处于数据链最低优先级,站点common.yaml只要声明同名键即胜出(first found wins)。
五、Fact 驱动覆盖:按 location 分流节点数据
5.1 dc1 专属数据文件
data/dc1.yaml 针对location=dc1的节点提供两份覆盖:
--- ntp::config::ntpservers: - 'ntp1.dc1.example.com' - 'ntp2.dc1.example.com' classes: - users::dc1配合hiera.yaml的第一层path: "%{facts.location}.yaml",当节点的locationfact 为dc1时,dc1.yaml自动成为最高优先级数据源。
5.2 场景 C:dc1 节点
操作:通过环境变量FACTER_location=dc1注入 fact(无需修改任何 manifest):
$ FACTER_location=dc1 puppet apply site.pp --hiera_config=hiera.yaml --modulepath=modules预期输出:
Notice: Compiled catalog for node.corp.com in environment production in 0.04 seconds Notice: Adding users::dc1 Notice: /Stage[main]/Users::Dc1/Notify[Adding users::dc1]/message: defined 'message' as 'Adding users::dc1' Notice: Adding users::common Notice: /Stage[main]/Users::Common/Notify[Adding users::common]/message: defined 'message' as 'Adding users::common' Notice: /Stage[main]/Ntp::Config/File[/tmp/ntp.conf]/content: content changed '{sha256}28ced955a8ed9efd7514b2364fe378ba645ab947f26e8c0b4d84e8368f1257a0' to '{sha256}39227f1cf8d09623d2e66b6622af2e8db01ab26f77a5a2e6d6e058d0977f369b' Notice: Applied catalog in 0.02 seconds $ cat /tmp/ntp.conf server ntp1.dc1.example.com server ntp2.dc1.example.com结果验证,dc1 节点会获得:
- 类集合:
users::dc1+users::common同时出现。因为lookup_options.classes.merge: unique,两个数据层的classes列表被合并去重; - NTP 配置:
/tmp/ntp.conf更新为ntp1.dc1.example.com/ntp2.dc1.example.com。
5.3 场景 D:dc2 节点回退到站点默认
dc2没有专属数据文件,因此 Hiera 沿层级逐级下探,最终命中common.yaml:
$ FACTER_location=dc2 puppet apply site.pp --hiera_config=hiera.yaml --modulepath=modules预期输出:
Notice: Compiled catalog for node.corp.com in environment production in 0.04 seconds Notice: Adding users::common Notice: /Stage[main]/Users::Common/Notify[Adding users::common]/message: defined 'message' as 'Adding users::common' Notice: /Stage[main]/Ntp::Config/File[/tmp/ntp.conf]/content: content changed '{sha256}39227f1cf8d09623d2e66b6622af2e8db01ab26f77a5a2e6d6e058d0977f369b' to '{sha256}28ced955a8ed9efd7514b2364fe378ba645ab947f26e8c0b4d84e8368f1257a0' Notice: Applied catalog in 0.02 seconds $ cat /tmp/ntp.conf server ntp1.example.com server ntp2.example.com结果验证:
users::dc1不再出现(dc2.yaml 不存在,classes只来自 common.yaml);- NTP 配置回退为站点默认
ntp1.example.com/ntp2.example.com。
这就是典型的"少数节点特化、多数节点共享默认"的数据策略。
六、查找顺序总结:为 dc2 新建覆盖的三种位置
原文档明确指出:若要为location=dc2的机器创建覆盖数据,可以在以下位置放置文件,Hiera按此顺序搜索,第一个有数据的层级命中:
data/dc2.yaml—— 按位置(最高优先级)data/<environment>.yaml—— 按环境(如data/production.yaml)data/common.yaml—— 站点公共数据(兜底)
data/dc2.yaml # 1. Per Location data/<environment>.yaml # 2. Per Environment data/common.yaml # 3. Common Data(兜底)重要结论:在本示例中,由于common.yaml已经声明了ntpservers键,类内部的默认值永远不会被搜索到——层级查找会在命中common.yaml时立即返回,不会继续下探到模块数据。这解释了"模块默认值只在没有任何站点数据覆盖时才生效"这一 Hiera 5 的核心语义。
七、从示例到生产:可复用的实战要点
7.1 完整命令模板
在任何包含hiera.yaml的目录中,均可按以下形式运行示例:
puppet apply site.pp --hiera_config=hiera.yaml --modulepath=modules--hiera_config:显式指定 Hiera 配置文件(Hiera 5 格式);--modulepath:指定模块搜索路径,此处为示例内的modules/;FACTER_<fact>=<value>:通过环境变量临时注入 fact,用于模拟不同节点属性,无需修改节点事实库。
7.2 设计模式提炼
| 模式 | 实现方式 | 示例位置 |
|---|---|---|
| 模块自带默认值 | 模块内hiera.yaml+data/common.yaml | modules/ntp/data/common.yaml |
| 站点公共覆盖 | 站点级data/common.yaml声明同名键 | data/common.yaml |
| 按 Fact 分流 | hierarchy 中使用%{facts.location}.yaml等插值路径 | hiera.yaml |
| 按环境分流 | hierarchy 中使用%{facts.environment}.yaml | hiera.yaml |
| 键级合并策略 | lookup_options+merge: unique | data/common.yaml |
| 数据驱动类选择 | site.pp中include lookup('classes') | site.pp |
7.3 源码延伸阅读
若想深入 Hiera 5 的底层实现,可继续阅读:
- lib/puppet/functions/yaml_data.rb:
yaml_datadata_hash 提供者实现(YAML 文件加载与校验); - lib/puppet/pops/lookup/hiera_config.rb:Hiera 配置文件解析与层级结构建模;
- lib/puppet/pops/lookup/data_provider.rb:数据提供者抽象及
data_hash返回值校验(必须是 Hash)。
7.4 实践注意事项
- 层级顺序即优先级:
hierarchy中越靠前的层优先级越高,务必把最具体的层(如 location)放在最前面; - first found wins:任何一层命中键即停止查找,因此"兜底层"(common.yaml)永远放最后;
- 模块默认值是最后一道防线:只要站点任一层级声明了同名键,模块默认值即失效;
lookup_options是键级策略:它本身也参与层级查找,用于为classes这类聚合键声明unique合并,避免多层数据互相覆盖类列表;- fact 插值用
%{facts.xxx}语法:在 Hiera 5 的path中引用 fact 时使用该形式,查找时自动替换为节点实际值; - 环境变量注入 fact 仅用于演示:生产环境应依赖真实的 facter 事实或 ENC 提供的数据。
结语
examples/hiera用不足百行的配置、数据与模块,完整演示了 Puppet + Hiera 5 + YAML 后端从"模块默认值 → 站点公共数据 → Fact 驱动特化"的三层数据协作模型。它既是学习 Hiera 层级语义的最佳入门实验,也是生产环境中"按位置、按环境分层管理数据"的可复用样板。结合yaml_data与hiera_config等源码,你可以在自己的基础设施中快速复刻这套"少数特化、多数兜底"的数据分层体系。
- 运维
- DevOps
- IaC
【免费下载链接】puppet
Server automation framework and application
相关推荐
Audiobookshelf 服务端 OpenAPI 规范:基于 Redocly 的分层 YAML 管理与文档生成实战
Audiobookshelf 服务端 OpenAPI 规范:基于 Redocly 的分层 YAML 管理与文档生成实战 本指南围绕 docs/README.md
后端音视频前端NeMo Evaluator 配置深度解析:基于 Hydra 的分层覆盖系统与实战配置指南
NeMo Evaluator 配置深度解析:基于 Hydra 的分层覆盖系统与实战配置指南 本指南系统讲解 NeMo Evaluator(NVIDIA 企业级
AI 技能人工智能大模型深度学习ChatGPT Shortcut 浏览器扩展使用指南:三种显示模式、语言适配与 Alt+Shift+S 快捷键
ChatGPT Shortcut 浏览器扩展使用指南:三种显示模式、语言适配与 Alt+Shift+S 快捷键 ChatGPT Shortcut(AiShort
AI 应用提示工程人工智能前端
创作声明:本文部分内容由AI辅助生成(AIGC),仅供参考