Ansible 日常使用技巧(上)

Posted 51reboot运维开发

tags:

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

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


Ansible 默认只会创建5个进程并发执行任务,所以一次任务只能同时控制 5 台机器执行。如果有大量的机器需要控制,例如 20 台,Ansible 执行一个任务时会先在其中 5 台上执行,执行成功后再执行下一批5台,直到全部机器执行完毕。使用-f 选项可以指定进程数,指定的进程数量多一些,不仅会实现全并发,对异步的轮训 poll 也会有正面影响。


Ansible 默认是同步阻塞模式它会等待所有的机器都执行完毕才会在前台返回。Ansible 可以采取异步执行模式。异步模式下,Ansible 会将节点的任务丢在后台,每台被控制的机器都有一个 job_id,Ansible 会根据这个 job_id 去轮训该机器上任务的执行情况,例如某机器上此任务中的某一个阶段是否完成,是否进入下一个阶段等。即使任务早就结束了,但只有轮训检查到任务结束后才认为该 job 结束。Ansible 可以指定任务检查的时间间隔,默认是10秒。除非指定任务检查的间隔为0,否则会等待所有任务都完成后,Ansible 端才会释放占用的 shell。如果指定时间间隔为0,则 Ansible 会立即返回(至少得连接上目标主机,任务发布成功之后立即返回),并不会去检查它的任务进度。


Ansible 的同步模式与异步模式


同步模式:如果节点数太多,ansible 无法一次在所有远程节点上执行任务,那么将先在一部分节点上执行一个任务(每一批节点的数量取决于 fork 进程数量,默认为5个,可设置),直到这一批所有节点上该任务完全执行完毕才会接入下一个批节点,直到所有节点将该任务都执行完毕,然后重新回到第一批节点开始执行第二个任务。依次类推,直到所有节点执行完所有任务,ansible 端才会释放 shell。这是默认同步模式,也就是说在未执行完毕时,ansible 是占用当前 shell 的,任务执行完后,释放 shell 了才可以输入其他命令做其他动作。


异步模式:假如 fork 控制的并发进程数为5,远程控制节点为24个,则   ansible 一开始会将 5 个节点的任务扔在后台,并每隔一段时间去检查这些节点的任务完成情况,当某节点完成不会立即返回,而是继续等待直到5个进程都空闲了,才会将这5个节点的结果返回给  ansible 端,ansible 会继续将下一批5个节点的任务扔在后台并每隔一段时间进行检查,依次类推,直到完成所有任务。


在异步模式下,如果设置的检查时间间隔为0,在将每一批节点的任务丢到后台后都会立即返回 ansible,并立即将下一批节点的任务丢到后台,直到所有任务都丢到后台完后,才返回 ansible 端,ansible 才会立即释放占用的 shell。即此时 ansible 是不会管各个节点任务执行情况的,不管执行成功或失败。因此在轮训检查时间内,ansible 仍然正在运行(尽管某批任务已经被放到后台执行了),当前 shell 进程仍被占用处于睡眠状态,只有指定的检查时间间隔为0,才会尽快将所有任务放到后台并释放 shell。



01
Ansible的异步和轮询  [ async、poll ]

Ansible 有时候要执行等待时间很长的操作,这个操作可能要持续很长时间,设置超过 ssh 的 timeout。这种情况下可以选择在 step 中指定 async 和 poll 来实现异步操作。其中 async表示这个 step 的最长等待时长, 如果设置为0, 表示一直等待下去直到动作完成;poll表示检查step操作结果的间隔时长。


ansible 默认的清单文件是 /etc/ansible/hosts,也就是 ansible 和 ansible-ploybook 执行时默认读的清单文件。这个可以自行定义。

[root@hostname ~]# cat /etc/ansible/ansible.cfg|grep inventory#inventory = /etc/ansible/hosts
[root@hostname ~]# cat /etc/ansible/hosts|tail -2 [test_server] #组名最好不要使用"-",可以使用"_"172.16.60.241


1)先来看下面初始配置

