ansible之条件判断
Posted
tags:
篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了ansible之条件判断相关的知识,希望对你有一定的参考价值。
参考技术A defined:判断变量是否已经定义,已经定义则为真undefined:判断变量是否已经定义,未定义则返回真
none:判断变量是否已经定义,如果变量值已经定义,但是变量值为空,则返回真
success或succeeded: 通过任务的返回信息判断任务的执行状态,任务执行成功则返回真
failure或failed: 通过任务的返回信息判断任务的执行状态,任务执行失败则返回真
change或changed: 通过任务的返回信息判断任务的执行状态,任务执行状态为changed则返回真
skip或skipped: 通过任务的返回信息判断任务的执行状态,当任务没有满足条件,而被跳过执行时,则返回真
稍加改变看看三种情况的结果
file: 判断路径是否是一个文件,如果路径是一个文件则为真(该参数在实际使用我碰到过问题,暂时不考虑使用可以使用stat来代替例如:
)
directory: 判断路径是否是一个目录,如果路径是一个目录则为真
link: 判断路径是否是一个软连接,如果路径是一个软连接则为真
mount: 判断路径是否是一个挂载点,如果路径是一个挂载点则为真
exists: 判断路径是否存在,如果路径存在则为真
注意:某些版本之前可能需要加上“is_”前缀
even: 判断数值是否是偶数,偶数则为真
odd: 判断数值是否是奇数,奇数则为真
divisibleby(num): 判断是否可以整除指定的数值,如果除以指定的值以后余数为0,则返回真
version: 可以用于对比两个版本号的大小,或者与指定的版本号进行对比,语法version('版本号','比较操作符')
2.5版本此test从version_compare 更名为version
这里的例子里面两种比较都是可以的 支持多种风格操作符。
subset: 判断一个list是不是另一个list的子集,是则为真
siperset: 判断一个list是不是另一个list的父集,是则为真
注:2.5版本之前是issubset和issuperset
string: 判断对象是否是一个字符串,是则为真
number: 判断对象是否是一个数字,是则为真
Ansible 日常使用技巧 (下)
接
在日常运维工作中,在有的时候 ansble-playbook 的结果依赖于变量、fact 或者是前一个任务的执行结果,从而需要使用到条件语句。使用 ansible-playbook 时,可能需要对某些条件进行判断,只有当满足条件才执行相应的tasks。有下面几种条件判断:
1)when 条件判断:只条满足 when 的条件时才执行对应的 tasks
需要注意:when 关键字后面跟着的是 python 的表达式,在表达式中我们能够使用任何的变量或者 facts。
另外注意:当需要用远程主机的一些信息时,gather_facts 必须要开启,默认是开启状态!!!!!
[root@hostname ~]# cat /etc/ansible/hosts |tail -3
[kevin_server]
172.16.60.241
172.16.60.242
注意:下面 debug 中 msg 后面引用的变量都是在 setup 模块中查询出来的(可直接作为变量引用)
[root@hostname ~]# ansible 172.16.60.242 -m setup|grep ansible_fqdn
"ansible_fqdn": "webserver02",
[root@hostname ~]# cat /etc/ansible/test.yml
- hosts: kevin_server
remote_user: root
gather_facts: True
tasks:
- name: Host 172.16.60.242 run this task
debug: 'msg=" {{ ansible_default_ipv4.address }}"'
when: ansible_default_ipv4.address == "172.16.60.242"
- name: memtotal < 500M and processor_cores == 2 run this task
debug: 'msg="{{ ansible_fqdn }}"'
when: ansible_memtotal_mb < 500 and ansible_processor_cores == 2
- name: all host run this task
shell: hostname
register: info
- name: Hostname is webserver01 Machie run this task
debug: 'msg="{{ ansible_fqdn }}"'
when: info['stdout'] == "webserver01"
- name: Hostname is startswith l run this task
debug: 'msg="{{ ansible_fqdn }}"'
when: info['stdout'].startswith('l')
查看执行结果:
[root@hostname ~]# ansible-playbook -v /etc/ansible/test.yml
Using /etc/ansible/ansible.cfg as config file
PLAY [kevin_server] ******************************************************************************************************************************
TASK [Gathering Facts] ***************************************************************************************************************************
ok: [172.16.60.242]
ok: [172.16.60.241]
TASK [Host 172.16.60.242 run this task] **********************************************************************************************************
skipping: [172.16.60.241] => {}
ok: [172.16.60.242] => {
"msg": " 172.16.60.242"
}
TASK [memtotal < 500M and processor_cores == 2 run this task] ************************************************************************************
skipping: [172.16.60.241] => {}
skipping: [172.16.60.242] => {}
TASK [all host run this task] ********************************************************************************************************************
changed: [172.16.60.241] => {"changed": true, "cmd": "hostname", "delta": "0:00:00.003661", "end": "2019-10-11 17:19:29.912525", "rc": 0,
"start": "2019-10-11 17:19:29.908864", "stderr": "", "stderr_lines": [], "stdout": "webserver01", "stdout_lines": ["webserver01"]}
changed: [172.16.60.242] => {"changed": true, "cmd": "hostname", "delta": "0:00:00.004133", "end": "2019-10-11 17:19:29.922962", "rc": 0,
"start": "2019-10-11 17:19:29.918829", "stderr": "", "stderr_lines": [], "stdout": "webserver02", "stdout_lines": ["webserver02"]}
TASK [Hostname is webserver01 Machie run this task] **********************************************************************************************
ok: [172.16.60.241] => {
"msg": "k8s-master01"
}
skipping: [172.16.60.242] => {}
TASK [Hostname is startswith l run this task] ****************************************************************************************************
skipping: [172.16.60.241] => {}
skipping: [172.16.60.242] => {}
PLAY RECAP ***************************************************************************************************************************************
172.16.60.241 : ok=3 changed=1 unreachable=0 failed=0 skipped=3 rescued=0 ignored=0
172.16.60.242 : ok=3 changed=1 unreachable=0 failed=0 skipped=3 rescued=0 ignored=0
2)when 条件判断之引用变量
when 变量引用错误提示:[WARNING]: when statements should not include jinja2 templating delimiters such as {{ }} or {% %}.
正确的引用方式:将{{}} or {% %} 改为()
错误写法示例:when: ansible_default_ipv4.address == {{ webserver01 }}
正确写法示例:when: ansible_default_ipv4.address == (webserver01)
~]# cat /etc/ansible/test.yml
hosts: kevin_server
remote_user: root
gather_facts: True
tasks:
name: Host 192.168.1.101 run this task
#debug: 'msg=" {{ ansible_default_ipv4.address }}"'
shell: hostname
when: ansible_default_ipv4.address == (webserver02)
查看执行结果:
[root@hostname ~]# ansible-playbook -v /etc/ansible/test.yml -e "webserver02=172.16.60.242"
Using /etc/ansible/ansible.cfg as config file
PLAY [kevin_server] ******************************************************************************************************************************
TASK [Gathering Facts] ***************************************************************************************************************************
ok: [172.16.60.241]
ok: [172.16.60.242]
TASK [Host 192.168.1.101 run this task] **********************************************************************************************************
skipping: [172.16.60.241] => {"changed": false, "skip_reason": "Conditional result was False"}
changed: [172.16.60.242] => {"changed": true, "cmd": "hostname", "delta": "0:00:00.004349", "end": "2019-10-11 17:23:39.961860", "rc": 0,
"start": "2019-10-11 17:23:39.957511", "stderr": "", "stderr_lines": [], "stdout": "webserver02", "stdout_lines": ["webserver02"]}
PLAY RECAP ***************************************************************************************************************************************
172.16.60.241 : ok=1 changed=0 unreachable=0 failed=0 skipped=1 rescued=0 ignored=0
172.16.60.242 : ok=2 changed=1 unreachable=0 failed=0 skipped=0 rescued=0 ignored=0
3)changed_when:先执行 task,并对 task 返回的值进行判断,当满足 changed_when 指定的条件时说明是执行成功的
需要注意:默认情况下执行了命令的主机状态都为 changed,本例对输出进行判断,包含是某个指定字符才能为 changed;
~]# cat /etc/ansible/test.yml
hosts: kevin_server
remote_user: root
gather_facts: True
tasks:
name: all host run this task
shell: hostname
register: info
changed_when: '"webserver01" in info.stdout'
查看执行结果:
[root@hostname ~]# ansible-playbook -v /etc/ansible/test.yml
Using /etc/ansible/ansible.cfg as config file
PLAY [kevin_server] ******************************************************************************************************************************
TASK [Gathering Facts] ***************************************************************************************************************************
ok: [172.16.60.241]
ok: [172.16.60.242]
TASK [all host run this task] ********************************************************************************************************************
changed: [172.16.60.241] => {"changed": true, "cmd": "hostname", "delta": "0:00:00.004531", "end": "2019-10-11 17:25:15.865591", "rc": 0,
"start": "2019-10-11 17:25:15.861060", "stderr": "", "stderr_lines": [], "stdout": "webserver01", "stdout_lines": ["webserver01"]}
ok: [172.16.60.242] => {"changed": false, "cmd": "hostname", "delta": "0:00:00.004694", "end": "2019-10-11 17:25:15.872135", "rc": 0,
"start": "2019-10-11 17:25:15.867441", "stderr": "", "stderr_lines": [], "stdout": "webserver02", "stdout_lines": ["webserver02"]}
PLAY RECAP ***************************************************************************************************************************************
172.16.60.241 : ok=2 changed=1 unreachable=0 failed=0 skipped=0 rescued=0 ignored=0
172.16.60.242 : ok=2 changed=0 unreachable=0 failed=0 skipped=0 rescued=0 ignored=0
4)failed_when
failed_when:当执行失败后,会将信息存在 register 的 stderr 中,通过判断指定的字符是否在 stderr 中来确定是否真的失败;
[root@hostname ~]# cat /etc/ansible/test.yml
- hosts: kevin_server
remote_user: root
gather_facts: True
tasks:
- name: this command prints FAILED when it fails
command: echo "FAILED"
register: command_result
failed_when: "'FAILED' in command_result.stdout"
- name: this is a test
shell: echo "haha"
[root@hostname ~]# ansible-playbook -v /etc/ansible/test.yml
Using /etc/ansible/ansible.cfg as config file
PLAY [kevin_server] ******************************************************************************************************************************
TASK [Gathering Facts] ***************************************************************************************************************************
ok: [172.16.60.242]
ok: [172.16.60.241]
TASK [this command prints FAILED when it fails] **************************************************************************************************
fatal: [172.16.60.241]: FAILED! => {"changed": true, "cmd": ["echo", "FAILED"], "delta": "0:00:00.002550", "end": "2019-10-11 19:19:47.918921", "failed_when_result": true, "rc": 0, "start": "2019-10-11 19:19:47.916371", "stderr": "", "stderr_lines": [], "stdout": "FAILED", "stdout_lines": ["FAILED"]}
fatal: [172.16.60.242]: FAILED! => {"changed": true, "cmd": ["echo", "FAILED"], "delta": "0:00:00.002410", "end": "2019-10-11 19:19:47.943843", "failed_when_result": true, "rc": 0, "start": "2019-10-11 19:19:47.941433", "stderr": "", "stderr_lines": [], "stdout": "FAILED", "stdout_lines": ["FAILED"]}
PLAY RECAP ***************************************************************************************************************************************
172.16.60.241 : ok=1 changed=0 unreachable=0 failed=1 skipped=0 rescued=0 ignored=0
172.16.60.242 : ok=1 changed=0 unreachable=0 failed=1 skipped=0 rescued=0 ignored=0
可以看出,第一个 task 任务的 failed_when 已经满足了,所以就此停止 playbook 的运行了,下面的 task 任务也不会执行了!
failed_when 其实是 ansible 的一种错误处理机制,是由 fail 模块使用了when 条件语句的组合效果。
所以,上面的配置也可以调整成下面写法(上面第一个 task 可以调整为下面第1 和第 2 个 task 的写法,是一样的效果):
[root@hostname ~]# cat /etc/ansible/test.yml
- hosts: kevin_server
remote_user: root
gather_facts: True
tasks:
- name: this command prints FAILED when it fails
command: echo "FAILED"
register: command_result
- name: fail the play if the previous command did not succeed
fail: msg="the command failed"
when: "'FAILED' in command_result.stdout"
- name: this is a test
shell: echo "haha"
[root@hostname ~]# ansible-playbook -v /etc/ansible/test.yml
Using /etc/ansible/ansible.cfg as config file
PLAY [kevin_server] ******************************************************************************************************************************
TASK [Gathering Facts] ***************************************************************************************************************************
ok: [172.16.60.242]
ok: [172.16.60.241]
TASK [this command prints FAILED when it fails] **************************************************************************************************
changed: [172.16.60.241] => {"changed": true, "cmd": ["echo", "FAILED"], "delta": "0:00:00.003989", "end": "2019-10-11 19:19:06.741840", "rc": 0, "start": "2019-10-11 19:19:06.737851", "stderr": "", "stderr_lines": [], "stdout": "FAILED", "stdout_lines": ["FAILED"]}
changed: [172.16.60.242] => {"changed": true, "cmd": ["echo", "FAILED"], "delta": "0:00:00.003135", "end": "2019-10-11 19:19:06.744136", "rc": 0, "start": "2019-10-11 19:19:06.741001", "stderr": "", "stderr_lines": [], "stdout": "FAILED", "stdout_lines": ["FAILED"]}
TASK [fail the play if the previous command did not succeed] *************************************************************************************
fatal: [172.16.60.241]: FAILED! => {"changed": false, "msg": "the command failed"}
fatal: [172.16.60.242]: FAILED! => {"changed": false, "msg": "the command failed"}
PLAY RECAP ***************************************************************************************************************************************
172.16.60.241 : ok=2 changed=1 unreachable=0 failed=1 skipped=0 rescued=0 ignored=0
172.16.60.242 : ok=2 changed=1 unreachable=0 failed=1 skipped=0 rescued=0 ignored=0
这里就可以看出"failed_when"的作用,它的作用就是当 failed_when 关键字对应的条件成立时,failed_when 会将对应的任务的执行状态设置为失败,以停止 playbook 的运行!
但是需要注意的时:failed_when 虽然会将任务的执行状态设置为失败,但是它并不代表任务真的失败了!就以上面例子来说,上面的 command 模块的确时完全正常的执行了,只不过在执行之后,failed_when 对应的条件成立了,failed_when将 command 模块的执行状态设置为失败而已!所以,failed_when 并不会影响 command 模块的执行过程,只会在条件成立时影响 command 模块最终的执行状态,以便于停止 playbook 的运行。
因此需要注意:
failed_when:关键字的作用是在条件成立时,将对应任务的执行状态设置为失败!
changed_when:关键字的作用是在条件成立时,将对应任务的执行状态设置为 changed!
最初,ansible 的执行效率和 saltstack (基于 zeromq 消息队列的方式)相比要慢的多的多,特别是被控节点量很大的时候。但是 ansible 发展到现在,它的效率得到了极大的改善。在被控节点不太多的时候,默认的设置已经够快。即使被控节点数量巨大的时候,也可以通过一些优化去极大的提高 ansible 的执行效率。所以在使用 Ansible 的过程中,当管理的服务器数量增加时,不得不面对一个无法避免的问题执行效率慢,这里列出一些解决办法。
优化一:关闭 gathering facts 功能
如果观察过 ansible-playbook 的执行过程,就会发现 ansible-playbook 的第1个步骤总是执行 gather facts,不论你有没有在 playbook 设定这个 tasks。
如果你不需要获取被控机器的 fact 数据的话,就可以关闭获取 fact 数据功能。关闭之后,可以加快 ansible-playbook 的执行效率,尤其是你管理很大量的机器时,这非常明显。
关闭获取 facts 很简单,只需要在 playbook 文件中加上"gather_facts: False" 或者 "gather_facts: No"即可(False 和 No 都为小写也可以)。
[root@hostname ~]# cat /etc/ansible/test.yml
- hosts: kevin_server
remote_user: root
tasks:
- name: this is a test
shell: echo "haha"
执行这个paly,会发现第一个执行的是gather facts,因为默认是打开gather facts功能的!!!!
[root@hostname ~]# ansible-playbook -v /etc/ansible/test.yml
Using /etc/ansible/ansible.cfg as config file
PLAY [kevin_server] ******************************************************************************************************************************
TASK [Gathering Facts] ***************************************************************************************************************************
ok: [172.16.60.242]
ok: [172.16.60.241]
TASK [this is a test] ****************************************************************************************************************************
changed: [172.16.60.241] => {"changed": true, "cmd": "echo \"haha\"", "delta": "0:00:00.002949", "end": "2019-10-11 19:33:54.883702", "rc": 0, "start": "2019-10-11 19:33:54.880753", "stderr": "", "stderr_lines": [], "stdout": "haha", "stdout_lines": ["haha"]}
changed: [172.16.60.242] => {"changed": true, "cmd": "echo \"haha\"", "delta": "0:00:00.003409", "end": "2019-10-11 19:33:54.884398", "rc": 0, "start": "2019-10-11 19:33:54.880989", "stderr": "", "stderr_lines": [], "stdout": "haha", "stdout_lines": ["haha"]}
PLAY RECAP ***************************************************************************************************************************************
172.16.60.241 : ok=2 changed=1 unreachable=0 failed=0 skipped=0 rescued=0 ignored=0
172.16.60.242 : ok=2 changed=1 unreachable=0 failed=0 skipped=0 rescued=0 ignored=0
现在关闭 gathering facts 功能
[ ]
- hosts: kevin_server
remote_user: root
gather_facts: False
tasks:
- name: this is a test
shell: echo "haha"
再执行这个 play,就会发现没有了 gathering facts 执行过程,整个执行速度也快了!
[root@hostname ~]# ansible-playbook -v /etc/ansible/test.yml
Using /etc/ansible/ansible.cfg as config file
PLAY [kevin_server] ******************************************************************************************************************************
TASK [this is a test] ****************************************************************************************************************************
changed: [172.16.60.242] => {"ansible_facts": {"discovered_interpreter_python": "/usr/bin/python"}, "changed": true, "cmd": "echo \"haha\"", "delta": "0:00:00.002571", "end": "2019-10-11 19:35:06.821842", "rc": 0, "start": "2019-10-11 19:35:06.819271", "stderr": "", "stderr_lines": [], "stdout": "haha", "stdout_lines": ["haha"]}
changed: [172.16.60.241] => {"ansible_facts": {"discovered_interpreter_python": "/usr/bin/python"}, "changed": true, "cmd": "echo \"haha\"", "delta": "0:00:00.003121", "end": "2019-10-11 19:35:06.842207", "rc": 0, "start": "2019-10-11 19:35:06.839086", "stderr": "", "stderr_lines": [], "stdout": "haha", "stdout_lines": ["haha"]}
PLAY RECAP ***************************************************************************************************************************************
172.16.60.241 : ok=1 changed=1 unreachable=0 failed=0 skipped=0 rescued=0 ignored=0
172.16.60.242 : ok=1 changed=1 unreachable=0 failed=0 skipped=0 rescued=0 ignored=0
优化二:开启 SSH pipelining
pipeline 是 openssh 的一个特性,ssh pipelining 是一个加速 Ansible 执行速度的简单方法。
在 ansible 执行每个任务的整个流程中,有一个过程是将临时任务文件put到远程的 ansible 客户机上,然后通过 ssh 连接过去远程执行这个任务。
如果开启了 pipelining,一个任务的所有动作都在一个 ssh 会话中完成,也会省去 sftp 到远端的过程,它会直接将要执行的任务在 ssh 会话中进行。
ssh pipelining 默认是关闭!!!!之所以默认关闭是为了兼容不同的 sudo 配置,主要是 requiretty 选项。如果不使用 sudo,建议开启!!!打开此选项可以减少 ansible 执行没有传输时 ssh 在被控机器上执行任务的连接数。
不过,如果使用sudo,必须关闭requiretty选项。修改/etc/ansible/ansible.cfg 文件可以开启pipelining
[root@hostname ~]# vim /etc/ansible/ansible.cfg
........
pipelining = True
这样开启了 pipelining 之后, ansible 执行的整个流程就少了一个 PUT 脚本去远程服务端的流程,然后就可以批量对机器执行命令试下,可以明显感受到速度的提升。
但是要注意的是:
如果在 ansible 中使用 sudo 命令的话(ssh user@host sudo cmd),需要在被控节点的 /etc/sudoers 中禁用"requiretty"!!!!
之所以要设置 /etc/sudoers 中的 requiretty,是因为 ssh 远程执行命令时,它的环境是非登录式非交互式 shell,默认不会分配 tty,没有 tty,ssh 的 sudo 就无法关闭密码回显(使用"-tt"选项强制 SSH 分配 tty)。所以出于安全考虑,/etc/sudoers 中默认是开启 requiretty 的,它要求只有拥有 tty 的用户才能使用 sudo,也就是说 ssh 连接过去不允许执行 sudo。可以通过 visudo 编辑配置文件,注释该选项来禁用它。
[ ]
优化三:开启 SSH 长连接 (ControlPersist 特性)
ansible天然支持openssh,默认连接方式下,它对ssh的依赖性非常强。所以优化ssh连接,在一定程度上也在优化ansible。其中一点是开启ssh的长连接,即长时间保持连接状态。
Ansible模式是使用SSH和远程主机进行通信, 所以Ansible对SSH的依赖性非常强, 在OpenSSH 5.6版本以后SSH就支持了Multiplexing(多路复用)。
所以如果Ansible中控机的SSH -V版本高于5.6时, 就可以使用ControlPersist来提高ssh连接速度,从而提高ansible执行效率。
[ ]
CentOS Linux release 7.6.1810 (Core)
[ ]
OpenSSH_7.4p1, OpenSSL 1.0.2k-fips 26 Jan 2017
我们可以直接在 ansible.cfg 文件中设置 SSH 长连接, 设置参数如下:
[root@hostname ansible]# vim /etc/ansible/ansible.cfg
..........
ssh_args = -C -o ControlMaster=auto -o ControlPersist=5d
注意:
ConrolPersist=5d, 这个参数是设置整个长连接保持时间为5天。
开启此参数的 ssh 长连接功能后,在会话过期前会一直建立连接,在 netstat 的结果中会看到 ssh 连接是一直 established 状态,且通过 SSH 连接过的设备都会在当前用户家目录的".ansible/cp"目录下生成一个 socket 文件,每个会话对应生成一个 socket 文件。也可以通过 netstat 命令查看, 会发现有一个 ESTABLISHED 状态的连接一直与远程设备进行着 TCP 连接。
[root ansible]# ps -ef|grep ssh|grep ansible
root 5614 1 0 23:09 ? 00:00:00 ssh: /root/.ansible/cp/7e37065045 [mux]
root 5617 1 0 23:09 ? 00:00:00 ssh: /root/.ansible/cp/e2056334cd [mux]
[root ansible]# netstat -anptu|grep ESTABLISHED|grep ssh|grep /root
tcp 0 0 172.16.60.246:44430 172.16.60.242:22 ESTABLISHED 5617/ssh: /root/.an
tcp 0 0 172.16.60.246:43498 172.16.60.241:22 ESTABLISHED 5614/ssh: /root/.an
[root ansible]# ls /root/.ansible/cp/
7e37065045 e2056334cd
需要注意:
ControlPersist 特性需要高版本的 SSH 才支持,CentOS6 默认是不支持的,如果需要使用,需要自行升级 openssh(确保 SSH -V 版本高于 5.6)。
ControlPersist 即持久化 socket,一次验证,多次通信。并且只需要修改 ssh 客户端就行,也就是 Ansible 机器即可。
优化四: 开启 accelerate 模式
[ 注意:这个只针对 centos6 系统 ]
Ansible 还有一个 accelerate 模式, 这和前面的 Multiplexing 有点类似, 因为都依赖 Ansible 中控机跟远程机器有一个长连接。
但是 accelerate 是使用 python 程序在远程机器上运行一个守护进程, 然后 Ansible 会通过这个守护进程监听的端口进行通信。
开启 accelerate 模式很简单, 只要在 playbook 中配置 accelerate: true 即可.
但是需要注意的是:
如果开启 accelerate 模式, 则需要在 Ansible 中控机与远程机器都安装python-keyczar 软件包。
下面是在ansible.cfg文件中定义一些accelerate参数, 当然也可以在写 playbook 的时候再定义
第一步:ansible 服务端和客户端都要安装 python-keyczar
[ ]
第二步:修改 ansible 服务端的 ansible.cfg 文件
[root@hostname ~]# vim /etc/ansible/ansible.cfg
..........
[accelerate]
accelerate_port = 5099
accelerate_timeout = 30
accelerate_connect_timeout = 5.0
第三步:修改ansible服务端的ansible-playbook的剧本文件,加入 accelerate: true
[ ]
- hosts: kevin_server
remote_user: root
gather_facts: False
accelerate: true
tasks:
- name: this is a test
shell: echo "haha"
需要注意:
这种优化方式只针对 centos6 系统来提高连接速度。在 centos7 下不可用,否则会报错:"ERROR! 'accelerate' is not a valid attribute for a Play"
如果 ansible 没有性能瓶颈的情况下,不推荐使用这种优化措施!
优化五: 设置 facts 缓存
如果细心的话, 就会发现执行 playbook 的时候, 默认第一个 task 都是GATHERING FACTS, 这个过程就是 Ansible 在收集每台主机的 facts 信息。
方便我们在 playbook 中直接饮用 facts 里的信息,当然如果你的 playbook 中不需要 facts 信息, 可以在 playbook 中设置"gather_facts: False"来提高 playbook 效率.
但是如果我们既想在每次执行 playbook 的时候都能收集 facts, 又想加速这个收集过程, 那么就需要配置 facts 缓存了。
目前 Ansible 支持使用 json 文件存储facts信息。
第一种缓存方式:使用json文件缓存
[root@hostname ~]# vim /etc/ansible/ansible.cfg
.........
gathering = smart
fact_caching_timeout = 86400
fact_caching = jsonfile
fact_caching_connection = /dev/shm/ansible_fact_cache
正常配置 palybook,不需要关闭 gathering facts 功能
[ ]
- hosts: kevin_server
remote_user: root
tasks:
- name: this is a test
shell: echo "haha"
查看这个 playbook 过程,用时1.102s(第一次可能稍微慢点,缓存之后,后面执行就很快了)
[root@hostname ~]# time ansible-playbook /etc/ansible/test.yml
PLAY [kevin_server] ******************************************************************************************************************************
TASK [this is a test] ****************************************************************************************************************************
changed: [172.16.60.241]
changed: [172.16.60.242]
PLAY RECAP ***************************************************************************************************************************************
172.16.60.241 : ok=1 changed=1 unreachable=0 failed=0 skipped=0 rescued=0 ignored=0
172.16.60.242 : ok=1 changed=1 unreachable=0 failed=0 skipped=0 rescued=0 ignored=0
real 0m1.102s
user 0m0.879s
sys 0m0.179s
如果去掉上面的 facts 缓存的四行配置,再次执行上面的 playbok,发现用时10s左右!!!
查看缓存文件:
[ ]
172.16.60.241 172.16.60.242
第二种缓存方式:使用 redis 存储 facts 文件需安装 redis,还需要安装 python 库
[root@hostname ~]# yum install redis
[root@hostname ~]# yum -y install epel-release
[root@hostname ~]# yum install python-pip
[root@hostname ~]# pip install redis
[root@hostname ~]# vim /etc/ansible/ansible.cfg
........
gathering = smart
facts_caching_timeout = 86400 #设置缓存过期时间86400秒
facts_caching = redis # 使用redis或者 (或者使用memcached,即"facts_caching = memcached")
fact_caching_connection = 127.0.0.1:6379
#若redis设置了密码,比如密码为"admin",则配置修改如下:
# fact_caching_connection = localhost:6379:0:admin
启动 redis
[ ]
[ ]
COMMAND PID USER FD TYPE DEVICE SIZE/OFF NODE NAME
redis-ser 29218 redis 4u IPv4 291786209 0t0 TCP localhost:6379 (LISTEN)
执行上面的 palybook
[root@hostname ~]# time ansible-playbook /etc/ansible/test.yml
PLAY [kevin_server] ******************************************************************************************************************************
TASK [this is a test] ****************************************************************************************************************************
changed: [172.16.60.241]
changed: [172.16.60.242]
PLAY RECAP ***************************************************************************************************************************************
172.16.60.241 : ok=1 changed=1 unreachable=0 failed=0 skipped=0 rescued=0 ignored=0
172.16.60.242 : ok=1 changed=1 unreachable=0 failed=0 skipped=0 rescued=0 ignored=0
real 0m1.132s
user 0m0.909s
sys 0m0.178s
需要注意:
在使用 redis 缓存后,如果出现异常(若未出现,请忽略):TypeError: the JSON object must be str, not 'bytes'。
解决办法:
[ ]
[ ]
..........
self._cache[key] = json.loads(value.decode('utf-8'))
查看 redis 存储情况
[root@hostname ~]# redis-cli
127.0.0.1:6379> keys *
1) "ansible_facts172.16.60.242"
2) "ansible_facts172.16.60.241"
3) "ansible_cache_keys"
总之:不同网络环境下的耗时肯定是不同的,但是设置缓存是肯定可以加快 Ansible 运行速度的,特别是 playbook 的运行。
优化六: Ansible 取消交互
[root@hostname ~]# vim /etc/ansible/ansible.cfg
........
host_key_checking = False # 打开注释即可
取消 ssh 的 yes 和 no 的交互:
[ ]
UserKnownHostsFile /dev/null
ConnectTimeout 15
StrictHostKeyChecking no
或者直接 ssh 时增加一个参数
[ ]
优化七:ansible 的 -t 选项,提高 ansible 执行效率
ansible 的"-t"或"--tree"选项是将 ansible 的执行结果按主机名保存在指定目录下的文件中。
有些时候,ansible 执行起来的速度会非常慢,这种慢体现在即使执行的是一个立即返回的简单命令(如 ping 模块),也会耗时很久,且不是因为 ssh 连接慢导致的。
如果使用 -t 选项,将第一次执行得到的结果按 inventory 中定义的主机名保存在文件中,下次执行到同一台主机时速度将会变快很多,即使之后不再加上-t选项,也可以在一定时间内保持迅速执行。即使执行速度正常(如执行一个Ping命令0.7秒左右),使用 -t 选项也可以在此基础上变得更快。
除了使用 -t 选项,使用重定向将结果重定向到某个文件中也是一样的效果。这也算是一种 ansible 提速方式,但在 centos6 上使用低版本 ansible 时,有时会出现执行很慢的现象,但不是每次都这样,且 centos7 执行速度正常
所以这也是一种"bug"式问题,故这种方式没有通用性。
[root@hostname ~]# time ansible kevin_server -m command -a "hostname"
[root@hostname ~]# time ansible kevin_server -m command -a "hostname" -t /tmp/test
[root@hostname ~]# ll /tmp/a
total 8
-rw-r--r-- 1 root root 2780 Oct 12 02:03 172.16.60.241
-rw-r--r-- 1 root root 2776 Oct 12 02:03 172.16.60.242
上面做了对比,发现使用-t或重定向方式,将 ansible 的执行结果按主机名保存在指定目录下的文件中,ansible 执行效率会有所提升。
完结.
出处|http://1t.click/aFSZ
以上是关于ansible之条件判断的主要内容,如果未能解决你的问题,请参考以下文章