事实与任务控制
本文已参与「新人创作礼」活动,一起开启掘金创作之路。
一、Ansible管理事实
ansible事实描述
-
Ansible事实是ansible在受管主机上自动检测到的变量
-
事实中包含有主机相关的信息,可以像play中的常规变量、条件、循环或依赖于从受管主机收集的值的任何其他语句那样使用
-
为受管主机收集的一些事实可能包括:主机名称、内核版本、网络接口、IP地址、操作系统版本、各种环境变量、CPU数量、提供的或可用的内存、可用磁盘空间等等
-
借助事实,可以方便地检索受管主机的状态,并根据该状态确定要执行的操作 例如:
- 可以根据含有受管主机当前内核版本的事实运行条件任务,以此来重启服务器
- 可以根据通过事实报告的可用内存来自定义
MySQL配置文件 - 可以根据事实的值设置配置文件中使用的IPV4地址
-
每个play在执行第一个任务之前会先自动与逆行
setup模块来收集事实
ansible事实的示例
| 事实 | 变量 |
|---|---|
| 短主机名 | ansible_facts['hostname'] |
| 完全限定域名 | ansible_facts['fqdn'] |
| IPv4地址 | ansible_facts['default_ipv4'] ['address'] |
| 所有网络接口的名称列表 | ansible_facts['interfaces'] |
| /dev/vda1磁盘分区的大小 | ansible_facts['devices'] ['vda'] ['partitions'] ['vda1'] ['size'] |
| DNS服务器列表 | ansible_facts['dns'] ['nameservers'] |
| 当前运行的内核版本 | ansible_facts['kernel'] |
如果变量的值为散列/字典类型,则可使用两种语法来获取其值。比如:
- ansible_facts['default_ipv4'] ['address']也可以写成ansible_facts.default_ipv4.address
- ansible_facts['dns'] ['nameservers']也可以写成ansible_facts.dns.nameservers
查看node2主机的IP
//编写playbook
---
- hosts: all
tasks:
- name: print ip
debug:
msg:
the IPv4 address of {{ ansible_facts.fqdn }} is {{ ansible_facts.all_ipv4_addresses }}
//执行playbook
[root@node1 test]# ansible-playbook fact.yml
PLAY [all] **************************************************************************************************************************
TASK [Gathering Facts] **************************************************************************************************************
ok: [192.168.100.110]
TASK [print ip] *********************************************************************************************************************
ok: [192.168.100.110] => {
"msg": "the IPv4 address of node2 is ['192.168.100.110']"
}
PLAY RECAP **************************************************************************************************************************
192.168.100.110 : ok=2 changed=0 unreachable=0 failed=0 skipped=0 rescued=0 ignored=0
关闭事实收集
通常我们关闭事实收集是为了:
- 不准备使用任何事实
- 希望加快play速度
- 希望减小play在受管主机上造成的负载
- 受管主机因为某种原因无法运行setup模块
- 需要安装一些必备软件后再进行事实收集
二、编写循环和条件任务
1. ansible中循环的介绍
我们在编写playbook时,不可避免的要执行一些重复性操作,比如安装软件包,批量创建用户,操作某个目录下的所有文件等。正因为ansible是一门简单的自动化语言,所以流程控制、循环语句这些编程语言的基本元素它都同样具备
1.1 loop
在playbook中使用循环,直接使用loop关键字即可
如下:
[root@node1 test]# vim test1.yml
---
- hosts: 192.168.100.110
gather_facts: no
tasks:
- name: start service
service:
name: "{{ item }}"
state: started
loop:
- httpd
- php-fpm
也可以将loop循环的列表提前赋值给一个变量,然后在循环语句中调用:
[root@node1 test]# vim test_service.yml
test_services:
- postfix
- httpd
[root@node1 test]# vim test1.yml
- name: start services
hosts: test
vars_files:
- test_services.yml
tasks:
- name: start service
service:
name: "{{ item }}"
state: started
loop: "{{ test_services }}"
执行结果如下:
[root@node1 test]# ansible-playbook test1.yml
PLAY [192.168.100.110] **************************************************************************************************************
TASK [stop service] *****************************************************************************************************************
ok: [192.168.100.110] => (item=httpd)
ok: [192.168.100.110] => (item=php-fpm)
PLAY RECAP **************************************************************************************************************************
192.168.100.110 : ok=1 changed=0 unreachable=0 failed=0 skipped=0 rescued=0 ignored=0
1.2 在循环语句中注册变量
register关键字也可以捕获循环任务的输出。以下代码片段显示了循环任务中register变量的结构:
[root@node1 test]# vim loop_register.yml
---
- hosts: 192.168.100.110
gather_facts: no
tasks:
- name: looping echo task
shell: 'echo this is my item: {{ item }}'
loop:
- one
- two
register: echo_results
- name: show echo_results variable
debug:
var: echo_results
执行语句,可以看到变量的返回结果为一个字典列表
[root@node1 test]# ansible-playbook loop_register.yml
PLAY [192.168.100.110] **************************************************************************************************************
TASK [looping echo task] ************************************************************************************************************
changed: [192.168.100.110] => (item=one)
changed: [192.168.100.110] => (item=two)
TASK [show echo_results variable] ***************************************************************************************************
ok: [192.168.100.110] => {
"echo_results": {
"changed": true,
"msg": "All items completed",
"results": [
{
"ansible_facts": {
"discovered_interpreter_python": "/usr/libexec/platform-python"
},
"ansible_loop_var": "item",
"changed": true,
"cmd": "echo this is my item: one",
"delta": "0:00:00.003536",
"end": "2021-07-25 05:07:34.249739",
"failed": false,
"invocation": {
"module_args": {
"_raw_params": "echo this is my item: one",
"_uses_shell": true,
"argv": null,
"chdir": null,
"creates": null,
"executable": null,
"removes": null,
"stdin": null,
"stdin_add_newline": true,
"strip_empty_ends": true,
"warn": true
}
},
"item": "one",
"rc": 0,
"start": "2021-07-25 05:07:34.246203",
"stderr": "",
"stderr_lines": [],
"stdout": "this is my item: one",
"stdout_lines": [
"this is my item: one"
]
},
{
"ansible_loop_var": "item",
"changed": true,
"cmd": "echo this is my item: two",
"delta": "0:00:00.003148",
"end": "2021-07-25 05:07:34.550064",
"failed": false,
"invocation": {
"module_args": {
"_raw_params": "echo this is my item: two",
"_uses_shell": true,
"argv": null,
"chdir": null,
"creates": null,
"executable": null,
"removes": null,
"stdin": null,
"stdin_add_newline": true,
"strip_empty_ends": true,
"warn": true
}
},
"item": "two",
"rc": 0,
"start": "2021-07-25 05:07:34.546916",
"stderr": "",
"stderr_lines": [],
"stdout": "this is my item: two",
"stdout_lines": [
"this is my item: two"
]
}
]
}
}
PLAY RECAP **************************************************************************************************************************
192.168.100.110 : ok=2 changed=1 unreachable=0 failed=0 skipped=0 rescued=0 ignored=0
1.3 旧循环列表
在ansible2.5以前,playbook通过不同的循环语句以实现不同的循环,这些语句使用with_作为前缀。这些语法目前仍然兼容,但在未来的某个版本会逐步废弃
| 循环语句关键字 | 描述 |
|---|---|
| with_items | 简单的列表循环 |
| with_nested | 嵌套循环 |
| with_dict | 循环字典 |
| with_fileglob | 循环指定目录中的所有文件 |
| with_lines | 循环一个文件中的所有行 |
| with_sequence | 生成一个自增的整数序列,可以指定起始值和结束值以及步长。参数以key=value的形式指定,format指定输出的格式。数字可以是十进制、十六进制、八进制 |
| with_subelement | 遍历子元素 |
| with_together | 遍历数据并行集合 |
在没学会使用循环之前,如果想要在同一主机中创建四个文件,那么可能会编写如下playbook
[root@server4 ~]# vim test2.yml
---
- hosts: 192.168.100.110
gather_facts: no
tasks:
- file:
path: "/opt/a"
state: touch
- file:
path: "/opt/b"
state: touch
- file:
path: "/opt/c"
state: touch
- file:
path: "/opt/d"
state: touch
我们重复写了file模块4次,其实每次只改变了参数path的值,如果使用循环可以改写成如下
[root@server4 ~]# vim test2.yml
---
- hosts: 192.168.100.110
gather_facts: no
tasks:
- file:
path: "{{ item }}"
state: touch
loop:
- a
- b
- c
- d