「ミドルウェアをインストール」「ミドルウェアの設定変更」「ミドルウェアのサービスをスタート」という流れで、サービスのスタートを必要な場合だけに実施するやり方。
以前作成したplaybook
この辺で書いたやつ。
- hosts: www gather_facts: false become: true tasks: - yum: name: httpd state: present - name: configure httpd server replace: path: /etc/httpd/conf/httpd.conf regexp: ^#?Listen 80$ replace: Listen 8080 - name: enable httpd service systemd: name: httpd state: restarted enabled: yes
初回であれば
- インストール
- 設定変更
- サービス起動
を順に全部実行で良いんだけど、同じplaybookを再度Ansible実行すると
- インストール (skip!)
- 設定変更 (skip!)
- サービス起動 (実行!)
となり、サービスの再起動が無駄になります。
(じゃあsystemd
はrestarted
じゃなくてstarted
にすると、単純な再実行は冪等になるので処理されないけど、今度は「設定変更」の内容をバージョンアップした場合などで変化があったときに、再起動して欲しいけどされないという状態になる)
こういう時に使用するのがhandlers
です。
基本形
まずは単純に「インストール」と「インストールされた場合だけrestart」
- hosts: www gather_facts: false become: true tasks: - yum: name: httpd state: present notify: - installed_httpd handlers: - name: installed_httpd systemd: name: httpd state: restarted enabled: yes
まずタスク内でnotify
を使い、「そのタスクがchanged
だった場合に呼び出すハンドラ名(上の例では- installed_httpd
)」を指定します。
これによって、上の例でいえば「yum
モジュールでhttpdがインストールされた場合」にinstalled_httpd
が呼ばれるようになります。
そして呼ばれる側の定義は通常のタスクを定義するtasks
とは別にhandlers
セクションで定義します。
handlers
に記述したどのハンドラを呼び出すか(上の例は1つしかないけど)については、name
に指定します。ここにinstalled_httpd
と書いておくことで、notify: [ installed_httpd]
が指定されているタスクがchanged
だった場合にこのハンドラが処理されるようになります。
これで「httpdがインストールされたときだけサービスをrestartする」となります。
name
は表示用文字列として使用して、プログラム的な識別子を別途使いたい場合は、handlers
側ではlisten
を指定することで、name
と別にnotify
先を定義できます。(後述)
インストール or 設定変更
冒頭にも挙げた例。
「サービスのrestart」の条件が複数の場合にどうするかと言うと
--- - hosts: www gather_facts: false become: true tasks: - yum: name: httpd state: present notify: - require_reload_httpd - name: configure httpd server replace: path: /etc/httpd/conf/httpd.conf regexp: ^#?Listen 80$ replace: Listen 8080 notify: - require_reload_httpd handlers: - name: enable httpd service systemd: name: httpd state: restarted enabled: yes listen: require_reload_httpd
実は同じハンドラをnotify
で複数指定しても、対象が実行されるのは1回です。
上のplaybookではtasksパートでは「httpdインストール」と「httpdサーバー設定」を順に行い、その両方でnotify
を使って同じrequire_reload_httpd
を指定しています。
この時の実行順と回数はtasks
に定義されたタスクを順に全て実行し、その際にnotify
で同じハンドラが複数回指定があった年ても、handlers
に定義された該当タスクは1回だけ実行、となります。
Handlers: Running Operations On Change
These ‘notify’ actions are triggered at the end of each block of tasks in a play, and will only be triggered once even if notified by multiple different tasks.
お、そういえば日本語ドキュメントも先月公開されたんだった
これらの「通知」アクションは、プレイのタスクの各ブロックの最後にトリガーされ、 複数の異なるタスクから通知された場合でも 1 回だけトリガーされます。
roleにする場合
上の例の「インストール」「設定変更」「必要な時だけrestart」をそのままroleに分割すると
$ tree roles/ roles/ └── install_httpd ├── handlers │ └── main.yml └── tasks └── main.yml
install_httpd/tasks/main.yml
--- - yum: name: httpd state: present notify: - require_reload_httpd - name: configure httpd server replace: path: /etc/httpd/conf/httpd.conf regexp: ^#?Listen 80$ replace: Listen 8080 notify: - require_reload_httpd
install_httpd/handlers/main.yml
--- - name: enable httpd service systemd: name: httpd state: restarted enabled: yes listen: require_reload_httpd
元のplaybook
--- - hosts: www gather_facts: false become: true roles: - install_httpd
です。
まぁここは普通です。
実装例
複数のロールがある場合の処理順序はちょっと注意。