[root@hostname ~]# cat /etc/ansible/test.yml- hosts : test_server tasks : - name : ansible-test shell : sleep 10 #async表示上述shell命令的等待时间,设置为0时会一直等待命令结束 async : 5 #poll表示检查step操作结果的间隔时长,设置为0表示 不用等待结果,继续做下面的操作,我们可以在下面的step中来验证这个命令是否成功执行. poll : 2


执行下看看是否成功:

[root@hostname ~]# ansible-playbook /etc/ansible/test.yml
PLAY [test_server] *******************************************************************************************************************************
TASK [Gathering Facts] ***************************************************************************************************************************ok: [172.16.60.241]
TASK [ansible-test] ******************************************************************************************************************************fatal: [172.16.60.241]: FAILED! => {"changed": false, "msg": "async task did not complete within the requested time - 5s"}
PLAY RECAP ***************************************************************************************************************************************172.16.60.241 : ok=1 changed=0 unreachable=0 failed=1 skipped=0 rescued=0 ignored=0

如上,这个 step 失败, 因为 ansible 的任务(就是上面配置中的shell动作)操作时间(10s)超过了最大等待时长(5s)

 

2)如果将上面的 async 异步等待时间设置为大于 10s,比如12s,则执行就成功了!

[root@hostname ~]# cat /etc/ansible/test.yml- hosts : test_server tasks : - name : ansible-test shell : sleep 10 #async表示上述shell命令的等待时间,设置为0时会一直等待命令结束 async : 12 #poll表示检查step操作结果的间隔时长,设置为0表示 不用等待结果,继续做下面的操作,我们可以在下面的step中来验证这个命令是否成功执行. poll : 2
[root@hostname ~]# ansible-playbook /etc/ansible/test.yml
PLAY [test_server] *******************************************************************************************************************************
TASK [Gathering Facts] ***************************************************************************************************************************ok: [172.16.60.241]
TASK [ansible-test] ******************************************************************************************************************************changed: [172.16.60.241]
PLAY RECAP ***************************************************************************************************************************************172.16.60.241 : ok=2 changed=1 unreachable=0 failed=0 skipped=0 rescued=0 ignored=0

这时候就不怕任务超时了。可以执行一个12s 的任务(大于上面shell执行的时间)。另外,如果 poll 为0,就相当于一个不关心结果的任务。

 

3)或者将上面的 poll 数值设置为0,即不用等待 ansible 任务执行的结果,立即执行下一个 step。

即只需要将任务命令推送到 ansible 客户机上,不需要等待任务执行完成就立即执行下一个step。


[root@hostname ~]# cat /etc/ansible/test.yml- hosts : test_server tasks : - name : ansible-test shell : sleep 10 #async表示上述shell命令的等待时间,设置为0时会一直等待命令结束 async : 5 #poll表示检查step操作结果的间隔时长,设置为0表示 不用等待结果,继续做下面的操作,我们可以在下面的step中来验证这个命令是否成功执行. poll : 0
[root@hostname ~]# ansible-playbook /etc/ansible/test.yml
PLAY [test_server] *******************************************************************************************************************************
TASK [Gathering Facts] ***************************************************************************************************************************ok: [172.16.60.241]
TASK [ansible-test] ******************************************************************************************************************************changed: [172.16.60.241]
PLAY RECAP ***************************************************************************************************************************************172.16.60.241 : ok=2 changed=1 unreachable=0 failed=0 skipped=0 rescued=0 ignored=0


4)如果还想要更方便地看轮询结果,ansible还提供了这个模块async_status。

[root@hostname ~]# cat /etc/ansible/test.yml - hosts : test_server tasks : - name : ansible-test shell : sleep 3 async : 8 poll : 2 register: kevin_result
- name: 'check ansible-test task polling results ' async_status: jid={{ kevin_result.ansible_job_id }} register: job_result until: job_result.finished retries: 10
[root@hostname ~]# ansible-playbook /etc/ansible/test.yml
PLAY [test_server] *******************************************************************************************************************************
TASK [Gathering Facts] ***************************************************************************************************************************ok: [172.16.60.241]
TASK [ansible-test] ******************************************************************************************************************************changed: [172.16.60.241]
TASK [check ansible-test task polling results] ***************************************************************************************************changed: [172.16.60.241]
PLAY RECAP ***************************************************************************************************************************************172.16.60.241 : ok=3 changed=2 unreachable=0 failed=0 skipped=0 rescued=0 ignored=0

