Handlers 是我們在 Ansible Playbooks 裡很常用來重開系統服務 (Service) 的手法,大家可以在不少前人分享的 Playbooks 裡看見它的蹤跡,這裡凍仁將透過安裝 Nginx 的 Playbook 來介紹它。
Handler 本身是一種非同步的 callback function 1;在這裡則是指關連於特定 tasks 的事件 (event) 觸發機制。當這些特定的 tasks 狀態為被改變 (changed) 且都已被執行時,才會觸發一次 event。
以上圖為例,要觸發 restart nginx
這個 handler,需符合以下條件:
modify index.html
或turn server_tokens off
兩個 tasks 中,至少有一個狀態為 changed。- 所有關連到
restart nginx
handler 的 tasks 都已被執行。 2
底下凍仁將透過部署 Nginx 的 Playbook 為例。
-
建立 ansible.cfg。
$ vi ansible.cfg [defaults] inventory = inventory remote_user = docker private_key_file = ~/.ssh/id_rsa host_key_checking = False retry_files_save_path = ./ansible-retry
-
建立 inventory file。
$ vi inventory server1 ansible_ssh_host=192.168.1.104 ansible_ssh_port=2221
-
建立 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: # 執行 'apt-get update' 指令。 - name: update apt repo cache apt: name=nginx update_cache=yes # 執行 'apt-get install nginx' 指令。 - name: install nginx with apt apt: name=nginx state=present # 於網頁根目錄 (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) 關閉 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 # # * 當確認事件有被觸發才會動作。 # * 一個 handler 可被多個 task 通知 (notify),並於 tasks 跑完才會執行。 handlers: # 執行 'sudo service nginx restart' 指令。 - name: restart nginx service: name=nginx enabled=yes state=restarted # post_tasks: # # 在 tasks 之後執行的 tasks。 post_tasks: # 檢查網頁內容。 - name: review http state command: "curl -s http://localhost" register: web_context # 印出檢查結果。 - name: print http state debug: msg={{ web_context.stdout_lines }} # vim:ft=ansible : {% endraw %}
註:
raw
和endraw
是為了相容 GitBook 所增加的語法,您可能會在某平台上看到它,請忽略之。- 在第 47 行裡,我們建立了一個
restart nginx
handler。 - 在修改到 Nginx 設定檔的 tasks (
modify index.html
,turn server_tokens off
) 裡,使用notify
通知 handlers (restart nginx
) 說這些 Tasks 要進行關連。 - 最後在
post_tasks
裡建了 2 個 tasks,讓它們可以在一般的 tasks 結束後才執行。
- 在第 47 行裡,我們建立了一個
-
建立 Nginx vhost 的 template:請參考前一篇的「14. 怎麼使用 Ansible 的 Template 系統?,凍仁就不在此多加詳述。
$ 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>[ {{ username }}@automate-with-ansible ~ ]$ hostname automate-with-ansible.drx.tw [ {{ username }}@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 | || || [ {{ username }}@automate-with-ansible ~ ]$ [ {{ username }}@automate-with-ansible ~ ]$ [ {{ username }}@automate-with-ansible ~ ]$ cat .profile - {{ mail }} - {{ blog }}</pre> </p> </body> </html> {% endraw %}
註:
raw
和endraw
是為了相容 GitBook 所增加的語法,您可能會在某平台上看到它,請忽略之。- 在這份 index.html.j2 裡,我們用了
username
,mail
和blog
三個變數,其值會從setup_nginx.yml
中代入。
- 在這份 index.html.j2 裡,我們用了
-
執行 Playbook。
- 試著多跑幾次,就會發現當
modify index.html
和turn server_tokens off
tasks 的狀態不為 changed 時,該 handler 不會被觸發的差異。 - 在此例中,我們可以藉由修改 Playbook 裡的變數 (vars) 來重複觸發 handler,例如把
username
從ironman
修改成root
。
- 試著多跑幾次,就會發現當
雖然我們可以在 tasks 的最後加個 task 來重開 web service,可當與 web service 相關的 tasks 的狀態皆為 ok 時,這種寫法會讓 web service 再次被重開。
透過 Handlers 我們可以只在需要時重開一次,進而減少服務中斷的時間。
Footnotes
-
維基百科對於 Handler 的解釋為 An asynchronous callback (computer programming) subroutine in computing,詳情請參考 Handler | Wikipedia 一文。 ↩
-
一般都會用 Tasks 通知 (notify) Handlers 來述敘兩者的關係,但凍仁比較喜歡用 Tasks 關連於 Handlers 的說法。 ↩