16、使用 Hiera 分离数据与代码

使用 Hiera 分离数据与代码

1. 引言

在管理系统配置时,将数据与代码分离是一种良好的实践。它有助于保持代码的简洁性和可维护性,同时使配置数据的管理更加灵活。Hiera 就是这样一个工具,它可以帮助我们实现数据与代码的分离。

2. 处理哈希和数组

在 Hiera 中,检索数组和哈希与检索简单的字符串、数字或布尔值并无不同, hiera 函数可以返回所有这些类型的值,这些值可以直接在清单中使用。此外,还有两个特殊的函数: hiera_array hiera_hash

  • hiera_array 函数 :当调用 hiera_array 函数时,它会从整个层次结构中收集所有指定名称的值,并将它们合并成一个包含所有找到元素的长数组。例如,在分布式防火墙配置中,每个节点可以导出一个开放公共访问端口的规则列表:
if hiera('site::net::nat_ip', false) {
    @@firewall {
        "200 NAT ports for $fqdn":
            port        => hiera_array('site::net::nat_ports'),
            proto       => 'tcp',
            destination => hiera('site::net::nat_ip'),
            jump        => 'DNAT',
            todest      => $ipaddress,
    }
}

需要注意的是,在 if 语句中, site::net::nat_ip 键的默认值 false 看似不合理,但它形成了一个有用的模式:只有当为相应节点定义了 public_ip 时,才会导出该资源。如果键的值可能为 false 或空字符串,应使用明确定义的比较,例如:

if hiera('feature_flag_A', undef) != undef { … }

层次结构可以在多个层中保存端口:
- common.yaml

nat_ports: 22

所有获得公共地址的节点都应可以使用 SSH 端口。注意,这个值本身不是数组,Hiera 会将标量值包含在结果列表中。
- role - webserver.yaml

nat_ports: [ 80, 443 ]

独立的 Web 应用服务器向公众展示其 HTTP 和 HTTPS 端口。
- tbt - backend - test.example.net.yaml

nat_ports: 
  - 5973
  - 5974
  - 5975
  - 6630

新云服务的测试实例应公开一系列用于自定义服务的端口。如果它具有 Web 服务器角色,还会导出端口 22、80 和 443 以及其单独选择的列表。

在设计这样的结构时,要记住数组合并是累积的,无法从最终结果中排除在较低层添加的值。

  • hiera_hash 函数 hiera_hash 函数也会遍历整个层次结构,并通过合并在给定 Hiera 键下从所有层次结构层找到的所有哈希来构造一个哈希。较高层的哈希键会覆盖较低层的键。所有值必须是哈希,字符串、数组或其他数据类型在这种情况下是不允许的。例如:
  • common.yaml
haproxy_settings:
  log_socket: /dev/log
  log_level: info
  user: haproxy
  group: haproxy
  daemon: true

这是 haproxy 在最低层次结构级别的默认设置。
- role - webserver.yaml

haproxy_settings:
  user: www - data
  group: www - data

当使用 hiera('haproxy_settings') 检索时,它将计算为哈希 { 'user' => 'www - data', 'group' => 'www - data' } ,特定角色层的哈希完全覆盖了默认设置。要获取所有值,可以使用 hiera_hash('haproxy_settings') ,结果可能更有用:

{ 'log_socket' => '/dev/log', 'log_level' => 'info',
  'user' => 'www - data', 'group' => 'www - data', 'daemon' => true }

hiera_hash 的限制与 hiera_array 类似,任何层次结构级别的键都不能被删除,只能用不同的值覆盖。

3. 将资源转换为数据

可以将配置设置移动到 Hiera 中,让清单专注于逻辑。对于类及其参数,这可以无缝工作,因为类参数会自动从 Hiera 中检索其值。但对于需要实例化资源的配置,仍然需要编写完整的清单并添加手动查找函数调用。

例如,Apache Web 服务器需要一些全局设置,但其配置的有趣部分通常在虚拟主机配置文件中进行,Puppet 使用定义的资源类型来建模。如果要配置 iptables 防火墙,则必须声明大量 firewall 类型的资源。

Puppet 提供了 create_resources 函数,允许将整组这样的资源移动到 Hiera 数据中。模式很简单:一组相同类型的资源由一个哈希表示,键是资源标题,值是另一层包含属性键值对的哈希。例如:

services:
  apache2:
    enable: true
    ensure: running
  syslog - ng:
    enable: false

要使 Puppet 将这些作为实际资源添加到目录中,可以将哈希传递给 create_resources 函数:

create_resources('service', hiera('services', {}))

第一个参数是资源类型的名称,第二个参数必须是实际资源的哈希。创建的资源会遵循给定类型的资源默认值。此外,还可以传递一个包含默认参数名称和值的额外哈希作为 create_resources 的第三个参数,以保持资源哈希的紧凑性:

create_resources('file', hiera('synced_directories'),
    { ensure => 'directory', recurse => true, mode => 640 })

默认值可以为每个 YAML 资源节省两到三行代码。也可以将默认哈希包含在 Hiera 数据中,例如:

synced_directories_defaults:
  ensure: directory
  recurse: true
  mode: 640