第一个job 执行异步任务sleep,并且注册了一个名字叫 kevin-result 的register 变量,用于提供给第二个 job 作为轮询对象,并且它自己 poll 设为2 (即自己轮询2次)。register 用于在 ansible 的 playbook 中 task 之间的相互传递变量,register 这个功能非常有用。当我们需要判断对执行了某个操作或者某个命令后,如何做相应的响应处理(执行其他 ansible 语句),则一般会用到 register 。


until 表示循环。

 

第二个 job 使用 async_status 模块,进行轮询并返回轮询结果。准备检查10次。


async 参数值:代表了这个任务执行时间的上限值。即任务执行所用时间如果超出这个时间,则认为任务失败。此参数若未设置,则为同步执行。
poll 参数值:代表了任务异步执行时轮询的时间间隔。


02
Ansible的并发限制  [ serial、max_fail_percentage ]

当 ansible 清单文件里设置的组里有很多机器,可以限制一下 ansible 任务的并发。ansible 的并发功能可以在 ansible.cfg 里修改配置,也可以在playbook 中限制服务端的并发数量,这是 ansible 经常用到的一个关键功能。ansible 默认情况下只会创建 5个进程,所以一次任务只能同时控制 5 台机器执行。如果有大量的机器需要控制,或者希望减少进程数,那就可以采取异步执行(async),ansible的模块可以把 task 放进后台,然后轮询它(poll)。


使用 async 和 poll 这两个关键字便可以并行运行一个任务,即在所有机器上一次性运行。async 这个关键字会触发 ansible 并行运作任务,async 的值是  ansible 等待运行这个任务的最大超时值(如果执行超时任务会强制中断导致失败),而 poll 就是 ansible 检查这个任务是否完成的频率时间。


1) serial 参数设置并发数

一般情况下, ansible 会同时在所有服务器上执行用户定义的操作, 但是用户可以通过 serial 参数来定义同时可以在多少太机器上执行操作。

[root@hostname ~]# cat /etc/ansible/test.yml- hosts : test_server serial: 3
tasks : - name: Install telnet yum: name=telnet state=installed

即 test_server 组内的 3 台机器完全执行完成 play 后, 其他机器才能开始执行。

 

接着看下面的配置

[root@hostname ~]# cat /etc/ansible/test.yml- hosts : all serial: 7
tasks : - name: Install telnet yum: name=telnet state=installed
- name : Run Serverstart.sh command : /bin/bash /opt/scripts/Serverstart.sh async : 300 poll : 10 register: kevin_result

如上配置,发现当 ansible 配置控制超过 5 台机器时,上面 ansible 中:

a)yum 模块会先在5台机器上跑,完成后再继续剩余2台的机器;

b)command 模块的任务会一次性在所有机器上都执行了,然后监听它的回调结果;

 

这里需要注意下面两种情况

a)情况一:设置 poll=0

如果上面 command 模块是控制机器开启一个进程放到后台,那就不需要检查这个任务是否完成了,只需要继续其他的动作,

最后再使用 wait_for 这个模块去检查之前的进程是否按预期中开启了便可。

这时只需要把 poll 这个值设置为 0, 便可以按上面的要求配置 ansible 不等待job 的完成。


b)情况二:设置 async=0

如果有一种需求是有一个 task 它是需要运行很长的时间,那就需要设置一直等待这个 job 完成。

这个时候只需要把 async 的值设成 0 便可。

 

简单总结下,适合使用到 ansible 的 polling 特性的场景

- 有一个 task 需要运行很长的时间,这个 task 很可能会达到 timeout;

- 有一个任务需要在大量的机器上面运行;

- 有一个任务是不需要等待它完成的;

 

不适合使用 polling 特性的场景

- task 任务是需要运行完后才能继续另外的任务的;

- task 任务能很快的完成;

 

2) max_fail_percentage:最大失败百分比


