設定する対象がデータベースやアプリケーションサーバの場合、「一つのインスタンスに複数のアプリケーションをデプロイ」したり、「一つのアプリケーションに複数のデータソースを追加」といった一対多の設定はよくあります。
ansibleで設定を行う場合に、
- 設定ファイルを肥大化を防止
- 必要最小限の値を設定
- 設定と構造の関係を把握することが容易
となるようなパターンを検討してみました。
より良い方法があるかもしれませんが、ひとまずこれで動いています。
設定:構造を定義
設定は、“./host_vars/[対象サーバ名]を起点にします。こうすることでansibleがインベントリから対象サーバを特定した際に自動的に設定が読み込まれます。
$ cat host_vars/appserv1 serverName: app-server1 tomcat: - appName: inst1 db: - dba - appName: inst2 db: - db1 - db2 $
この例では、tomcatという変数にinst1とinst2という2つのアプリケーションがあり、inst1は、dbaというデータベース接続を、inst2は、db1とdb2の2つのデータベース接続を設定します。
設定:各オブジェクトのパラメータ定義
各オブジェクトのパラメータ定義は、./varsにオブジェクト毎に設定します。
アプリケーションのパラメータは、./vars/inst1.ymlと./vars/inst2.ymlに設定します。
各アプリケーションに関連するデータベースの設定は、./vars/[アプリ名][db名].ymlに設定します。
今回の例ですと、./vars/inst1dba.ymlや./vars/inst2db1.ymlや./vars/inst2db2.ymlに設定することになります。
$ ls vars/inst[12]*.yml | cat vars/inst1.yml vars/inst1dba.yml vars/inst2.yml vars/inst2db1.yml vars/inst2db2.yml $
アプリケーションの設定は、下記のようにappNameを定義します。
$ for i in `ls ./vars/inst[12].yml`; do echo $i; cat $i; done ./vars/inst1.yml appName: inst1 ./vars/inst2.yml appName: inst2 $
データベースの設定は、下記とします。
$ for i in `ls ./vars/inst[12]db*.yml`; do echo $i; cat $i; done ./vars/inst1dba.yml schemaName: inst1dba ./vars/inst2db1.yml schemaName: inst2db1 ./vars/inst2db2.yml schemaName: inst2db2 $
roleの定義
パラメータを読み込んで設定するroleを作成するために下記のようなファイル一式を作ります。host_varsとvarsは、上記で設定したファイルです。
$ tree . ├── host_vars │ ├── appserv1 │ └── appserv2 ├── hosts ├── roles │ └── app │ └── tasks │ ├── db.yml │ ├── main.yml │ └── tomcat.yml ├── site.yml └── vars ├── inst1.yml ├── inst1dba.yml ├── inst2.yml ├── inst2db1.yml └── inst2db2.yml $
roles/app/tasks/main.ymlでアプリケーションの設定と、それに紐づくデータベースの設定をするためのタスクを定義します。
$ cat roles/app/tasks/main.yml
---
- include: tomcat.yml
with_items: "{{tomcat}}"
- include: db.yml
with_subelements:
- tomcat
- db
$
一つ目のタスクは、アプリケーション設定をするtomcat.ymlというファイルをインクルードします。
./host_avrs/[サーバ名]で定義したtomcatという変数に定義したアプリケーションの回数繰り返します。
二つ目のタスクは、アプリケーションに紐付いたデータベースの設定をするdb.ymlというファイルをインクルードします。
本当は、インスタンスの設定に入れ子したかったのですが、with_itemsで使われるitemという変数が入れ子の中では設定できず諦めました。(誰かうまい方法教えて)
いろいろ調べた結果、with_subelementsでtomcat変数の配列の一つを取り出し、appName+dbの組み合わせをdb.ymlに渡しています。
それぞれの処理
サンプルなので設定されたパラメータを読み込み表示するだけの処理です。
アプリケーションの設定は、以下の通りです。
$ cat roles/app/tasks/tomcat.yml
---
- include_vars: "{{item.appName}}.yml"
- debug: msg="Tomcat application Name={{appName}}"
$
DBの設定は、以下の通りです。
$ cat roles/app/tasks/db.yml
---
- include_vars: "{{item.0.appName}}{{item.1}}.yml"
- debug: msg="{{item.0.appName}} application dbName={{schemaName}}"
$
どちらも、最初にinclude_varsで./varsディレクトリ下の所定の定義ファイルのパラメータを読み込み、表示します。
実行
インベントリにとりあえず1台サーバを追加します。
appserv2も追加して、./host_vars/appserv1を./host_vars/appserv2とにコピーすると、全くおなじ設定のサーバを作ることができます。
もちろん、./vars/inst1*.yml一式をコピーして個別の設定にすることも可能です。
[appservers] appserv1 #appserv2 $
実行すると、こんな感じです。
アプリケーションの名前やDB接続先など、設定が必要な固有の値をtemplateで埋め込んだりtaskの中で参照するといった使い方になります。
$ ansible-playbook -i hosts site.yml
PLAY ***************************************************************************
TASK [setup] *******************************************************************
ok: [appserv1]
TASK [app : include] ***********************************************************
included: /home/vagrant/git/sample/roles/app/tasks/tomcat.yml for appserv1
included: /home/vagrant/git/sample/roles/app/tasks/tomcat.yml for appserv1
TASK [app : include_vars] ******************************************************
ok: [appserv1]
TASK [app : debug] *************************************************************
ok: [appserv1] => {
"msg": "Tomcat application Name=inst1"
}
TASK [app : include_vars] ******************************************************
ok: [appserv1]
TASK [app : debug] *************************************************************
ok: [appserv1] => {
"msg": "Tomcat application Name=inst2"
}
TASK [app : include] ***********************************************************
included: /home/vagrant/git/sample/roles/app/tasks/db.yml for appserv1
included: /home/vagrant/git/sample/roles/app/tasks/db.yml for appserv1
included: /home/vagrant/git/sample/roles/app/tasks/db.yml for appserv1
TASK [app : include_vars] ******************************************************
ok: [appserv1]
TASK [app : debug] *************************************************************
ok: [appserv1] => {
"msg": "inst1 application dbName=inst1dba"
}
TASK [app : include_vars] ******************************************************
ok: [appserv1]
TASK [app : debug] *************************************************************
ok: [appserv1] => {
"msg": "inst2 application dbName=inst2db1"
}
TASK [app : include_vars] ******************************************************
ok: [appserv1]
TASK [app : debug] *************************************************************
ok: [appserv1] => {
"msg": "inst2 application dbName=inst2db2"
}
PLAY RECAP *********************************************************************
appserv1 : ok=16 changed=0 unreachable=0 failed=0
$