Ansible 日常使用技巧(上)
Posted 51reboot运维开发
tags:
篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了Ansible 日常使用技巧(上)相关的知识,希望对你有一定的参考价值。
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。
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 参数值:代表了任务异步执行时轮询的时间间隔。
当 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]
默认情况下,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.241
172.16.60.245
172.16.60.246
127.0.0.1
[kevin_server]
172.16.60.246
127.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']}}"
当 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"对齐!!否则会报错!
在使用 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 kevin
Success
[root@242 ~]# /bin/bash /mnt/scripts/test.sh kevin234
Failed
现在要求:
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.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 [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.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 [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.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 [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 日常使用技巧(上)的主要内容,如果未能解决你的问题,请参考以下文章