聊聊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日,於內蒙古呼和浩特。
關注公衆號

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