另外, hiera_include('classes') 函数可以收集层次结构中所有的值,将结果数组解释为类名列表,并包含所有这些命名的类。例如:
- common.yaml

classes:
  - ssh
  - syslog
  • role - webserver.yaml
classes:
  - apache
  - logrotate
  - syslog

可以使用 hiera_include 在任何节点块之外声明这些类,数据将影响所有节点。

4. 选择清单和 Hiera 设计

虽然可以将大部分具体配置移动到数据存储中,但清单仍然是设计的核心支柱。清单通常需要使用配置数据作为输入的逻辑。例如:

if hiera('use_caching_proxy', false) {
    include nginx
}

如果仅依赖 Hiera,需要在层次结构中所有将 use_caching_proxy 标志设置为 true 的地方将 nginx 添加到 classes 数组中,这容易出错,并且该标志在更具体的层可能会从 true 覆盖为 false ,但 nginx 元素无法从 hiera_include 检索的数组中删除。

因此,清单和数据应该相互补充。主要构建清单,并在适当的地方添加查找函数调用。在 Hiera 中定义标志和值应该允许更改清单的行为,数据不应成为目录组成的驱动因素,除非用大型数据结构替换大量静态资源。

5. 在不同上下文中使用 Hiera

在设计配置或其他文件的模板时,可能需要从 Hiera 中获取一些数据。例如,在构建管理 SSH 服务器的个人模块时,可能希望允许节点为 AcceptEnv 选项指定一个环境变量列表。

在模板中直接使用 hiera 函数的简单实现不起作用,因为调用将指向 Ruby 中的 hiera 方法而不是 Puppet 函数。模板可以通过访问本地作用域属性来访问 Puppet 的解析器函数,方法是在解析器函数名称前添加 function_ 前缀:

<% vars = scope.function_hiera('ssh::server::env_vars', …) -%>
AcceptEnv = <%= vars * ' ' %>

在解析器函数中,也不能直接调用 hiera() 函数,解决方法是在函数体中添加 function_ 前缀:

data = function_hiera('key', 'default')

而类型、提供者和事实等由 Ruby 代码组成的部分,由于它们在编译期间不运行,因此无法访问存储在主服务器上的数据层次结构。

以下是一个使用 Hiera 的流程示意图:

graph LR
    A[定义 Hiera 层次结构] --> B[编写 Puppet 清单]
    B --> C[使用 hiera 函数查找数据]
    C --> D[应用配置]
    E[更新 Hiera 数据] --> C
6. 实际示例

为了完整说明,我们构建一个使用 Hiera 增强的模块示例。创建一个名为 demo 的模块:

# /etc/puppet/env/production/modules/demo/manifests/init.pp
class demo($auto = false,
           $syslog = true,
           $user = 'nobody') {
    file { '/usr/local/bin/demo': … }
    if $auto {
        cron { 'auto - demo':
            user    => $user,
            command => '/usr/local/bin/demo'
            ...
        }
        create_resources('demo::atom', hiera('demo::atoms', {}))
    }
}

这个类隐式查找三个 Hiera 键的参数:
- demo::auto
- demo::syslog
- demo::user
同时显式查找一个可选的 demo::atoms 哈希来为模块创建配置项。每个哈希必须符合定义的类型 demo::atom

# /etc/puppet/env/production/modules/demo/manifests/atom.pp
define demo::atom($address, $port = 14193) {
    file { "/etc/demo.d/$name":
        ensure  => 'file',
        content => "---\nhost: $address\nport: $port\n",
        mode    => '644',
        owner   => 'root',
        group    => 'root',
    }
}

common.yaml 中设置偏好:

demo::user: automation
demo::syslog: false

role - public_desktop.yaml 中设置替代值:

demo::user: maintenance

role - webserver.yaml 中设置 cron 作业:

demo::auto: true

int01 - web01.example.net.yaml 中设置例外:

demo::auto: false

common.yaml 中设置配置资源:

demo::atoms:
  self:
    address: localhost

role - kerberos.yaml 中设置 Kerberos 服务器:

demo::atoms: {}

role - dbms.yaml 中设置数据库服务器:

demo::atoms:
  self:
    address: localhost
  master:
    address: master.example.net
    port: 60119

site.pp 中包含 demo 类:

if hiera('enable_demo', true) {
    include demo
}
7. 调试 Hiera 查找

由于贡献到任何模块完整配置的数据可能分散在数据源集中,确定给定代理节点从何处检索相应值可能具有挑战性。为了使这个过程更透明,Hiera 提供了一个命令行工具 hiera

  • 检索给定键:
$ hiera -c /etc/puppet/hiera.yaml demo::atoms

确保使用与 Puppet 相同的 Hiera 配置。
- 提供所需事实:

$ hiera -c /etc/puppet/hiera.yaml demo::atoms \
    clientcert = int01 - web01.example.net role = webserver location = ny

添加 -d 标志以获取有关层次结构遍历的有用信息:

$ hiera -d -c ...
8. 总结

将具体配置数据从 Puppet 清单中剥离是明智的做法,这有助于巩固类并避免代码库混乱。Hiera 是一个以层次结构方式存储和检索数据的工具,主要通过 hiera 函数进行查找,数据通常以 YAML 或 JSON 表示。

