ksaitoの日記

日々試したことの覚え書き

ansibleで一対多の設定をする

設定する対象がデータベースやアプリケーションサーバの場合、「一つのインスタンス複数のアプリケーションをデプロイ」したり、「一つのアプリケーションに複数のデータソースを追加」といった一対多の設定はよくあります。

ansibleで設定を行う場合に、

  • 設定ファイルを肥大化を防止
  • 必要最小限の値を設定
  • 設定と構造の関係を把握することが容易

となるようなパターンを検討してみました。

より良い方法があるかもしれませんが、ひとまずこれで動いています。

設定:構造を定義

設定は、``./host_vars/[対象サーバ名]を起点にします。こうすることでansibleがインベントリから対象サーバを特定した際に自動的に設定が読み込まれます。

$ cat host_vars/appserv1
serverName: app-server1

tomcat:
  - appName: inst1
    db:
      - dba
  - appName: inst2
    db:
      - db1
      - db2
$ 

この例では、tomcatという変数にinst1inst2という2つのアプリケーションがあり、inst1は、dbaというデータベース接続を、inst2は、db1db2の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_varsvarsは、上記で設定したファイルです。

$ 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_subelementstomcat変数の配列の一つを取り出し、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
  
$