收集节点信息
ansible可以获取目标主机的节点信息,如ip地址,主机名、系统版本、内核版本等等,对于运维来说是一个很好的功能,但是正是它收集的信息很全面,运行也很慢,在日常工作中,没有特殊的需求会在playbook中将其关闭,或者开启facts缓存,在运行任务前手动执行一次。
ansible中提供了两个模块(setup
与gather_facts
)来实现收集主机facts,其中setup是最早的模块,gather_facts是基于setup二次开发的模块(2.8版本以上),gather_facts相比setup多了个并行收集facts的功能(自动识别)。
在playbook中可以通过gather_facts: BOOL
,来控制是否收集节点facts,默认是true,在开始执行定义好的任务前会先执行gather_facts.
访问节点信息
收集到目标节点信息之后,各信息都保存在一个名为ansible_facts的变量中,如下:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44
| "ansible_facts": { "ansible_all_ipv4_addresses": [ "192.168.100.10" ], "ansible_all_ipv6_addresses": [ "fe80::8199:4454:db1e:911c" ], "ansible_apparmor": { "status": "disabled" }, "ansible_architecture": "x86_64", "ansible_bios_date": "07/22/2020", "ansible_bios_version": "6.00", "ansible_cmdline": { ... }, "ansible_date_time": { ... }, "ansible_default_ipv4": { "address": "192.168.100.10", "alias": "ens33", "broadcast": "192.168.100.255", "gateway": "192.168.100.2", "interface": "ens33", "macaddress": "00:0c:29:ec:61:46", "mtu": 1500, "netmask": "255.255.255.0", "network": "192.168.100.0", "type": "ether" }, "ansible_distribution": "CentOS", "ansible_distribution_file_parsed": true, "ansible_distribution_file_path": "/etc/redhat-release", "ansible_distribution_file_variety": "RedHat", "ansible_distribution_major_version": "7", "ansible_distribution_release": "Core", "ansible_distribution_version": "7.6", "ansible_dns": { "nameservers": [ "114.114.114.114" ] }, ...
|
有了这些信息,就可以去访问这些信息。比较常用有获取目标主机名,系统版本号、ip地址:
1 2 3 4 5 6
| - debug: var: ansible_hostname - debug: var: ansible_distribution_version - debug: var: ansible_all_ipv4_addresses
|
获取到所需的信息可以添加一些判断的逻辑:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27
| --- - hosts: test gather_facts: true tasks: - name: template and copy centos6 yum repo template: src: centos6.repo.j2 dest: /tmp/centos6.repo when: ansible_distribution == "CentOS" and ansible_distribution_major_version == "6"
- name: template and copy centos7 yum repo template: src: centos7.repo.j2 dest: /tmp/centos7.repo when: ansible_distribution == "CentOS" and ansible_distribution_major_version == "7" ---
--- - hosts: test gather_facts: true tasks: - name: template and copy yum repo template: src: "{{'centos6.repo.j2' if (ansible_distribution_major_version == 6) else 'centos7.repo.j2'}}" dest: /tmp/centos.repo when: ansible_distribution == 'CentOS'
|
local fact
Ansible除了远程收集目标节点的Facts信息,还允许用户在目标节点上自定义该节点的Facts信息,这种方式收集到的Facts称为local Facts。
要自定义local Facts,需要在目标节点的/etc/ansible/facts.d/目录下创建以.fact
为后缀的文件,并在该文件中定义Facts变量信息。该文件要求是json、ini格式或能够输出json、ini数据格式的可执行文件,比如shell脚本。也可以更改默认的local fact目录,在play关键字中指定就好。
如下示例:
在第一台目标节点编写local fact如下
1 2 3 4 5 6
| [root@slions_pc1 facts.d]# ls myfact.fact [root@slions_pc1 facts.d]# cat myfact.fact [model] pc=del_G3 [root@slions_pc1 facts.d]# pwd
|
在第二台目标节点编写local fact如下
1 2 3 4 5 6 7
| [root@slions_pc2 facts.d]# ls myfact.fact [root@slions_pc2 facts.d]# pwd /home/ansible_poc/facts.d [root@slions_pc2 facts.d]# cat myfact.fact [model] pc=macbook x1
|
playbook如下
1 2 3 4 5 6 7
| - hosts: test fact_path: /home/ansible_poc/facts.d/ tasks: - debug: var: ansible_facts.ansible_local.myfact.model.pc
|
运行后可以看到能正常访问到自定义的本地fact。
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17
| PLAY [test] **************************************************************************************************
TASK [Gathering Facts] *************************************************************************************** ok: [192.168.100.11] ok: [192.168.100.10]
TASK [debug] ************************************************************************************************* ok: [192.168.100.10] => { "ansible_facts.ansible_local.myfact.model.pc": "del_G3" } ok: [192.168.100.11] => { "ansible_facts.ansible_local.myfact.model.pc": "macbook x1" }
PLAY RECAP *************************************************************************************************** 192.168.100.10 : ok=2 changed=0 unreachable=0 failed=0 skipped=0 rescued=0 ignored=0 192.168.100.11 : ok=2 changed=0 unreachable=0 failed=0 skipped=0 rescued=0 ignored=0
|
使用Local Facts并不方便,这需要单独去目标节点创建/home/ansible_poc/facts.d/目录,还要将写好的.fact文件拷贝过去,然后在下一个play中使用(如果在当前play中使用,需要先手动调用setup模块收集信息再使用)。
换句话说,使用Local Facts的一般流程可能是这样的:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24
| --- - name: play1 hosts: test gather_facts: false tasks: - block: - name: mkdir /home/ansible_poc/facts.d file: name: /home/ansible_poc/facts.d state: directory - name: copy a.fact copy: src: myfact.fact dest: /home/ansible_poc/facts.d when: inventory_hostname == "192.168.100.10"
- name: play2 use local facts hosts: test gather_facts: true tasks: - debug: var: ansible_local.myfact.model.pc when: inventory_hostname == "192.168.100.10"
|
虽然local Facts不太方便,但它支持可执行文件的方式。用户可以直接写一个可执行文件来动态生成Facts信息而不是预先以静态的方式写好的Facts变量。
例如,想要收集mysql galera集群中节点的状态,编写如下可执行Facts文件:
1 2 3 4
| #!/bin/bash
echo '[cluster_status]' mysql -e "SHOW GLOBAL STATUS LIKE 'wsrep_cluster_status'\G" | awk '/Value/{print "status="$2}'
|
之后便可以在playbook中使用ansible_local.FACT_FILENAME.cluster_status.status
来访问对应节点的状态。
set_fact模块
Facts的各种信息实际上是以变量方式保存的。
我们还可以在任务中通过set_fact
模块直接定义Facts,其效果就是定义了一个变量,和register
指令的功能类似,只不过register
指令是将模块的执行返回值赋值给变量名,而set_fact
是手动指定变量的值。
示例:
1 2 3 4 5 6 7 8 9 10 11
| - hosts: localhost gather_facts: false tasks: - name: define some var set_fact: name: slions age: 29
- name: use var debug: msg: "name: {{name}}, age: {{age}}"
|
set_fact经常用于临时设置变量,也非常方便,比如可以在将shell执行结果通过register注册变量之后,立即使用set_fact将命令的标准输出定义成变量。如下:
1 2 3 4 5 6 7 8 9 10 11
| - hosts: localhost gather_facts: false tasks: - shell: | echo 183@163.com register: echo_res - set_fact: echo_var={{echo_res.stdout}}
- name: use var debug: var: echo_var
|
facts缓存
收集fact是耗时的,ansible支持fact缓存,通过设置Ansible配置文件,然后就可以在任何时间点通过一个独立的收集任务去收集,并将收集的Facts缓存下来,以后使用Facts变量时就不用再显式地低效收集。
配置Ansible开启Facts缓存的方式非常简单,修改Ansible配置文件(默认是/etc/ansible/ansible.cfg
或其它位置)。目前Ansible支持以下几种缓存模式:
- redis:缓存在redis服务中,直到目前(Ansible 2.9)为止,Ansible还不支持指定连接redis的端口、密码等
- memcached:缓存在memcache文件中
- mongodb:缓存在mongodb文件中
- jsonfile:缓存在本地的json文件中
- yaml:缓存在本地的yaml文件中
- pickle:缓存在本地的pickle序列化文件中
配置方式,可参考如下配置项:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16
| gathering = smart或explicit或implicit fact_caching = jsonfile fact_caching_connection = DIRNAME fact_caching_timeout=TIMEOUT
gathering = smart或explicit或implicit fact_caching = redis fact_caching_timeout=TIMEOUT fact_caching_connection = localhost:6379:0
fact_caching = mongodb fact_caching_timeout = 60 fact_caching_connection = mongodb://localhost:32770/ansible_cache
|
配置项解析:
gathering:控制Ansible是否自动收集Facts,它有三种值:
- implicit:这是默认值,表示执行play时会自动收集Facts,除非显式指定gather_facts: false禁止收集
- explicit:不自动收集Facts,除非显式指定gather_facts: true开启收集
- smart:自动收集Facts,但如果已存在(缓存)则不重复收集
fact_caching_connection:指定本地目录用于存放Facts的缓存文件,如果目录不存在则Ansible会尝试创建
fact_caching_timeout:缓存的有效时长
当前工作中我们使用的jsonfile配置如下:
1 2 3
| gathering = smart fact_caching = jsonfile fact_caching_connection = facts
|
当第一次执行playbook后,会将收集到的内容缓存到当前目录下的facts目录下:
1 2 3 4 5
| [root@slions_pc1 ansible_poc]# ll facts 总用量 48 -rw-r--r--. 1 root root 22845 12月 1 15:06 192.168.100.10 -rw-r--r--. 1 root root 23039 12月 1 15:06 192.168.100.11
|
之后便可以直接去引用这些缓存下来的Facts信息,甚至访问不在该play中的节点的Facts信息。例如,playbook内容如下:
1 2 3 4 5 6
| - hosts: localhost gather_facts: false tasks: - name: use var debug: var: hostvars['192.168.100.11'].ansible_hostname
|