使用 create_resources 函数可以将资源声明转换为哈希,从而清理包含大量静态资源的清单。 hiera_include 函数可以作为基本的外部节点分类器。在实际应用中,要合理选择清单和 Hiera 设计,使它们相互补充。通过调试工具 hiera 可以更方便地查找数据来源。

使用 Hiera 分离数据与代码

9. Hiera 工具的优势与价值

Hiera 工具在分离数据与代码方面带来了诸多显著的优势和价值,以下为您详细阐述:
- 提高代码可维护性 :将配置数据从代码中分离出来,使得代码更加简洁,易于理解和维护。当需要修改配置时,只需在 Hiera 数据文件中进行修改,而无需改动代码逻辑,减少了出错的可能性。
- 增强配置灵活性 :Hiera 的层次结构允许根据不同的环境、角色、节点等因素灵活配置数据。可以针对不同的场景设置不同的配置值,满足多样化的需求。
- 减少代码冗余 :通过在 Hiera 中统一管理配置数据,避免了在多个地方重复定义相同的配置,减少了代码的冗余度。
- 方便团队协作 :不同的团队成员可以分别负责代码开发和配置管理,提高工作效率,同时降低了因代码和配置混淆而导致的问题。

10. 常见问题及解决方案

在使用 Hiera 过程中,可能会遇到一些常见问题,以下为您提供相应的解决方案:
| 问题描述 | 解决方案 |
| — | — |
| 数据查找结果不符合预期 | 检查 Hiera 层次结构配置是否正确,确保数据文件路径和命名无误。使用 hiera -d 命令进行调试,查看数据查找的详细过程。 |
| 模板中无法正确调用 hiera 函数 | 在模板中使用 scope.function_hiera 方法调用,确保正确访问 Puppet 的解析器函数。 |
| 数据更新后未生效 | 检查 Puppet 代理是否正常运行,是否及时获取到最新的 Hiera 数据。可以尝试手动触发 Puppet 代理更新。 |

11. 最佳实践建议

为了更好地使用 Hiera 分离数据与代码,以下是一些最佳实践建议:
- 合理设计层次结构 :根据实际需求,合理划分 Hiera 层次结构,如按照环境、角色、节点等进行分层,确保数据的查找和管理更加清晰。
- 使用有意义的键名 :在 Hiera 数据文件中,使用有意义的键名,便于理解和维护。避免使用过于复杂或随意的键名。
- 定期清理和优化数据 :随着时间的推移,Hiera 数据文件可能会变得庞大和复杂。定期清理不再使用的数据,优化数据结构,提高查找效率。
- 进行充分的测试 :在修改 Hiera 数据或代码之前,进行充分的测试,确保修改不会影响系统的正常运行。可以使用测试环境进行验证。

12. 与其他工具的集成

Hiera 可以与其他工具进行集成,进一步提升系统的管理效率。以下是一些常见的集成场景:
- 与 Puppet 集成 :Hiera 是 Puppet 的重要组成部分,与 Puppet 紧密集成,为 Puppet 提供数据支持。通过在 Puppet 清单中使用 hiera 函数,可以方便地获取 Hiera 中的配置数据。
- 与 Foreman 集成 :Foreman 是一个开源的外部节点分类器,可以与 Hiera 结合使用。通过 Foreman 可以更直观地管理节点和配置数据,同时利用 Hiera 的层次结构进行数据存储和检索。
- 与 Git 集成 :将 Hiera 数据文件存储在 Git 仓库中,可以实现版本控制和团队协作。通过 Git 的分支和合并功能,可以方便地管理不同版本的配置数据。

以下是 Hiera 与其他工具集成的流程示意图:

graph LR
    A[Hiera] --> B[Puppet]
    A --> C[Foreman]
    A --> D[Git]
    B --> E[应用配置]
    C --> E
    D --> A
13. 未来发展趋势

随着技术的不断发展,Hiera 在数据管理和配置方面也将不断演进。以下是一些可能的未来发展趋势:
- 智能化配置管理 :借助人工智能和机器学习技术,实现智能化的配置管理。例如,根据系统的运行状态自动调整配置参数,提高系统的性能和稳定性。
- 与云原生技术的融合 :随着云原生技术的普及,Hiera 将与云原生技术如 Kubernetes 等进行更深入的融合。实现云环境下的高效配置管理和自动化部署。
- 增强的安全性 :在数据存储和传输过程中,加强安全性措施,如数据加密、访问控制等,确保配置数据的安全性和完整性。

14. 结论

通过使用 Hiera 工具分离数据与代码,我们可以提高代码的可维护性和配置的灵活性,减少代码冗余,方便团队协作。在实际应用中,要合理选择清单和 Hiera 设计,使它们相互补充。同时,要注意解决常见问题,遵循最佳实践建议,积极探索与其他工具的集成,以适应未来的发展趋势。

希望本文能够帮助您更好地理解和应用 Hiera 工具,实现高效的数据与代码分离。如果您在使用过程中有任何问题或建议,欢迎随时交流。

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值