默认情况下, 只要 ansible 的 group 中还有 server 没有失败, ansible就是继续执行 tasks。实际上, 用户可以通过 max_fail_percentage(最大失败百分比)来限制 ansible 的并发执行。


只要超过 max_fail_percentage 的 server 失败, ansible 就可以中止 tasks 的执行。serial 参数在 ansible-1.8 以后就开始支持百分比功能了!!

 

试想一下如果 group 组里有 200 台机器,那么如果使用 serial 来限制并发数量,比如设置 serial=10,意思就是一次只执行 10 台,一直到 200 台完成。

只要组内还有 server 没有失败, ansible 就是继续执行 tasks。这样就显得效率很低了,很不方便!这时就可以使用类似控制流的 max_fail_percentage 功能了!!

[root@hostname ~]# cat /etc/ansible/test.yml- hosts : all max_fail_percentage: 30 serial: 10
tasks : - name: Install telnet yum: name=telnet state=installed
- name : Run Serverstart.sh command : /bin/bash /opt/scripts/Serverstart.sh async : 300 poll : 10 register: kevin_result

如上配置,即10 台机器里有30% 的机器执行 yum 模块的 task 任务失败,那么就终止这个10 台机器的 task 任务的执行,接着执行下一组 10 台机器的 task 任务,这样效果就很棒了。

 

温馨提示:

实际失败机器必须大于这个百分比时, tasks 任务才会被中止;如果等于这个百分比时,task 任务是不会被终止的!


踩坑经验:Ansible 并发失败(fork=100. 但是真正执行 playbook 时并没有实现并发)

[root@hostname ~]# cd /usr/lib/python2.7/site-packages/ansible/[root@hostname ansible]# find . -name ssh.py./plugins/connection/ssh.py
[root@hostname ansible]# vim plugins/connection/ssh.py.................. if C.HOST_KEY_CHECKING and not_in_host_file: # lock around the initial SSH connectivity so the user prompt about whether to add # the host to known hosts is not intermingled with multiprocess output. fcntl.lockf(self.runner.process_lockfile, fcntl.LOCK_EX) fcntl.lockf(self.runner.output_lockfile, fcntl.LOCK_EX)
# create process (p, stdin) = self._run(ssh_cmd, in_data)..................


通过以上文件代码可以看出:

如果 ansible 配置"HOST_KEY_CHECKING=True", 并且 ansible 客户机信息没有在ansible服务端的~/.ssh/known_hosts里面, 一个进程就会锁死~/.ssh/known_hosts 文件。

这样 ansible 就不能实现并发!

 

解决方案:

在 ansible 服务端的/etc/ansible/ansible.cfg文件里配置"host_key_checking = False"    [其实 ansible.cfg 文件里该项默认配置的就是 False]


03
Ansible的任务委托  [ delegate_to、delegate_facts、run_once ]

默认情况下,ansible 的所有任务都是在指定的机器上运行的。当在一个独立的群集环境中配置时,只是想操作其中的某一台主机,或者在特定的主机上运行 task 任务,此时就需要用到 ansible 的任务委托功能。使用delegate_to 关键字可以配置 task 任务在指定的机器上执行,就是说其他的 task 任务还是在 hosts 关键字配置的机器上运行,到了这个关键字所在的任务时,就使用委托的机器运行。



1)委托

通过"delegate_to", ansible 可以把某一个 task 任务放在委托的机器上执行。即在指定的组内的某一台或多台机器上执行 task 任务。

[root@hostname ~]# cat /etc/ansible/test.yml- hosts : test_server serial: 10
tasks : - name: test-haha shell: echo "test" > /root/test.list delegate_to: 172.16.60.245

则上面的shell模块的task任务只会在172.16.60.245这台节点上执行,test_server 组内其他的机器不会执行 shell 任务。


如果 "delegate_to: 127.0.0.1" 则可以用 local_action 来代替。即下面两个配置效果是一样的!!

[root@hostname ~]# cat /etc/ansible/test.yml- hosts : test_server serial: 10
tasks : - name: test-haha shell: echo "test" > /root/test.list delegate_to: 127.0.0.1
[root@hostname ~]# cat /etc/ansible/test.yml- hosts : test_server serial: 10
tasks : - name: test-haha local_action: shell echo "test" > /root/test.list


