使用 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 工具,实现高效的数据与代码分离。如果您在使用过程中有任何问题或建议,欢迎随时交流。
超级会员免费看
18

被折叠的 条评论
为什么被折叠?



