Ansibleのハンドラが起動するのはタスクがchangedを返したときだけ
Ansibleのハンドラとは
Ansibleのタスクには `notify` という属性を追加してコールバック処理を呼ぶよう設定できる。
[roles/nginx/tasks/main.yml]
- name: nginx config ensure template: src=my.nginx.conf.j2 dest=/etc/nginx/conf.d/your.conf sudo: yes notify: restart nginx
[roles/nginx/handlers/main.yml]
- name: restart nginx service: name=nginx state=restarted sudo: yes
こう書いておくと roles/nginx/templates/my.nginx.conf.j2 から生成した内容が /etc/nginx/conf.d/your.conf の内容を変更したときに、自律的にnginxを再起動してくれる。
この挙動を一般に「nginxの設定を変えたら自動的に再起動される」などと呼ぶ。
ところがわざわざ下線を引いたけれども、Ansibleのプレイブックを実行したタイミングで `nginx config ensure` のタスクが `CHANGED` を返さないとハンドラは起動しない。
だから
- プレイブックを起動。(A -> B -> C) の順にタスクを実行。
- nginxの設定ファイル配置をBのタイミングで行ったが、Cに指定した別のタスクが失敗した。
- ハンドラはすべてのタスクが終わった後に動くのでCが失敗した時点で処理が終わってしまう。
- もう一度プレイブックを動かすとBのタスクではもはやCHANGEDとは評価されないのでnginxが再起動されないまま放置される。
このような事態が起きうる。
役に立つのかわからない --force-handlers オプション
そういう事態を想定して、 `ansible-playbook` コマンドには `--force-handlers` というオプションが用意されている。
これを指定してプレイブックを動かすと、たとえタスクが失敗してもハンドラの起動まで進めてくれる。
とはいえ、指定し忘れると結局アウトなのだ。
よくわからないのだが、Ansibleには「ハンドラのタスクを指定して動かす」仕組みが無いので、nginxの設定ファイル配置以降のタスクが予期せず失敗した場合にやり直す方法が無い。
どうしたらいいのか?
仕方が無いのでこんな方法で対処してみた。
Role -- register/changed を利用
[roles/nginx/tasks/main.yml]
- name: 1. nginxの設定ファイルを配置 template: src=my.nginx.conf.j2 dest=/etc/nginx/conf.d/your.conf sudo: yes register: nginx_conf notify: restart nginx ... (他の雑多なタスク) ... - name: 2. nginxが起動していること service: name=nginx state=started sudo: yes - name: 3. nginxを強制的に再起動 service: name=nginx state=restarted sudo: yes when: nginx_restart is defined and not nginx_conf.changed tags: - deploy
実行コマンド
[通常時]
$ ansible-playbook -i foo.ini some.yml
[やり直しするとき]
$ ansible-playbook -i foo.ini some.yml -t deploy -e 'nginx_restart=yes'
こうしておけば
- 1のタスクでnginxの設定が変わったらハンドラから再起動される
- 3のタスクはコマンドラインからnginx_restartを指定したときだけ動く
- 1から動くハンドラと3のタスクによってnginx再起動が2度実行されることもない
ひとり言
なんかややこしいことをしている気がするのだが・・・
もっと簡潔な方法は無いのか。