如果设置了多个 delegate_to,则执行时只会匹配最下面那个。

例如下面配置中,只会执行"delegate_to: 172.16.60.245", 上面那个"delegate_to: 172.16.60.241"就会被忽略了。

[root@hostname ansible]# cat /etc/ansible/test.yml- hosts : all serial: 10
tasks : - name: test-haha shell: echo "test" > /root/test.list delegate_to: 172.16.60.241 delegate_to: 172.16.60.245

delegate_to 默认后面只能跟一个主机 ip,不能跟多个主机 ip。即默认委托到单个主机。

如果有多个 ip 需要委托,则可以将这些 ip 重新放一个 group,然后delegate_to 委托给 group 组。

delegate_to 委托到组的方式:通过 items 变量方式!!!


[root@hostname ansible]# cat /etc/ansible/hosts |tail -8[test_server]172.16.60.241172.16.60.245172.16.60.246127.0.0.1
[kevin_server]172.16.60.246127.0.0.1
[root@hostname ansible]# cat /etc/ansible/test.yml- hosts: all tasks: - name: test-haha shell: echo "test" > /root/test.list delegate_to: "{{item}}" with_items: "{{groups['kevin_server']}}"

即将 shell 这个 task 任务委托给 kevin_server 组内的机器执行。

  

2)委托者的 facts


默认情况下, ansible 委托任务的 facts 是 inventory_hostname 中主机的 facts, 而不是被委托机器的 facts。

 

a) delegate_facts

在 ansible 2.0 中, 通过设置"delegate_facts: True"可以让 task 任务去收集被委托机器的 facts。

[root@hostname ~]# cat /etc/ansible/test.yml- hosts: test_server tasks: - name: test-haha shell: echo "test" > /root/test.list delegate_to: "{{item}}" delegate_facts: True with_items: "{{groups['kevin_server']}}"

如上配置,表示会收集 kevin_server 的 facts 并分配给这些机器, 而不会去收集test_server 的 facts

 

b)RUN ONCE

通过设置"run_once: true"来指定该 task 只能在委托的某一台机器或委托的组内机器上执行一次!!可以和 delegate_to 结合使用。

如果没有 delegate_to, 那么这个 task 默认就会在第一台机器上执行!!!

[root@hostname ~]# cat /etc/ansible/test.yml- hosts: test_server tasks: - name: test-haha shell: echo "test" > /root/test.list delegate_to: "{{item}}" run_once: true delegate_facts: True with_items: "{{groups['kevin_server']}}"


04
Ansible的任务暂停  [ local_action、wait_for ]

当 Ansible 一些任务的运行需要等到一些状态的恢复,比如某一台主机或者应用刚刚重启,需要等待其某个端口开启,这个时候就需要用到 Ansible 的任务暂停功能。Ansible 任务的暂停操作是通过local_action配合wait_for模块来完成的。

[root@hostname ~]# cat /etc/ansible/test.yml- hosts: test_server remote_user: root gather_facts: no
tasks: - name: kevin_test local_action: module: wait_for #模块名字 port: 2379 host: 172.16.60.241 delay: 10 timeout: 300 state: started


使用 local_action 配合 wait_for 模块来完成任务的暂停操作。

上面配置说明 kevin_test 任务每隔 10s 检查指定主机上的 2379 端口是否开启,如果操作 300s,2379 端口任未开启,将返回失败信息。

 

上面 host 指定了一台机器,如果是需要指定多台机器呢?

可以将执行的多台机器放在一台新 group 内,然后通过变量去指定group。

[root@hostname ~]# cat /etc/ansible/test.yml - hosts: test_server remote_user: root gather_facts: no
tasks: - name: kevin_test local_action: module: wait_for port: 2379 host: "{{item}}" delay: 10 timeout: 300 state: started with_items: "{{groups['kevin_server']}}"


如上面配置,每间隔10s检查指定的 kevin_server 组内的主机的 2379 端口是否开启,如果操作 300s,2379 端口没开启,则返回失败信息。

注意:上面的"with_items"这一项配置要和"local_action"对齐!!否则会报错!


