Ansible 日常使用技巧 (下)

Posted 51reboot运维开发

tags:

篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了Ansible 日常使用技巧 (下)相关的知识,希望对你有一定的参考价值。

python自动化进阶课
K8s课程
golang 课程


接 


6
Ansible 之条件判断  [ when ]

在日常运维工作中,在有的时候 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.241172.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.ymlUsing /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)

[root@hostname ~]# 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;

[root@hostname ~]# 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.ymlUsing /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.ymlUsing /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.ymlUsing /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!


7
性能优化  [ 提升 ansible 执行效率 ]

最初,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.ymlUsing /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=0172.16.60.242 : ok=2 changed=1 unreachable=0 failed=0 skipped=0 rescued=0 ignored=0


现在关闭 gathering facts 功能

[root@hostname ~]# cat /etc/ansible/test.yml- 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.ymlUsing /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=0172.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 编辑配置文件,注释该选项来禁用它。

[root@webserver01 ~]# grep requiretty /etc/sudoers  # Defaults requiretty


优化三:开启 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执行效率。

[root@hostname ansible]# cat /etc/redhat-releaseCentOS Linux release 7.6.1810 (Core) [root@hostname ansible]# ssh -VOpenSSH_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@hostname ansible]# ps -ef|grep ssh|grep ansibleroot 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@hostname ansible]# netstat -anptu|grep ESTABLISHED|grep ssh|grep /roottcp 0 0 172.16.60.246:44430 172.16.60.242:22 ESTABLISHED 5617/ssh: /root/.antcp 0 0 172.16.60.246:43498 172.16.60.241:22 ESTABLISHED 5614/ssh: /root/.an [root@hostname 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

[root@hostname ~]# yum install -y python-keyczar


第二步:修改 ansible 服务端的 ansible.cfg 文件

[root@hostname ~]# vim /etc/ansible/ansible.cfg..........[accelerate]accelerate_port = 5099accelerate_timeout = 30accelerate_connect_timeout = 5.0


第三步:修改ansible服务端的ansible-playbook的剧本文件,加入 accelerate: true

[root@hostname ~]# cat /etc/ansible/test.yml- 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 = smartfact_caching_timeout = 86400fact_caching = jsonfilefact_caching_connection = /dev/shm/ansible_fact_cache


正常配置 palybook,不需要关闭 gathering facts 功能

[root@hostname ~]# cat /etc/ansible/test.yml- 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=0172.16.60.242 : ok=1 changed=1 unreachable=0 failed=0 skipped=0 rescued=0 ignored=0  real 0m1.102suser 0m0.879ssys 0m0.179s

如果去掉上面的 facts 缓存的四行配置,再次执行上面的 playbok,发现用时10s左右!!!

    

查看缓存文件:

[root@hostname ~]# ls /dev/shm/ansible_fact_cache/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 = smartfacts_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

[root@hostname ~]# systemctl start redis[root@hostname ~]# lsof -i:6379 COMMAND PID USER FD TYPE DEVICE SIZE/OFF NODE NAMEredis-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=0172.16.60.242 : ok=1 changed=1 unreachable=0 failed=0 skipped=0 rescued=0 ignored=0  real 0m1.132suser 0m0.909ssys 0m0.178s

需要注意:

在使用 redis 缓存后,如果出现异常(若未出现,请忽略):TypeError: the JSON object must be str, not 'bytes'。


解决办法:

[root@hostname ~]# find / -name ansible[root@hostname ~]# vim /usr/lib/python2.7/site-packages/ansible/plugins/cache/redis.py..........self._cache[key] = json.loads(value.decode('utf-8')) #修改为这个


查看 redis 存储情况

[root@hostname ~]# redis-cli127.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 的交互:

[root@hostname ~]# vim /root/.ssh/configUserKnownHostsFile /dev/nullConnectTimeout 15StrictHostKeyChecking no

或者直接 ssh 时增加一个参数

[root@hostname ~]# ssh -o StrictHostKeyChecking=no -p22 root@172.16.60.247


优化七: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/atotal 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 日常使用技巧 (下)的主要内容,如果未能解决你的问题,请参考以下文章

译文:18个实用的JavaScript代码片段,助你快速处理日常编程任务

ansible日常小结

ansible plugins简介

在ansible模板中使用动态组名称

02-日常管理脚本-ansible 程序断电修复;

运维自动化之 - ansible 批量主机管理