Ansibleのroleを実際に使ってみてわかったことを共有します。さらに便利に活用するtips等ありましたら、ぜひコメントをお願いします。
Ansibleのroleは単にインクルードの単位
最初roleという名前を聞いたときは、webserverとかdbserverといった役割を設定するのだろうと予想しました。が、Rolesのドキュメントを読んで、playbookの一部をインクルードして再利用するための仕組みだということがわかりました。つまり、playbookを分割・構成するコンポーネントという意味合いです。
もともとroleはなくてincludeの仕組みだけありましたが、より便利にするためにroleという仕組みが追加されたという経緯のようです。
例えばnginx, mysqlといった単位でroleを定義するのが良いです。さらにmysql/clientのように階層的なrole名を用いることも出来ます。下記で詳しく説明します。
roleを使わなくてもincludeでtaskから別のtaskのファイルを読み込むことはできます。が、roleを分けるほうが以下の利点があるため、他のroleから利用しやすくなります。
- roleが別になるのでrole_varsの内容も分割できる
- role間の依存関係を設定できる
- role間の依存関係には実行条件も設定できる
roleのディレクトリ・ファイル構成
Ansibleのroleは以下の様なディレクトリ・ファイル構成になっています。ここではmysqlというroleを例に説明します。
- roles/mysql/tasks/main.yml
- タスク定義のメインファイル。内容が多くなってきたら分割してtasks/foo.ymlのようなファイルを作ってtasks/main.ymlからincludeすることもできます。
- roles/mysql/handlers/main.yml
- notifyに対するハンドラ定義のメインファイル。もう少し詳しく言うと、ファイルを変更した場合にAnsibleの実行の最後にサービスを再起動やリロードさせるためのnotificationの仕組みで呼び出されるハンドラ定義のメインファイルです。notificationについて詳しくはRunning Operations On Changeを参照してください。
- roles/mysql/vars/main.yml
- role単位の変数定義のメインファイル。
- roles/mysql/meta/main.yml
- roleの依存関係の定義ファイル。
階層的なrole名も使えますが注意が必要です
Ansibleのroleにはmysqlといったシンプルな名前の他に、mysql/clientといった階層的な名前をつけることもできます。
ただし、roleの定義フォルダにはtasks, handlers, vars, metaというフォルダがあるので、これらの名前は避ける必要があります。また将来roleの定義フォルダとして追加されそうな名前も避けておいたほうが無難です。
roleのデフォルト変数
Role Defaults Variablesによると、roleから別のroleをインクルードしたり依存関係を設定するとそちらのrole_varsに定義された変数がデフォルト値として設定されます。それを自分のrole_varsで上書き変更することも可能です。
この仕組を使うと場合によっては変数定義を一箇所にまとめることもできます。例えば、mysql/clientでクライアント・サーバ共通用のrpmをインストールし、mysql/serverではサーバ専用のrpmをインストールする場合、mysql/serverからmysql/clientに依存させておいて、rpmのバージョンの変数定義をmysql/clientのほうにまとめて書くといったことができます。
role間の依存関係を設定できる
例えばmysql/serverがmysql/clientに依存する場合は以下のように書きます。
---
dependencies:
- { role: mysql/client }
依存関係を設定すると、依存先のroleが先に実行されるようになります。依存関係は再帰的に辿られます。また、依存関係で複数回参照されても通常は最初の1回だけが実行されます。allow_duplicatesキーをtrueに設定すれば毎回実行することも出来ます。
詳細はRole Dependenciesにドキュメントがありますので参照してください。
role間の依存関係には実行条件も設定できる
依存関係の定義にはwhenキーで条件を設定することも出来ます。これを使えばOSのディストリビューションに応じて実行するサブroleを切り替えることが出来ます。例えばlxcがlxc/redhat, lxc/debianに依存している場合は以下のように書けます。
---
dependencies:
- { role: lxc/redhat, when: "ansible_os_family == 'RedHat'" }
- { role: lxc/debian, when: "ansible_os_family == 'Debian'" }
実際のplaybookでの例
CentOS 6.4 x86_64用のroleの実例は拙作のplaybookを参照してください。まだまだ非互換な変更が入る予定なので、その点はご留意ください。
https://github.com/hnakamur/ansible-playbooks/tree/master/roles