05
Ansible如何判断并中断执行  [ when、fail ]

在使用 ansible-playbook 在执行一个脚本时,如何根据脚本返回的内容判断是否继续往下执行还是中断执行?查询官网可以发现使用 register 寄存器可以实现记录脚本输出,并且使用 when+fail 模块来判断是否往下继续执行或者中断。

远端机器172.16.60.242有如下脚本:[root@242 ~]# cat /mnt/scripts/test.sh#!/bin/bash
TEXT=$1
if [ $1 == "kevin" ];then echo "Success"else echo "Failed"fi
[root@242 ~]# /bin/bash /mnt/scripts/test.sh kevinSuccess[root@242 ~]# /bin/bash /mnt/scripts/test.sh kevin234Failed


现在要求:

a)通过 ansible 执行 172.16.60.242 的 test.sh 脚本,当脚本返回 Success时,在 172.16.60.242 机器上创建一个目录 /opt/kevin。

b)通过 ansible 执行 172.16.60.242 的 test.sh 脚本,当脚本返回 Failed  时,则中断执行。

  

在 ansible 服务端配置 yml 文件,相关配置过程如下:

1)如下配置,将 command 模块的 task 任务委托给 kevin_server 组内的172.16.60.242 机器执行。先使用了 register 寄存器,具体寄存了什么内容,可以使用 -v 参数来查看输出

[root@hostname ~]# cat /etc/ansible/test.yml- hosts: kevin_server remote_user: root
tasks : - name: an_bo command: /bin/bash /mnt/scripts/test.sh kevin delegate_to: 172.16.60.242 register: result
[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 [an_bo] *************************************************************************************************************************************changed: [172.16.60.242 -> 172.16.60.242] => {"changed": true, "cmd": ["/bin/bash", "/mnt/scripts/test.sh", "kevin"], "delta": "0:00:00.004078","end": "2019-10-11 15:35:49.850430", "rc": 0, "start": "2019-10-11 15:35:49.846352", "stderr": "", "stderr_lines": [], "stdout": "Success","stdout_lines": ["Success"]}changed: [172.16.60.241 -> 172.16.60.242] => {"changed": true, "cmd": ["/bin/bash", "/mnt/scripts/test.sh", "kevin"], "delta": "0:00:00.004502","end": "2019-10-11 15:35:49.852445", "rc": 0, "start": "2019-10-11 15:35:49.847943", "stderr": "", "stderr_lines": [], "stdout": "Success","stdout_lines": ["Success"]}
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

可以看出:

register 保存的信息就是上面执行结果中 "=>" 后面的字典信息,信息保存在   result 变量中。

并且看到 "stdout" 就是脚本的标准输出信息,这时可以使用 "when" 来判断是否执行或者跳过。

 

2)使用"when"来判断是否执行或者跳过。

[root@hostname ~]# cat /etc/ansible/test.yml- hosts: kevin_server remote_user: root
tasks : - name: an_bo command: /bin/bash /mnt/scripts/test.sh kevin delegate_to: 172.16.60.242 register: result
- name: ru_bo file: path=/opt/kevin state=directory delegate_to: 172.16.60.242 when: result.stdout == 'Success'


查看执行结果:

[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 [an_bo] *************************************************************************************************************************************changed: [172.16.60.242 -> 172.16.60.242] => {"changed": true, "cmd": ["/bin/bash", "/mnt/scripts/test.sh", "kevin"], "delta": "0:00:00.002337", "end": "2019-10-11 15:48:20.427582", "rc": 0, "start": "2019-10-11 15:48:20.425245", "stderr": "", "stderr_lines": [], "stdout": "Success", "stdout_lines": ["Success"]}changed: [172.16.60.241 -> 172.16.60.242] => {"changed": true, "cmd": ["/bin/bash", "/mnt/scripts/test.sh", "kevin"], "delta": "0:00:00.002579", "end": "2019-10-11 15:48:20.425082", "rc": 0, "start": "2019-10-11 15:48:20.422503", "stderr": "", "stderr_lines": [], "stdout": "Success", "stdout_lines": ["Success"]}
TASK [ru_bo] *************************************************************************************************************************************changed: [172.16.60.241 -> 172.16.60.242] => {"changed": true, "gid": 0, "group": "root", "mode": "0755", "owner": "root", "path": "/opt/kevin", "size": 6, "state": "directory", "uid": 0}ok: [172.16.60.242 -> 172.16.60.242] => {"changed": false, "gid": 0, "group": "root", "mode": "0755", "owner": "root", "path": "/opt/kevin", "size": 6, "state": "directory", "uid": 0}
PLAY RECAP ***************************************************************************************************************************************172.16.60.241 : ok=3 changed=2 unreachable=0 failed=0 skipped=0 rescued=0 ignored=0 172.16.60.242 : ok=3 changed=1 unreachable=0 failed=0 skipped=0 rescued=0 ignored=0


可以发现,当脚本返回 Success 时,已经在172.16.60.242机器上创建一个目录 /opt/kevin。

 

3)现在将脚本输出内容修改为"Failed" (即执行脚本时,$1为非 kevin 字符)

