Ansible 在 Playbooks 使用 Handlers

2018-07-25 10:48 更新

Handlers 是我們在 Ansible Playbooks 里很常用來重開系統(tǒng)服務(wù) (Service) 的手法,大家可以在不少前人分享的 Playbooks 里看見它的蹤跡,這里凍仁將透過安裝 Nginx 的 Playbook 來介紹它。

automate_with_ansible_practice-20.jpg

Handlers 是什么?

Handler 本身是一種非同步的 callback function 1;在這里則是指關(guān)連于特定 tasks 的事件 (event) 觸發(fā)機(jī)制。當(dāng)這些特定的 tasks 狀態(tài)為被改變 (changed) 且都已被執(zhí)行時(shí),才會觸發(fā)一次 event。

以上圖為例,要觸發(fā) restart nginx 這個(gè) handler,需符合以下條件:

  1. modify index.html 或 turn server_tokens off 兩個(gè) tasks 中,至少有一個(gè)狀態(tài)為 changed
  2. 所有關(guān)連到 restart nginx handler 的 tasks 都已被執(zhí)行。 2

怎么使用 Handlers?

底下凍仁將通過部署 Nginx 的 Playbook 為例。

  1. 建立 ansible.cfg。

    $ vi ansible.cfg
    [defaults]
    
    hostfile = inventory
    remote_user = docker
    private_key_file = ~/.ssh/id_rsa
    host_key_checking = False
    retry_files_save_path = ./ansible-retry
    
  2. 建立 inventory file。

    $ vi inventory
    server1  ansible_ssh_host=192.168.1.104  ansible_ssh_port=2221
    
  3. 建立 setup_nginx.yml。

    $ vi setup_nginx.yml
    ---
    
    - name: setup the nginx
     hosts: all
     become: true
     vars:
       username: "ironman"
       mail: "chusiang (at) drx.tw"
       blog: "http://note.drx.tw"
    
     tasks:
       # 執(zhí)行 'apt-get update' 指令。
       - name: update apt repo cache
         apt: name=nginx update_cache=yes
    
       # 執(zhí)行 'apt-get install nginx' 指令。
       - name: install nginx with apt
         apt: name=nginx state=present
    
       # 于網(wǎng)頁根目錄 (DocumentRoot) 編輯 index.html。
       - name: modify index.html
         template: >
           src=templates/index.html.j2
           dest=/usr/share/nginx/html/index.html
           owner=www-data
           group=www-data
           mode="644"
           backup=yes
         notify: restart nginx
    
       # (security) 關(guān)閉 server_tokens:移除 server_tokens 前的 '#' 字元。
       - name: turn server_tokens off
         lineinfile: >
           dest=/etc/nginx/nginx.conf
           regexp="server_tokens off;"
           insertafter="# server_tokens off;"
           line="server_tokens off;"
           state=present
         notify: restart nginx
    
     # handlers 
     #
     # * 當(dāng)確認(rèn)事件有被觸發(fā)才會動(dòng)作。
     # * 一個(gè) handler 可被多個(gè) task 通知 (notify),并于 tasks 跑完才會執(zhí)行。
     handlers:
       # 執(zhí)行 'sudo service nginx restart' 指令。
       - name: restart nginx
         service: name=nginx enabled=yes state=restarted
    
     # post_tasks:
     #
     # 在 tasks 之后執(zhí)行的 tasks。
     post_tasks:
       # 檢查網(wǎng)頁內(nèi)容。
       - name: review http state
         command: "curl -s http://localhost"
         register: web_context
    
       # 印出檢查結(jié)果。
       - name: print http state
         debug: msg=
    
    # vim:ft=ansible :
    
    1. 在第 47 行里,我們建立了一個(gè) restart nginx handler。
    2. 在修改到 Nginx 設(shè)定檔的 tasks (modify index.htmlturn server_tokens off) 里,使用 notify 通知 handlers (restart nginx) 說這些 Tasks 要進(jìn)行關(guān)連。
    3. 最后在 post_tasks 里建了 2 個(gè) tasks,讓它們可以在一般的 tasks 結(jié)束后才執(zhí)行。
  4. 建立 Nginx vhost 的 template:請參考前一篇的Ansible 使用 Template 系統(tǒng),凍仁就不在此多加詳述。

    $ mkdir templates && vi templates/index.html.j2
    <!DOCTYPE html>
    <html>
     <head>
       <meta charset="UTF-8">
       <title>Day15 demo | automate-with-ansible</title>
     </head>
     <style type="text/css" media="all">
       body {
         font-size: x-large;
       }
     </style>
     <body>
       <p>
    <pre>[ @automate-with-ansible ~ ]$ hostname
    automate-with-ansible.drx.tw
    [ @automate-with-ansible ~ ]$ cowsay "This is a ansible-playbook demo for automate-with-ansible at 2016/12/15."
    _____________________________________
    / This is a ansible-playbook demo for \
    \ automate-with-ansible at 2016/12/15./
    -------------------------------------
           \   ^__^
            \  (oo)\_______
               (__)\       )\/\
                   ||----w |
                   ||     ||
    [ @automate-with-ansible ~ ]$
    [ @automate-with-ansible ~ ]$
    [ @automate-with-ansible ~ ]$ cat .profile
    - 
    - </pre>
       </p>
     </body>
    </html>
    
    • 在這份 index.html.j2 里,我們用了 usernamemail 和 blog 三個(gè)變數(shù),其值會從 setup_nginx.yml 中代入。
  5. 執(zhí)行 Playbook。

    2016-12-15-ansible-handlers.gif

    • 試著多跑幾次,就會發(fā)現(xiàn)當(dāng) modify index.html 和 turn server_tokens off tasks 的狀態(tài)不為 changed 時(shí),該 handler 不會被觸發(fā)的差異。
    • 在此例中,我們可以借由修改 Playbook 里的變數(shù) (vars) 來重復(fù)觸發(fā) handler,例如把 username從 ironman 修改成 root。

后話

雖然我們可以在 tasks 的最后加個(gè) task 來重開 web service,可當(dāng)與 web service 相關(guān)的 tasks 的狀態(tài)皆為 ok 時(shí),這種寫法會讓 web service 再次被重開。

通過 Handlers 我們可以只在需要時(shí)重開一次,進(jìn)而減少服務(wù)中斷的時(shí)間。

相關(guān)連結(jié)

1. 維基百科對于 Handler 的解釋為 An asynchronous callback (computer programming) subroutine in computing,詳情請參考 Handler | Wikipedia 一文。 ?
2. 一般都會用 Tasks 通知 (notify) Handlers 來述敘兩者的關(guān)系,但凍仁比較喜歡用 Tasks 關(guān)連于 Handlers 的說法。 ?


以上內(nèi)容是否對您有幫助:
在線筆記
App下載
App下載

掃描二維碼

下載編程獅App

公眾號
微信公眾號

編程獅公眾號