Ansible 在 Playbooks 使用 Handlers
Handlers 是我们在 Ansible Playbooks 里很常用来重开系统服务 (Service) 的手法,大家可以在不少前人分享的 Playbooks 里看见它的踪迹,这里冻仁将透过安装 Nginx 的 Playbook 来介绍它。
Handlers 是什么?
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
怎么使用 Handlers?
底下冻仁将通过部署 Nginx 的 Playbook 为例。
建立 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
建立 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= # vim:ft=ansible :
- 在第 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:请参考前一篇的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>[ @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 里,我们用了
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 我们可以只在需要时重开一次,进而减少服务中断的时间。
相关连结
1. 维基百科对于 Handler 的解释为 An asynchronous callback (computer programming) subroutine in computing,详情请参考 Handler | Wikipedia 一文。 ↩
2. 一般都会用 Tasks 通知 (notify) Handlers 来述叙两者的关系,但冻仁比较喜欢用 Tasks 关连于 Handlers 的说法。 ↩