過去複数回に渡って、Ansibleを使ってWordPressをセットアップしてきましたが、あるサーバーのセットアップができる「一品物」のPlaybookになっていました。複数台のサーバーをセットアップする際に、毎回イチからPlaybookを書いていたのでは効率が悪いですし、例えば同じ機能を持つ開発機と本番機がある場合などでは、開発機と本番機でhosts句の書き換えが必用になってしまいます。
Ansibleに用意されている「Best Practices」を実践すれば、その問題は解決です。最初は単なる「推奨ディレクトリ構成」みたいなものかと思っていたのですが、違いました。その名の通りAnsibleを使うための「最良の方法」です。
Best Practicesを理解するためのポイント
ベストプラクティスを理解するために必要なポイント(個人的見解!)をあげていきます。
(1)rolesステートメントとディレクトリ構成
最も重要なポイントです。
マニュアルだとここに記載されています。
サーバーの機能を細分化し「ロール(役割)」として管理できます。
例えばWebサーバー、DBサーバーなどのまとまった機能を「ロール」とします。
以下のように、rolesディレクトリは以下に、各ロールに対応するディレクトリを作成します。raspi.ymlが実行するPlaybook、その他の/で終わっているのがディレクトリです。base/はベースディレクトリです。
1 2 3 4 5 6 7 8 9 |
base/ |--raspi.yml `--roles |--common/ | `--tasks/ |--webserver/ | `--tasks/ `--dbserver/ `--tasks/ |
Playbook「raspi.yml」の中には、「roles」ステートメントに配列として役割の名前を記述します。
1 2 3 4 |
roles: - common - webserver - dbserver |
このPlaybookを実行すると、rolesステートメントの配列名に対応する、rolesディレクトリ以下のディレクトリに処理が移ります。「- webserver」実行時には、roles/webserver/ディレクトリの内容が参照される。といった具合です。
(2)役割別ディレクトリの扱い
roles配下の役割別ディレクトリの中には、tasks、vars、templatesなどのディレクトリを作成します。ディレクトリの名前により、処理が変わります。例えばtasksディレクトリ内のmain.ymlに記載した内容は、playbook内のtasks:に記載された内容として読み込まれます。
作成できるディレクトリの機能を以下に記載します。いずれのディレクトリも必須ではないようです。
・tasksディレクトリ
タスクを記載した「main.yml」ファイルを配置します。このファイルの内容はplaybookの「tasks:」以下に記載されたものとして扱われます。
main.ymlファイルの中には、下記のようにplaybookのtasksに記載する内容を記載します。最初の「—」や「tasks:」は不要です。
1 2 3 4 5 |
- name: Place the ntp conf file copy: src=ntp.conf dest=/etc/ - name: Place the resolv conf file copy: src=resolvconf.conf dest=/etc |
・handlersディレクトリ
ハンドラを記載した「main.yml」ファイルを配置します。このファイルの内容はplaybookの「handlers:」以下に記載されたものとして扱われます。私は使ったことがないのですが、詳細は「Ansible: notify と handlers の使い方について調べた」が分かりやすかったです。
・templatesディレクトリ
templateモジュールで使用するテンプレートを配置します。ここに配置したファイルは、ファイル名のみでtemplateのsrcに指定できます。
例えばtemplatesディレクトリに中に「my.cnf.j2」ファイルを配置している場合、tasks/main.yml内には以下のように記載できます。
1 |
template: src=my.cnf.j2 dest=/root/.my.cnf mode=0600 |
・filesディレクトリ
copyモジュールやscriptモジュールで使用するファイルを配置します。ここに配置したファイルは、ファイル名のみでcopyのsrcやscriptで使用できます。
例えばfilesディレクトリに中に「localtime」ファイルを配置している場合、tasks/main.yml内には以下のように記載できます。
1 |
copy: src=localtime dest=/etc/ |
・varsディレクトリ
変数を記載した「main.yml」ファイルを配置します。このファイルは、playbookのvars_filesステートメントで指定したファイルと同様に扱われます。
1 2 3 |
--- var1: value1 var2: value2 |
・defaultsディレクトリ
変数を記載した「main.yml」ファイルを配置します。vars/main.ymlと似ていますが、defaults/main.ymlに記載された変数は最低のの優先度となり、後述するgroup_varsやhost_vars、インベントリファイル内の変数などで上書きすることができます。
・metaディレクトリ
依存関係を記載した「main.yml」ファイルを配置します。
例えば、webserverロールがcommonロールに依存する場合、下記のように記載します。
1 2 3 |
--- dependencies: - { role: common } |
この場合、webserverロールを実行する前に、commonロールが実行されます。
下記のように記載すると、依存するロールに変数を渡すことができます。
この場合、webserverロールの前にcommonロールを実行し、その際に変数var1とvar2を渡すことができます。
1 2 |
---dependencies: - { role: postgres, var1: aaa, var2: bbb } |
その他、whenを使用してOS等の実行条件を記載することもできるようです。
(2)インベントリファイル
開発環境(Staging)と本番環境(Production)など、目的・役割や場所などで分けたインベントリファイルを、ベースディレクトリ直下に配置します。
ansible-playbookを実行する際、-iオプションで実行したい環境のインベントリファイルを指定します。Productionファイルには本番機のサーバーを記載しておき、下記のように実行すると、インベントリファイルに記載された本番機が処理対象となります。
1 |
ansible-playbook -i production site.yml |
インベントリファイルとはplaybookの実行対象サーバーを記載するファイルで、デフォルトでは/etc/ansible/hostsが使われています。
1 2 3 4 5 6 7 8 9 10 11 12 13 14 |
mail.example.com [webservers] foo.example.com bar.example.com [dbservers] one.example.com two.example.com three.example.com [tokyo:children] webservers dbservers |
この内容の場合、mail.example.comサーバーはグループに所属しないサーバー、foo,barはwebserversグループに所属するサーバー、one,two,threeはdbserversに所属するサーバーになります。さらにwebserversグループとdbserversグループを、親グループであるtokyoグループに所属させています。
ちなみに、インベントリファイル内でホスト名を使う場合は、hostsファイルやDNSでの名前解決が必用なので注意してください。
詳細は公式マニュアルにて。
(3)group_varsディレクトリ
グループ別に使用する変数ファイルを格納できます。group_varsディレクトリ配下に、グループと同じ名前のディレクトリもしくはファイルを配置すると、グループを指定して実行した際に該当する変数ファイルが読み込まれます。
例えば、playbook内のhostsにwebserversグループを指定して実行した場合、base\group_vars\webserversが読み込まれます。
webserversがファイルの場合、拡張子無し、*.yml、*.yaml、*.jsonが使用できます。ベース名が同じで拡張子が同じ複数のファイル(例えばwebservers.ymlとwebservers.json)を配置した場合、どちらかしか読み込まれません。
webserversがディレクトリの場合、その配下にあるすべてのファイルから変数が読み込まれます。拡張子は問いません。webserversファイルとwebserversディレクトリがある場合、webserversファイルは無視され、webserversディレクトリ内のファイルが読み込まれます。
1 2 3 4 5 6 7 8 |
base/ `--group_vers |--common/ | |--main.yml | `--aaa.yml |--webservers/ | `--vers.json `--dbservers.yml |
上記のような構成の場合、実行されているグループにより読み込まれるファイルは以下の通りです。
1 2 |
base/group_vers/common/main.yml base/group_vers/common/aaa.yml |
1 |
base/group_vers/webservers/vers.json |
1 |
base/group_vers/dbservers.yml |
(4)host_varsディレクトリ
ホスト別に使用する変数ファイルを格納できます。host_varsディレクトリ配下に、ホスト名と同じ名前のディレクトリもしくはファイルを配置すると、ホストを指定して実行した際に該当する変数ファイルが読み込まれます。 (5)ベースディレクトリ直下のプレイブック
ベースディレクトリ直下に配置するPlaybookは、マスタープレイブックsite.ymlとそれにインクルードするグループ別のPlaybookのみとなります。 site.ymlにインクルードするグループ別のPlaybookでは、下記のように実行するロールのみを記載します。 Raspberry PiにWordPressをセットアップするPlaybookを、BestPracticeに沿って組み替えてみました。 ※末尾に/が付いているのはディレクトリ、付いていないはファイルです。 それぞれのファイルの内容です。 本番環境用のインベントリファイルです。Rasberry Pi 3の情報を記述しています。 開発環境用のインベントリファイルです。開発機として使用しているRasberry Pi B+の情報を記述しています。 raspiグループ用の変数ファイルです。パスワードなどを記載しています。パスワードはマスクしてます。 site.ymlが実行するPlaybookです。内容はraspi.ymlを呼び出すだけです。 RasberryPiにraspiをセットアップするために必要なロールを記述しています。 roles配下は非常に長くなるので、baseにしました。 下記のように実行すれば、各種ファイルが読み込まれてRaspberry PiにWordPressがセットアップされます。 ・本番環境をセットアップする場合 ベストプラクティスに沿ってPlaybookと関連ファイルを配置することで、セットアップ先の制御や機能(ロール)の再利用が簡単にできるようになります。すっきりしてどのようなPlaybookなのか分かりやすくなるのもメリットですね。 最後までお読みいただきありがとうございました。よろしければ広告もご覧ください!
細かい点は未検証なので記載しません。おそらくgroup_varsと同様かと。
マスタープレイブック(site.yml)には以下のようにincludeのみを記載します。
WordPressのPlaybookをBestPracticeに沿って組み替える
ファイルとディレクトリ構成は以下の通りとしました。
※ユーザー名、パスワード、IPアドレスはマスクしています。
・開発環境をセットアップする場合