聊聊Ansible Playbook中的Handler

Ansible是一个系列文章,我会尽量以通俗易懂、诙谐幽默的总结方式给大家呈现这些枯燥的知识点,让学习变的有趣一些。
Ansible系列博文直达链接:Ansible入门系列

前言

在之前的这篇《初窥Ansible playbook》文章中,有说到这个handler,细心的朋友可能就对这个handler很好奇,这到底是个什么东西呢?在Ansible中,我们又是如何使用这个handler呢?在使用的过程中又有哪些事项需要特别注意的呢?这篇文章我就来对这个handler进行详细的总结,让大家在日后的工作中能够明明白白、放放心心的使用handler

什么是handler

通过这么多年的编程经验,我们知道基本上每个主流的编程框架、语言都有Event机制,Ansible作为自动化运维界最亮的仔,它也不例外,这里要说的handler就是Playbook中的Event。将handler概念映射成Event,这样大家应该就能恍然大悟了。但是在Ansible中,它的handler还有一些特别的地方。

在Playbook中Handlers里面的每一个handler都是对模块的一次调用。而handler与任务不同,任务会默认的按照我们定义的顺序执行,handler则不一样,它需要在任务中被明确调用,才有可能被调用。注意这里的有可能,也就是说也有可能你明确调用了,但是handler也不一定能够被触发调用,这又是为什么呢?且听我慢慢说来!

前面有说到过,任务表中的任务都是有状态的,也就是任务执行后的结果:changed或者ok。在Ansible中,只有在任务的执行状态为changed时,才会执行该任务调用的handler。这也是handler与普通的Event机制不同的地方。

handler应用场景

一个东西存在就必定有它存在的场景,那我们在什么情况下使用handler呢?下面我就来说一个特别现实的场景。

在我们的生产环境中是通过Nginx来做负载均衡的,有的时候我们修改了Nginx的配置文件,然后就需要从Ansible管理主机分发到被管理的Nginx主机上,拷贝成功后,要执行nginx -s reload命令。在这个操作中有一个前提是必须要配置文件拷贝成功后才能执行nginx -s reload命令。像这样的应用场景,重启Nginx就可以设计成一个handler。

一个handler最多只执行一次,并且在所有的任务都执行完成之后再执行;如果有多个任务调用同一个handler,那么也只执行一次,这个也是同普通的Event机制的一个不同点。下面通过一个简单的例子来进行说明:

---

- hosts: server1

  tasks:
    - name: CopyFile1
      copy: 
        src: /home/jelly/file1.log
        dest: /home/test1/file1.log
      notify:
        - handler1

    - name: CopyFile2
      copy:
        src: /home/jelly/file2.log
        dest: /home/test1/file2.log
      notify:
        - handler1

  handlers:
    - name: handler1
      debug: msg="Call handler1"

一开始,在被管理主机上是没有文件的,我们执行上面的YAML脚本,会输出以下日志内容:

[jelly@localhost yaml]$ ansible-playbook handlerDemo1.yaml 

PLAY [server1] ***************************************

TASK [Gathering Facts] *******************************
ok: [192.168.1.3]

TASK [CopyFile1] *************************************
changed: [192.168.1.3]

TASK [CopyFile2] *************************************
changed: [192.168.1.3]

RUNNING HANDLER [handler1] ***************************
ok: [192.168.1.3] => {
    "msg": "Call handler1"
}

PLAY RECAP *******************************************
192.168.1.3                : ok=4    changed=2    unreachable=0    failed=0

可以看到,handler1只被执行了一次。第一次执行后,文件已经被分发过去了,当我们再次执行这个YAML脚本时,changed状态应该为0,此时handler1就不会被执行。输出日志就是这个样子:

[jelly@localhost yaml]$ ansible-playbook handlerDemo1.yaml 

PLAY [server1] ***************************************

TASK [Gathering Facts] *******************************
ok: [192.168.1.3]

TASK [CopyFile1] *************************************
ok: [192.168.1.3]

TASK [CopyFile2] *************************************
ok: [192.168.1.3]

PLAY RECAP *******************************************
192.168.1.3                : ok=3    changed=0    unreachable=0    failed=0  

handler执行顺序

除了上面说到的触发场景和执行次数需要我们特殊关注外,还有这里要说的执行顺序,handler的执行顺序也是一个“奇葩”点。

handler是按照定义的顺序执行的,而不是按照在任务中的调用顺序执行的。

上面的话有点绕口,下面我通过一个例子来说明。

---

- hosts: server1

  tasks:
    - name: CopyFile1
      copy: 
        src: /home/jelly/file1.log
        dest: /home/test1/file1.log
      notify:
        - handler3

    - name: CopyFile2
      copy:
        src: /home/jelly/file2.log
        dest: /home/test1/file2.log
      notify:
        - handler2

    - name: CopyFile3
      copy:
        src: /home/jelly/file3.log
        dest: /home/test1/file3.log
      notify:
        - handler1

  handlers:
    - name: handler1
      debug: msg="Call handler1"

    - name: handler2
      debug: msg="Call handler2"

    - name: handler3
      debug: msg="Call handler3"

从上面的YAML脚本可以看到,我们调用handler的顺序是3->2->1,而在handlers中定义的顺序是1->2->3,最终handler的执行顺序是1->2->3,同定义顺序保持一致的。执行输出日志如下:

[jelly@localhost yaml]$ ansible-playbook handlerDemo3.yaml

PLAY [server1] ***************************************

TASK [Gathering Facts] *******************************
ok: [192.168.1.3]

TASK [CopyFile1] *************************************
changed: [192.168.1.3]

TASK [CopyFile2] *************************************
changed: [192.168.1.3]

TASK [CopyFile3] *************************************
changed: [192.168.1.3]

RUNNING HANDLER [handler1] ***************************
ok: [192.168.1.3] => {
    "msg": "Call handler1"
}

RUNNING HANDLER [handler2] ***************************
ok: [192.168.1.3] => {
    "msg": "Call handler2"
}

RUNNING HANDLER [handler3] ***************************
ok: [192.168.1.3] => {
    "msg": "Call handler3"
}

PLAY RECAP *******************************************
192.168.1.3                : ok=7    changed=3    unreachable=0    failed=0  

触发场景、执行次数和执行顺序这三个“奇葩”点,大家可得牢牢记住喽!!!

总结

断断续续把这个知识点总结完了,关于Ansible handler这个知识点,别看它看起来很简单,就那么点东西,但是在实际的工作中作用却是非常大的,以后大家在读别人的YAML脚本的时候,就能看到更多handler的应用场景了。还是那句话,小工具,大作为!

果冻想,认真玩技术的地方。

2019年10月6日,于内蒙古呼和浩特。
关注公众号

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章