AnsibleのInventory Groupで環境毎に異なるlocalhostを構築する
渡辺です。
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の時はご注意を!