☰
Puppet 实战:基于 Hiera 5 与 YAML 后端的层次化数据分层与 Fact 驱动覆盖
2026/9/27 9:39:01 网站建设 项目流程
  • 运维
  • DevOps
  • IaC

【免费下载链接】puppet

Server automation framework and application

项目地址:https://gitcode.com/gh_mirrors/pu/puppet
点击查看免费下载

导读

本文以 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: unique
  • classes:由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按此顺序搜索,第一个有数据的层级命中:

  1. data/dc2.yaml—— 按位置(最高优先级)
  2. data/<environment>.yaml—— 按环境(如data/production.yaml)
  3. 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.yamlmodules/ntp/data/common.yaml
站点公共覆盖站点级data/common.yaml声明同名键data/common.yaml
按 Fact 分流hierarchy 中使用%{facts.location}.yaml等插值路径hiera.yaml
按环境分流hierarchy 中使用%{facts.environment}.yamlhiera.yaml
键级合并策略lookup_options+merge: uniquedata/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 实践注意事项

  1. 层级顺序即优先级:hierarchy中越靠前的层优先级越高,务必把最具体的层(如 location)放在最前面;
  2. first found wins:任何一层命中键即停止查找,因此"兜底层"(common.yaml)永远放最后;
  3. 模块默认值是最后一道防线:只要站点任一层级声明了同名键,模块默认值即失效;
  4. lookup_options是键级策略:它本身也参与层级查找,用于为classes这类聚合键声明unique合并,避免多层数据互相覆盖类列表;
  5. fact 插值用%{facts.xxx}语法:在 Hiera 5 的path中引用 fact 时使用该形式,查找时自动替换为节点实际值;
  6. 环境变量注入 fact 仅用于演示:生产环境应依赖真实的 facter 事实或 ENC 提供的数据。

结语

examples/hiera用不足百行的配置、数据与模块,完整演示了 Puppet + Hiera 5 + YAML 后端从"模块默认值 → 站点公共数据 → Fact 驱动特化"的三层数据协作模型。它既是学习 Hiera 层级语义的最佳入门实验,也是生产环境中"按位置、按环境分层管理数据"的可复用样板。结合yaml_data与hiera_config等源码,你可以在自己的基础设施中快速复刻这套"少数特化、多数兜底"的数据分层体系。

  • 运维
  • DevOps
  • IaC

【免费下载链接】puppet

Server automation framework and application

项目地址:https://gitcode.com/gh_mirrors/pu/puppet
点击查看免费下载

相关推荐

上一篇:blendergltf 插件全场景解决方案:从环境配置到引擎兼容优化
下一篇:5步掌握Counterfeit-V3.0:AI图像生成从入门到精通

创作声明:本文部分内容由AI辅助生成(AIGC),仅供参考

需要专业的网站建设服务?

联系我们获取免费的网站建设咨询和方案报价,让我们帮助您实现业务目标

立即咨询