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: 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 :
restart nginx
handler。modify index.html
, turn server_tokens off
) 裡,使用 notify
通知 handlers (restart nginx
) 說這些 Tasks 要進行關連。post_tasks
裡建了 2 個 tasks,讓它們可以在一般的 tasks 結束後才執行。建立 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>
username
, mail
和 blog
三個變數,其值會從 setup_nginx.yml
中代入。執行 Playbook。
modify index.html
和 turn server_tokens off
tasks 的狀態不為 changed 時,該 handler 不會被觸發的差異。username
從 ironman
修改成 root
。雖然我們可以在 tasks 的最後加個 task 來重開 web service,可當與 web service 相關的 tasks 的狀態皆為 ok 時,這種寫法會讓 web service 再次被重開。
透過 Handlers 我們可以只在需要時重開一次,進而減少服務中斷的時間。
[^1]: 維基百科對於 Handler 的解釋為 An asynchronous callback (computer programming) subroutine in computing,詳情請參考 Handler | Wikipedia 一文。
[^2]: 一般都會用 Tasks 通知 (notify) Handlers 來述敘兩者的關係,但凍仁比較喜歡用 Tasks 關連於 Handlers 的說法。