[root@hostname ~]# cat /etc/ansible/test.yml- hosts: kevin_server remote_user: root
tasks : - name: an_bo command: /bin/bash /mnt/scripts/test.sh shibo delegate_to: 172.16.60.242 register: result
- name: if stdout 'Failed',Interrupt execution delegate_to: 172.16.60.242 fail: msg="Check Failed" when: result.stdout == 'Failed'
- name: ru_bo file: path=/opt/kevin state=directory delegate_to: 172.16.60.242 when: result.stdout == 'Success'


查看执行结果:

[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 [an_bo] *************************************************************************************************************************************changed: [172.16.60.241 -> 172.16.60.242] => {"changed": true, "cmd": ["/bin/bash", "/mnt/scripts/test.sh", "shibo"], "delta": "0:00:00.002767", "end": "2019-10-11 15:57:56.049142", "rc": 0, "start": "2019-10-11 15:57:56.046375", "stderr": "", "stderr_lines": [], "stdout": "Failed", "stdout_lines": ["Failed"]}changed: [172.16.60.242 -> 172.16.60.242] => {"changed": true, "cmd": ["/bin/bash", "/mnt/scripts/test.sh", "shibo"], "delta": "0:00:00.002698", "end": "2019-10-11 15:57:56.051455", "rc": 0, "start": "2019-10-11 15:57:56.048757", "stderr": "", "stderr_lines": [], "stdout": "Failed", "stdout_lines": ["Failed"]}
TASK [if stdout 'Failed',Interrupt execution] ****************************************************************************************************fatal: [172.16.60.241 -> 172.16.60.242]: FAILED! => {"changed": false, "msg": "Check Failed"}fatal: [172.16.60.242 -> 172.16.60.242]: FAILED! => {"changed": false, "msg": "Check 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


可以看出:

playbook 运行到第二个 task 时就会报错并抛出 msg!根据第二个 task 任务,脚本输出结果为"Failed",直接中断任务执行。那么第三个task任务就不会被执行了。

 

注意:

result 寄存器中的数据都可以拿来使用,如"rc","stderr"等。

当然也有很多种方法,文中的"Failed"是严格匹配,也可以使用模糊查找,如"result.stdout.find('Failed') != -1"也可以达到相同的效果

[root@hostname ~]# cat /etc/ansible/test.yml - hosts: kevin_server remote_user: root
tasks : - name: an_bo command: /bin/bash /mnt/scripts/test.sh shibo delegate_to: 172.16.60.242 register: result
- name: if stdout 'Failed',Interrupt execution delegate_to: 172.16.60.242 fail: msg="Check Failed" when: result.stdout.find('Failed') != -1 # 等同于 when: result.stdout == 'Failed'
- name: ru_bo file: path=/opt/kevin state=directory delegate_to: 172.16.60.242 when: result.stdout == 'Success'

 出处|http://1t.click/aFSZ



内容太多了,我们下节继续发

未完待续......


后续有性能优化  [ 提升ansible执行效率 ]


以上是关于Ansible 日常使用技巧(上)的主要内容,如果未能解决你的问题,请参考以下文章

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

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

ansible日常小结

ansible plugins简介

Ansible学习 安装

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