为什么使用Hiera?
Puppet中的manifest同时包含静态的代码(判断/循环逻辑,依赖关系,类定义,资源类型定义等等)和动态的数据(类声明时的参数值和资源声明时的属性值)。说代码是静态的是因为如果在设计阶段考虑比较全面,代码写成之后是很少变化的。但是数据要根据具体情况赋予不同的值。如果manifest设计的不是很灵活,比如某些数据被固化(hardcode)在文件中时,manifest就很难适用于新的场景,重用性就变差了。此外,为了追加/更新数据经常修改manifest也增加了出错的几率。
Puppet的解决方案是将动态的数据从manifest中剥离出来,这样manifest中只需留下代码,不必经常改动。
一种方式是我们要尽量使用Forge上的模块,或者将我们的manifest按同样方式设计,也就是将manifest内的资源的所有属性都通过类参数的形式暴露给用户,这样用户就可以通过传递不同的参数值来自由控制资源的最终状态。
另一种方式就是使用Hiera,也就是将manifest要使用的数据存储在外部的文件中,根据实际情况赋值。在编译catalog时,manifest向Hiera动态查询所需值的具体内容,然后加载到catalog中。
Hiera是如何存储数据的?
Hiera将数据以键/值对的方式存储在外部文件中。查询时,将键传给Hiera,然后Hiera返回对应值。
存储键/值对的文件被称作数据源(data source)文件。数据源文件可以是yaml或json格式,也可以自定义格式。下面是一个yaml格式的数据源的例子。每一行都是一个键/值对,值可以是数字,字符串,布尔值,数组或者hash,也支持数组和hash的嵌套。
# 值是数字
process_count: 10
# 值是字符串
apache-service: apache2
# 值是布尔
root_allowed: no
# 值是数组
apache-packages:
– apache2
– apache2-common
– apache2-utils
# 值是hash
sshd_settings:
root_allowed: "no"
password_allowed: "yes"
# hash的另外一种写法
sshd_settings: {root_allowed: "no", password_allowed: "yes"}
json格式的数据源和其他细节请看这里
Hiera是如何组织数据源文件的?
Hiera的一个核心理念是重用数据,具体体现为对数据源文件的层次化分类管理(Hierarchy)
层次1: 所有节点通用的数据定义在一个公共数据源文件中,且只需定义一次
层次2: 对节点分类(主要是依据facts)。一类节点的通用数据定义在一个公共数据源文件中,且只需定义与上面一层不同的部分
层次3: 对每一个节点进行配置,每个节点一个数据源文件,且只需定义与上面几层不同的数据
数据源的配置被定义在Hiera的主配置文件(hiera.conf)中。下面是一个配置文件的例子。更多hiera.conf细节请看这里
:backends: #支持的数据源文件格式,默认是yaml和json
– yaml #查找yaml格式数据源文件
– json #查找json格式数据源文件
:yaml: #yaml格式数据源文件的根目录
:datadir: "/etc/puppet/environments/%{::environment}/hieradata" #%{::environment}是指facts中的environment变量。这行定义是说yaml格式的数据源文件的根目录是"/etc/puppet/environments/%{::environment}/hieradata"
:json: #json格式数据源文件的根目录
:datadir: "/etc/puppet/environments/%{::environment}/hieradata"
:hierarchy: #分类和层次关系(hierarchy)
– "nodes/%{::fqdn}" #%{::fqdn}是指facts中的fqdn变量。按fqdn分类的数据源文件存在$datadir/nodes目录下,文件以agent节点的fqdn命名
– "virtual/%{::virtual}" #%{::virtual}是指facts中的virtual变量。按virtual值分类的数据源文件存在$datadir/virtual目录下,文件以virtual值命名
– "common" #所有节点的默认配置都存在common.yaml或者common.json中
注意:如果修改了hiera.conf的内容,Puppet master进程必须重启才能生效
如果我的production环境中,server1和server2都是运行在xen上,而server3和server4都是在vmware上,那么根据上面的配置文件,我的数据源文件目录结构就很可能是这个样子
/etc/puppet/environments/production/hieradata
├── common.yaml #所有节点的通用配置
├── nodes #以fqdn分类的每个节点的配置
│ ├── server1.yaml #server1的配置
│ ├── server2.yaml #server2的配置
│ ├── server3.yaml #server3的配置
│ └── server4.yaml #server4的配置
└── virtual #以virtual分类的通用配置
├── xen.yaml #所有xen虚拟机的通用配置
└── vmware.yaml #所有vmware虚拟机的通用配置
对于server1 (xen虚拟机)来说,它的最终配置会是server1.yaml, xen.yaml 和common.yaml 中配置的组合。
如何从Hiera查询数据?
Hiera支持几种查询方式
1. 自动参数查询(automatic parameter lookup)
这种方式主要用于查询类的参数。
当Hiera配置好后,在manifest中声明类但不给指定参数赋值,比如使用include-like方式(无类参数),或者使用resource-like方式但不显性的给参数赋值,这两种情况下,Puppet都会自动使用<类名>::<参数名>作为键通过Hiera查询相应的参数值。详细信息请看这里
注意: * 不要在template中使用自动参数查询。
* 如果想禁止这个功能,在master的puppet.conf设置data_binding_terminus = none
2. 使用Hiera内置函数或Hiera命令查询
数据类型 | Hiera内置函数 | Hiera命令 |
任何数据类型 | hiera(<键>) | hiera <键> |
数组 | hiera_array(<键>) | hiera -a <键> |
Hash | hiera_hash(<键>) | hiera -h <键> |
注意: * Hiera内置函数可以在任意的manifest文件中调用或者在puppet apply -e中命令调用。
* Hiera命令在Hiera安装好后,就可以从shell中使用。
3. 使用Hiera内置函数hiera_include
hiera_include()专门用来在site.pp中查询哪些类分配给了指定节点,等同于在节点定义中使用include-like/resource-like来声明类,可以作为ENC的一个替代方案。
Hiera查询是如何工作的?
查询时,Hiera会按:hierarchy:下面定义的顺序遍历datadir子目录下的数据源文件,寻找匹配的键。
:hierarchy:
– "nodes/%{::fqdn}"
– "virtual/%{::virtual}"
– "common"
如果:hierarchy:的定义是上面这样的,查询的顺序就是datadir下的nodes/%{::fqdn}子目录,然后是virtual/%{::virtual}子目录,最后是common.yaml文件。
如果你是使用以下的查询方式,那么在找到第一个匹配的键之后Hiera就返回了,不在继续查找
* 自动参数查询(automatic parameter lookup)
* Hiera内置的hiera函数
* hiera命令(没有-a或-h)
如果你是使用以下的查询方式,那么Hiera会认为你在查找一个数组,它会遍历所有的数据源文件,然后将所匹配的所有数组值合并到一个数组中返回
* Hiera内置的hiera_array函数
* Hiera内置的hiera_include函数
* hiera -a 命令
如果你是使用以下的查询方式,那么Hiera会认为你在查找一个hash,它会遍历所有的数据源文件,然后将所匹配的所有内容值合并到一个hash中返回。
* Hiera内置的hiera_hash函数
* hiera -h 命令
注意:如果这个hash又嵌套了其他的hash或者数组,且某个键在不同的数据源文件中被赋予了不同的hash或者数组,默认情况下,Hiera只会保留第一个匹配到的嵌套hash或者数组。如果你希望在这种情况下执行合并操作,请看这里
Hiera使用示例
我们通过一个例子来展示如何使用Hiera.
1. 演示环境
节点名 | OS系统 | Puppet组件 |
master-host | CentOs7 | Puppet 3.8开源版master, |
agent-centos | CentOs6 | Puppet 3.8开源版agent和facter |
agent-ubuntu | Ubuntu14 | Puppet 3.8开源版agent和facter |
2. 实验目标
* 所有agent节点的标准配置是安装ntp,使用节点系统自带的ntp设置,并启动ntp服务
* 在且只在所有RedHat家族Linux上安装nginx,使用默认设置,并启动nginx服务(当前RedHat家族Linux上没有nginx)
* 在agent-centos节点上停止ntp服务
* 在agent-ubuntu节点上使用外部ntp源0.au.pool.ntp.org和1.au.pool.ntp.org(当前agent-ubuntu节点上没有ntp)
3. 安装所需模块
在这个演示中,会用到ntp和nginx模块(负责安装,配置并管理相关服务)。简单起见,我们从Forge上下载并安装相关模块到master-host上。当然,你也可以使用自己写的模块。
puppet module install puppetlabs-ntp #安装ntp模块
puppet module install jfryman-nginx #安装nginx模块
后面我们会用到puppetlabs-ntp模块中ntp类的两个参数,$::ntp::service_ensure和$::ntp::servers。如果你想了解其他参数的用途,可以查看模块的init.pp(/etc/puppet/modules/ntp/manifests/init.pp)
4. 安装Hiera
一般在安装puppetserver的过程中,Hiera会被自动安装。如果你的master上没有Hiera软件包,请看这里了解安装过程。
5. 配置
a. Hiera主配置文件(/etc/puppet/hiera.yaml)
:backends:
– yaml #告诉Hiera只查找yaml格式的数据源文件
:yaml:
:datadir: "/etc/puppet/hieradata" #yaml格式的数据源文件的根目录是/etc/puppet/hieradata
:hierarchy: #定义数据源的分类和层次。
– "nodes/%{::fqdn}" #按fqdn分类命名数据源文件并保存在/etc/puppet/hieradata/nodes目录下,比如agent-centos节点的文件名就是agent-centos.yaml
– "osfamily/%{::osfamily}" #在/etc/puppet/hieradata/osfamily目录下含有为以osfamily分类的数据源文件,例如RedHat家族Linux的数据源文件就是RedHat.yaml
– common #所有节点通用的默认配置
b. 配置site.pp
node "agent-centos","agent-ubuntu" { #节点定义
hiera_include('classes') #调用hiera_include函数向Hiera查询classes键值所对应的数组内容。这个键可以是其他名字,只要在数据源文件中保持名字一致就可以
}
b. 配置所有节点的默认配置(/etc/puppet/hieradata/common.yaml)
classes: #所有节点默认都调用ntp类。
– ntp
ntp::service_ensure: running #ntp::service_ensure是puppetlabs-ntp模块中,ntp类的service_ensure参数,是指服务的运行状态(也就是service资源中的ensure属性)这里给他赋值为 running
上面定义是说每个节点默认都要安装ntp数据包,使用默认ntp配置并启动服务
c. 配置agent-centos节点(/etc/puppet/hieradata/nodes/agent-centos.yaml)
ntp::service_ensure: stopped #停止ntp服务
d. 配置agent-ubuntu节点(/etc/puppet/hieradata/nodes/agent-ubuntu.yaml)
ntp::servers: #ntp::service_ensure是puppetlabs-ntp模块中ntp类的参数,用来指定ntp源。
– 0.au.pool.ntp.org #第一个ntp源是0.au.pool.ntp.org
– 1.au.pool.ntp.org #第二个ntp源是1.au.pool.ntp.org
做了以上配置后,agent-ubuntu节点会使用0.au.pool.ntp.org和1.au.pool.ntp.org作为ntp源。
e. 配置RedHat家族Linux(/etc/puppet/hieradata/osfamily/RedHat.yaml)
classes: #配置所有RedHat家族Linux都调用nginx类
– nginx
经过以上的配置,agent-centos的节点定义将会是agent-centos.yaml,RedHat.yaml和common.yaml整合后的内容,等同于以下设置。
node "agent-centos" { #agent-centos节点定义
class { "ntp": #声明ntp类,来自common.yaml
service_ensure => "stopped", #停止ntp服务。高优先级的agent-centos.yaml覆盖了低优先级的common.yaml中的设置
}
include nginx #声明nginx类,来自于RedHat.yaml
}
而agent-ubuntu的节点定义是agent-ubuntu.yaml和common.yaml的内容整合后的结果,相当于下面的配置
node "agent-ubuntu" { #agent-ubuntu节点定义
class { "ntp": #声明ntp类,来自common.yaml
service_ensure => "running", #运行ntp服务,来自common.yaml
servers=> ["0.au.pool.ntp.org", "1.au.pool.ntp.org"],#设置ntp源,来自于agent-ubuntu.yaml
}
}
6. 检查配置
在应用前,可以使用hiera命令或者puppet apply命令来检查配置结果是否正确。
a. 用hiera命令
如果想检查agent-centos6(osfamily的值是RedHat)和agent-ubuntu(osfamily的值是Debian)上所分配的classes是哪些,可以使用下面的命令
[root@master-host~]hiera -a 'classes' '::osfamily=RedHat' '::fqdn=agent-centos' -c /etc/puppet/hiera.yaml
["ntp","nginx"]
[root@master-host~]hiera -a 'classes' '::osfamily=Debian' '::fqdn=agent-ubuntu' -c /etc/puppet/hiera.yaml
["ntp"]
在上面命令中,-a说明被查询的classes是一个数组,如果它在不同数据源文件中都有定义,要求Hiera整合匹配的结果。如果不写-a,Hiera在找到第一个匹配classes的内容时就会立即返回。
此外,'::osfamily=RedHat'和 '::fqdn=agent-centos6'是来告诉Hiera使用传入的facts值,如果没有指定,Hiera会使用当前系统的facts值。
b. 用puppet apply命令
上面的检查也可以用puppet apply来执行
[root@master-host~]FACTER_fqdn=agent-centos FACTER_osfamily=RedHat puppet apply -e "notice(hiera_array('classes'))"
Notice: Scope(Class[main]): nginx ntp
Notice: Compiled catalog for master-centos6 in environment production in 0.05 seconds
Info: Applying configuration version '1467801050'
Notice: Finished catalog run in 0.11 seconds
[root@master-host~]FACTER_fqdn=agent-ubuntu FACTER_osfamily=Debian puppet apply -e "notice(hiera_array('classes'))"
Notice: Scope(Class[main]): ntp
Notice: Compiled catalog for master-centos6 in environment production in 0.05 seconds
Info: Applying configuration version '1467801027'
Notice: Finished catalog run in 0.14 seconds
上面命令中使用的FACTER_fqdn和FACTER_osfamily都是告诉puppet使用指定的fqdn和osfamily值。此外,hiera_array用来说明classes是一个数组,Hiera会将所有匹配结果整合后再返回。
7. 运行并检查结果
在agent节点上启动agent进程
puppet agent -v –no-daemonize
在agent将catalog应用完成后,检查agent-centos节点
[root@agent-centos~]# service ntpd status
ntpd is stopped #ntp服务被停止了
[root@agent-centos~]# rpm -qa | grep nginx
nginx-1.10.1-1.el6.ngx.i386 #nginx安装包已安装
[root@agent-centos~]service nginx status
nginx (pid 4531) is running… #nginx服务已运行
检查agent-ubuntu节点
root@agent-ubuntu:~# dpkg -l ntp #ntp包已安装
||/ Name Version Architecture Description
+++-==============-============-============-=================================
ii ntp 1:4.2.6.p5+d i386 Network Time Protocol daemon and
root@agent-ubuntu:~# service ntp status
* NTP server is running #ntp服务已运行
root@agent-ubuntu:~# grep server /etc/ntp.conf #ntp.conf中的ntp源与预期相符
server 0.au.pool.ntp.org iburst
server 1.au.pool.ntp.org iburst
原创文章,作者:MVP,如若转载,请注明出处:http://www.178linux.com/22350