ansbile实战应用系列教程7:管理facts
Ansible Facts
Ansiblefacts是Ansible在托管主机上自动发现的变量。fact包含特定于主机的信息,可以像在play、条件conditionals、循环loop或依赖于从托管主机收集的值的任何其他语句中使用常规变量一样。
facts代表主机信息,为托管主机收集的一些fact可能包括:
主机名、内核版本、网卡、ip信息、操作系统版本、不同的环境变量、CPUs数量、可用内存、可用磁盘。
fact是检索托管主机状态并根据该状态确定要采取什么操作的方便方法。例如:
l 服务器可以通过一个有条件的任务重新启动,这个任务是基于一个包含托管主机当前内核版本的事实运行的。
l MySQL配置文件可以定制,取决于可用内存报告的一个事实。
l 配置文件中使用的IPv4地址可以根据一个fact的值进行设置。
通常,每次play都会在第一个任务开始前自动运行setup模块,以Gathering Facts。这在Ansible 2.3中作为收集fact的任务报告,或者在Ansible早期版本中作为setup。你不需要在你的play中有一个任务来运行安装程序,它会自动为你运行。
ansible servera -m setup #setup模块用于收集主机信息
为了查看为托管主机收集了哪些fact,可以在这些主机上使用临时命令运行setup。在下面的例子中,一个ad hoc的命令被用来在托管主机demol.example.com上运行setup模块:
[student@taijitao-server ~]$ ansibleservera.lab.example.com -m setup
servera.lab.example.com | SUCCESS => {
"ansible_facts": {
"ansible_all_ipv4_addresses": [
"172.25.250.10"
],
"ansible_all_ipv6_addresses": [
"fe80::5054:ff:fe00:fa0a"
],
"ansible_apparmor": {
"status": "disabled"
},
"ansible_architecture": "x86_64",
"ansible_bios_date": "01/01/2011",
"ansible_bios_version": "0.5.1",
"ansible_cmdline": {
"BOOT_IMAGE": "/boot/vmlinuz-3.10.0-514.el7.x86_64",
"LANG": "en_US.UTF-8",
"console": "ttyS0,115200n8",
"crashkernel": "auto",
"net.ifnames": "0",
"no_timer_check": true,
"ro": true,
"root": "UUID=d85d7be1-03aa-433a-a847-030104cc3ce2"
},
ad hoc命令的输出是。以JSON格式返回变量的散列/字典。您可以浏览输出,查看收集了哪些fact,并在您的playbook中使用它们。
下表显示了一些可能从托管节点收集的fact,这些fact可能在playbook中有用:
facts | 2.5版本后的变量 | 2.3版本的变量 |
---|---|---|
短主机名 | ansible_facts[‘hostname’] | ansible_hostname |
完全限定域名 | ansible_fact[‘fqdn’] | ansible_fqdn |
主要IPv4(基于路由) | ansible_facts[‘default_ipv4’][‘address’] | ansible_default_ipv4.address |
所有网络接口的名称列表 | ansible_facts[‘interfaces’] | ansible_interfaces |
/dev/vdal 磁盘分区的大小 | ansible_facts[‘devices’][‘vda’][‘partitions’][‘vdal’]['size 1] | ansible_devices.vda.partitions.vda1.size |
DNS服务器列表 | ansible_facts[‘dns’][ ‘nameservers’] | ansible_dns.nameservers |
当前运行的内核的版本 | ansible_facts[‘kernel’] | ansible_kernel |
当在playbook中使用fact时,Ansible用相应的值动态地替换变量名:
---
- hosts: all
tasks:
-name: Print various Ansible facts
debug:
msg: >
The default IPv4 address of {{ ansible_fqdn }}
is {{ ansible_default_ipv4.address }}
下面的输出显示了Ansible如何查询托管节点并动态使用系统信息更新变量。此外,还可以使用fact创建匹配特定条件的动态主机组。
[student@taijitao-server dep-lab]$ansible-playbook setups.yaml
PLAY [ansible_facts] *****
TASK [Gathering Facts] *******
ok: [servera.lab.example.com]
TASK [print various ansible facts] *******
ok: [servera.lab.example.com] => {
"msg": "The default IPv4 address ofservera.lab.example.com is 172.25.250.10\n"
}
PLAY RECAP *******
servera.lab.example.com : ok=2 changed=0 unreachable=0 failed=0
关闭facts收集
有时候,你并不想为你的play收集fact。有几个原因可以解释为什么会这样。可能是您没有使用任何fact,并且希望加速play或减少托管主机上play所造成的负载。可能是托管主机由于某种原因不能运行setup模块,或者需要在收集fact之前安装一些必要的软件。
要禁用play的fact收集,请将gather_facts键设置为no:
---
- name:This playgathers no facts automatically
hosts: large_farm
gather_facts: no
即使为play设置了gather_facts: no,您也可以在任何时候通过运行使用setup模块的任务手动收集事实:
在tasks模块中开启收集facts
示例:
[student@taijitao-server demo_variablesplaybook]$ vim playbook.yml
---
- name: install package
hosts: all
gather_facts: no #**关闭主机信息的采集**
tasks:
- name: install the "{{package }}" package
yum:
name: "{{ package}}"
state: latest
- name: gather facts
setup: #**开启主机信息的采集**
- name: print variousAnsible facts
debug:
msg: >
The default IPv4address of {{ ansible_fqdn }}
is {{ansible_default_ipv4.address }}
过滤facts
有可能的facts包含了关于这个系统的大量信息。管理员可以使用Ansible filter来限制从托管节点收集facts时返回的结果。过滤器可用于:
仅检索有关网卡的信息。
仅检索关于磁盘的信息。
只检索用户信息。
要使用筛选器,需要使用-a ’ filter=expression '将表达式作为选项传递。例如,要仅返回关于eth0的信息,可以在ansible_eth0元素上应用筛选器:
[student@taijitao-server dep-lab]$ ansible-m setup servera.lab.example.com -a 'filter=ansible_eth0'
servera.lab.example.com | SUCCESS=> {
"ansible_facts": {
"ansible_eth0": {
"active": true,
"device":"eth0",
"ipv4": {
"address":"172.25.250.10",
"broadcast":"172.25.250.255",
"netmask":"255.255.255.0",
"network":"172.25.250.0"
},
"ipv6": [
{
"address":"fe80::5054:ff:fe00:fa0a",
"prefix":"64",
"scope":"link"
}
],
"macaddress": "52:54:00:00:fa:0a",
"module":"virtio_net",
"mtu": 1500,
"pciid":"virtio0",
"promisc": false,
"type": "ether"
}
},
"changed": false
}
注意,Ansible只返回Ansible_eth0散列/字典中的facts。
ansible servera -m setup -a'filter=ansible_default_ipv4'
ansible servera -m setup -a'filter=ansible_default_ip*'
*代表通配符
自定义Facts
管理员可以创建本地存储在每个托管主机上的自定义facts。这些facts被集成到安装程序在托管主机上运行时收集的标准facts列表中。这些允许托管主机提供任意变量给Ansible,可以用来调整play的行为。
定制facts可以在静态文件中定义,格式化为INI文件或使用JSON。它们也可以是生成JSON输出的可执行脚本,就像动态inventory脚本一样。
自定义facts允许管理员为托管主机定义某些值,这些托管主机可能用于填充配置文件或有条件地运行任务。动态自定义facts允许在playbook运行时以编程方式确定这些事实的值,甚至提供哪些facts。
默认情况下,setup从每个托管主机的/etc/ansible/facts.d目录中的文件和脚本加载自定义facts。每个文件或脚本的名称必须以.fact结尾才能使用。动态自定义facts脚本必须输出JSON:格式化的facts,并且必须是可执行的。
这是一个用INI格式编写的静态自定义facts文件的示例。一个INI格式的自定义facts文件包含一个由节定义的顶层,后面是要定义的facts的键-值对:
配置文件是ini的根式,与ansible.cfg格式一致,文件扩展名必须是.fact。
[root@servera ~]# mkdir -p /etc/ansible/facts.d/
[root@servera ~]# cd /etc/ansible/facts.d/
[root@servera facts.d]# vim custom.fact
[packages]
web_package = httpd
db_package = mariadb_server
[users]
user1 = joe
user2 = jane
同样的事实也可以以JSON格式提供。下面的JSON事实与前面示例中的INI指定的事实相同。JSON数据可以存储在一个静态文本文件或打印到标准输出由一个可执行脚本:
{
"packages": {
"web_package": "httpd",
"db_package": "mariadb-server"
},
"users": {
"userl": "joe",
"user2": "jane"
}
}
注意:自定义事实文件不能像剧本一样采用YAML格式。JSON格式是最接近的对等物。
自定义facts由setup程序存储在ansible_local[2.5版本以前]/ansible_facts.ansible_local[2.5版本后]变量中。facts根据定义它们的文件的名称进行组织。例如,假设上述自定义facts是由托管主机上保存为/etc/ansible/facts.d/custom.fact的文件生成的。在这种情况下,ansible_local[‘custom’][‘users’][‘user1’]或者ansible_facts.ansible_local[的值是joe。
通过使用一个ad hoc命令在托管主机上运行setup模块,可以检查自定义facts的结构
[student@taijitao-server demo_variablesplaybook]$ ansible -m setup servera-a 'filter=ansible_local'
servera | SUCCESS => {
"ansible_facts": {
"ansible_local": {
"custom":{ #fact的文件名
"packages": { #packages的组名
"db_package": "mariadb_server",
"web_package": "httpd"
},
"users": {
"user1": "joe",
"user2": "jane"
}
}
}
},
"changed": false
}
#通过以上的命令获取自定义facts的内容。
ansible_local:自定义fact内容。
在playbook中自定义facts可以使用与默认facts相同的方式。
为什么用自定义facts:
因为每个主机都承担不同的角色,每个主机都有特定的信息,可以通过自定义facts配置到目标主机上,
也可以使用host_vars group_vars实现自定义的功能。
magic variables
有些变量不是facts或配置通过setup模块,但由Ansible自动收集。这些 magic variables还可以用于获取特定于特定托管主机的信息。
即使您没有自己定义它们,Ansible会为您自动提供一些变量。其中最重要的是hostvars , group_names和groups 。
ansible servera -i inventory -m debug -a'var=hostvars'
其中四个最有用的是:
hostvars
包含用于托管主机的变量,可用于获取另一个托管主机的变量的值。它不会包括托管主机的事实,如果它们还没有为该主机收集。
group_names
列出当前托管主机所在的所有组。
groups
列出inventory中的所有组和主机。
inventory_hostname
包含在inventory中配置的当前托管主机的主机名。由于各种原因,这可能与facts报告的主机名不同。
还有其他一些“magic variables”。更多信息,请参见http://docs.ansible.com/ansible/playbooks_variables.html。了解它们值的一种方法是使用debug模块报告特定主机的hostvars变量的内容:
[user@demo ~]$ ansible localhost -m debug-a 'var=hostvars["localhost"]'
示例:
OpenShift部署过程中master节点判断。
tasks:
- name: Create/root/.ssh
file:
path: /root/.ssh
mode: 0700
owner: root
group: root
state:directory
when:inventory_hostname in groups['masters']
实战:
- 从taijitao-server,作为student用户,切换到~/dev- vars- facts目录。
[student@taijitao-server~]$ cd dev-vars-facts/
[student@taijitao-serverdev-vars-facts]$ ls
ansible.cfg inventory
[student@taijitao-serverdev-vars-facts]$ cat ansible.cfg
[defaults]
inventory = inventory
remote_user =devops
[privilege_escalation]
become = true
[student@taijitao-serverdev-vars-facts]$ cat inventory
[webserver]
servera.lab.example.com
- Ansiblesetup模块从系统中检索事实。运行ad hoc命令检索Webserver组中所有服务器的事实。输出将显示为servera.lab.example.com收集的所有事实,其格式为JSON格式。查看显示的一些变量。
[student@taijitao-serverdev-vars-facts]$ ansible webserver -m setup
servera.lab.example.com| SUCCESS => {
"ansible_facts": {
"ansible_all_ipv4_addresses":[
"172.25.250.10"
],
"ansible_all_ipv6_addresses":[
"fe80::5054:ff:fe00:fa0a"
……….
3.过滤与ansible_user表达式匹配的事实。附加一个通配符来匹配所有以ansible_user开头的事实。
[student@taijitao-serverdev-vars-facts]$ ansible webserver -m setup -a 'filter=ansible_user*'
servera.lab.example.com| SUCCESS => {
"ansible_facts": {
"ansible_user_dir":"/root",
"ansible_user_gecos":"root",
"ansible_user_gid": 0,
"ansible_user_id":"root",
"ansible_user_shell":"/bin/bash",
"ansible_user_uid": 0,
"ansible_userspace_architecture": "x86_64",
"ansible_userspace_bits":"64"
},
"changed": false
}
- 创建一个名为custom.fact的事实文件。事实文件定义要在servera上安装的包和要启动的服务。该文件应如下所示:
[student@taijitao-serverdev-vars-facts]$ cat custom.fact
[general]
package=httpd
service=httpd
state=started
- 创建setup_facts.yml剧本,创建/etc/ansible/facts.d远程目录,并将custom.fact文件保存到该目录中。
[student@taijitao-serverdev-vars-facts]$ cat setup_facts.yaml
---
- name:install remote fact
hosts: webserver
vars:
remote_dir: /etc/ansible/facts.d
facts_file: custom.fact
tasks:
- name: create the remote directory
file:
state: directory
mode: 0644
recurse: yes
path: "{{ remote_dir }}"
- name: copy the facts file to remotedirectory
copy:
dest: "{{ remote_dir }}"
src: "{{ facts_file }}"
- 使用setup模块运行ad hoc命令。由于用户定义的事实被放入ansible_local部分,所以使用筛选器只显示该部分。此时不应该有任何自定义事实。
[student@taijitao-serverdev-vars-facts]$ ansible webserver -m setup -a 'filter=ansible_local'
servera.lab.example.com| SUCCESS => {
"ansible_facts": {},
"changed": false
}
- 在运行剧本之前,验证它的语法是正确的运行ansible - playbook --syntax- check。如果它报告任何错误,请在进行下一步之前纠正它们。您应该会看到类似如下的输出:
[student@taijitao-serverdev-vars-facts]$ ansible-playbook setup_facts.yaml --syntax-check
playbook:setup_facts.yaml
- Run the setup_facts.yml playbook.
[student@taijitao-serverdev-vars-facts]$ ansible-playbook setup_facts.yaml
PLAY [installremote fact] ********************
TASK[Gathering Facts] ********************
ok:[servera.lab.example.com]
TASK [createthe remote directory] ****************
changed:[servera.lab.example.com]
TASK [copythe facts file to remote directory] ************
changed:[servera.lab.example.com]
PLAY RECAP************************
servera.lab.example.com : ok=3 changed=2 unreachable=0 failed=0
- 要确保新事实已正确安装,请再次使用setup模块运行ad hoc命令。只显示ansible_local部分。自定义事实应该出现。
[student@taijitao-serverdev-vars-facts]$ ansible webserver -m setup -a 'filter=ansible_local'
servera.lab.example.com| SUCCESS => {
"ansible_facts": {
"ansible_local": {
"custom": {
"general": {
"package":"httpd",
"service": "httpd",
"state":"started"
}
}
}
},
"changed": false
}
- 现在可以创建使用默认事实和用户事实来配置服务器的主剧本。在接下来的几个步骤中,您将添加到剧本文件。开始playbook.yml剧本文件与以下:
---
- name:install apache and start the service
hosts: webserver
- 继续编辑剧本。通过创建安装HTTPD包的第一个任务。使用事实自定义作为包的名称。
- name: install the required package
yum:
name: "{{ansible_local.custom.general.service}}"
state: latest
- 创建另一个使用自定义事实启动httpd服务的任务
- name: start the service
service:
name: "{{ansible_local.custom.general.service}}"
state: "{{ansible_local.custom.general.state }}"
- 完成所有任务后,完整的剧本应该如下所示。检查剧本,确保所有任务都有明确的定义。
---
- name:install apache and start the service
hosts: webserver
tasks:
- name: install the required package
yum:
name: "{{ansible_local.custom.general.service}}"
state: latest
- name: start the service
service:
name: "{{ansible_local.custom.general.service}}"
state: "{{ansible_local.custom.general.state }}"
- 在运行playbook之前,使用ad hoc命令来验证httpd服务当前没有在servera上运行。
[student@taijitao-serverdev-vars-facts]$ ansible webserver -m command -a 'systemctl status httpd'
- 执行ansible - playbook - - syntax - check检查剧本的语法。如果它报告任何错误,请在进行下一步之前纠正它们。您应该会看到类似如下的输出:
[student@taijitao-serverdev-vars-facts]$ ansible-playbook playbook.yaml--syntax-check
playbook:playbook.yaml
- 使用ansible- playbook命令运行playbook。观察输出,Ansible从安装包开始,然后启用服务。
[student@taijitao-serverdev-vars-facts]$ ansible-playbook playbook.yml
- 使用ad hoc命令执行systemctl检查httpd服务现在是否在servera上运行。
[student@taijitao-serverdev-vars-facts]$ ansible webserver -m command -a 'systemctl status httpd'
servera.lab.example.com| SUCCESS | rc=0 >>
●httpd.service - The Apache HTTP Server
Loaded: loaded(/usr/lib/systemd/system/httpd.service; enabled; vendor preset: disabled)
Active: active (running) since Fri2023-02-17 11:26:06 CST; 5h 52min ago
Docs: man:httpd(8)
man:apachectl(8)
Main PID: 855 (httpd)
Status: "Total requests: 0; Currentrequests/sec: 0; Current traffic: 0B/sec"
CGroup: /system.slice/httpd.service
├─855 /usr/sbin/httpd -DFOREGROUND
├─920 /usr/sbin/httpd -DFOREGROUND
├─921 /usr/sbin/httpd -DFOREGROUND
├─922 /usr/sbin/httpd -DFOREGROUND
├─923 /usr/sbin/httpd -DFOREGROUND
└─924 /usr/sbin/httpd -DFOREGROUND
Feb 1711:26:03 servera.lab.example.com systemd[1]: Starting The Apache HTTP Server...
Feb 1711:26:06 servera.lab.example.com systemd[1]: Started The Apache HTTP Server