この記事は公開されてから1年以上経過しています。情報が古い可能性がありますので、ご注意ください。
渡辺です。
Ansibleでは、ホストをInventoryファイル(スクリプト)で定義します。 この時、次のようにグループ化することが可能です。
[prd]
10.0.0.10
10.0.0.20
[stg]
10.0.100.10
10.0.100.20
ここではprdグループとstgグループにホストを定義しています。 ホストをグループ化することで、グループ変数(group variable)が利用できるため、本番環境(prd)と検証環境(stg)における構成の差異を反映した構成管理を行えます。
ここまではよくある話。 今回、ハマったのは本番環境も検証環境もlocalhostの場合です。 すなわちAnsibleをローカル実行させる場合に期待通りのグループ変数が適用されなかったというお話です。
期待通りにいかないファイル構成
こちらは上手く動作しなかった構成です。
# hosts
[stg]
localhost
[prd]
localhost
# stg.yml
- hosts: stg
connection: local
tasks:
- debug: var=stage
# prd.yml
- hosts: prd
connection: local
tasks:
- debug: var=stage
# group_vars/stg.yml
stage: stg
# group_vars/prd.yml
stage: prd
実行してみます。
$ ansible-playbook -i hosts stg.yml
PLAY ***************************************************************************
TASK [setup] *******************************************************************
ok: [localhost]
TASK [debug] *******************************************************************
ok: [localhost] => {
"stage": "stg"
}
PLAY RECAP *********************************************************************
localhost : ok=2 changed=0 unreachable=0 failed=0
期待通りです。
PLAY ***************************************************************************
TASK [setup] *******************************************************************
ok: [localhost]
TASK [debug] *******************************************************************
ok: [localhost] => {
"stage": "stg"
}
PLAY RECAP *********************************************************************
localhost : ok=2 changed=0 unreachable=0 failed=0
あれ・・・prdのはずが・・・。
調査中...
対策後の構成
試行錯誤の結果、次のような構成としました。
# local
[local]
localhost
# local.yml
- hosts: local
connection: local
tasks:
- group_by: key={{ env }}
- debug: var=stage
# group_vars/stg.yml
stage: stg
# group_vars/prd.yml
stage: prd
実行してみます。
$ ansible-playbook --extra-vars "env=stg" -i local local.yml
PLAY ***************************************************************************
TASK [setup] *******************************************************************
ok: [localhost]
TASK [group_by] ****************************************************************
ok: [localhost]
TASK [debug] *******************************************************************
ok: [localhost] => {
"stage": "stg"
}
PLAY RECAP *********************************************************************
localhost : ok=3 changed=0 unreachable=0 failed=0
$ ansible-playbook --extra-vars "env=prd" -i local local.yml
PLAY ***************************************************************************
TASK [setup] *******************************************************************
ok: [localhost]
TASK [group_by] ****************************************************************
ok: [localhost]
TASK [debug] *******************************************************************
ok: [localhost] => {
"stage": "prd"
}
PLAY RECAP *********************************************************************
localhost : ok=3 changed=0 unreachable=0 failed=0
期待通りです!
考察
最初の構成は、localhostという同一のホストが複数のグループに属している状態になります。 つまり、localhostはstgグループにもprdグループにも属しています。
Ansibleは、ホスト毎に実行を行います。 この時、属しているグループからグループ変数を適用する流れになります。 localhostは、stgグループにもprdグループにも属しているので、両方のグループ変数ファイルが適用されます 今回、優先されたのがstgグループのグループ変数だったわけです。
つまり、localhostを環境毎にグループ変数を適用するにはこの定義では上手くいきません。
--extra-varsオプションとgroup_byモジュールの利用
これらの問題を解決するために、--extra-varsオプションとgroup_byモジュールを利用しました。 他の方法もありますが、設定ファイルの数が少なく、重複も減らしたいとなると、この方法がベストだと思います。
--extra-varsオプションは次のようにansible-playbookのコマンド実行時に指定します。
$ ansible-playbook --extra-vars "env=prd" -i local local.yml
これでenv=prdが変数として渡されることになります。
group_byモジュールは、playbook実行時に動的にグループを指定するモジュールです。 実行環境から取得する情報などかグループを指定しますが、ここでは--extra-varsオプションで指定されたenvを使い、prd(stg)グループに追加します。
tasks:
- group_by: key={{ env }}
prd(stg)グループに属すれば、それぞれのグループ変数が適用されることになります。
まとめ
Ansibleは、あくまでホストを主人公として実行されます。 同じホストに異なる設定を行いたい場合は、動的にグループを指定してください(inventoryファイル自体を環境分作成する方法もあります)。 動的なグループ追加はgroup_byモジュールで実現します。
localhostの時はご注意を!