EC2 インスタンスに対して Ansible するときは Ansible に付属の ec2.py
などの Dynamic Inventory でインスタンスの一覧を取得しますが、本番やステージングを切り替えるためのインベントリの構成についてのメモ。
環境変数 で切り替える
ec2.py
に環境変数 AWS_PROFILE
でアドホックにプロファイルを指定できるので、Dynamic Inventory がインスタンスを取得してくる AWS アカウントを切り替えられます。
AWS_PROFILE=prod ansible-playbook -i ec2.py site.yml
この場合、インベントリはすべての環境で共通で良いので ansible.cfg
で指定しておけばコマンドラインでの指定は不要です。
# ansible.cfg
[defaults]
inventory = ec2.py
環境固有の変数(ansible_ssh_common_args
とか)は、インスタンスに Env=prod
のようなタグを付与しておけば ec2.py
がタグ名と値で tag_Env_prod
のようなグループを作るので group_vars/tag_Env_prod.yml
のようなファイルで指定できます。
# group_vars/tag_Env_prod.yml
ansible_ssh_common_args: -o ProxyCommand='ssh -W %h:%p ore@192.0.2.123'
ファイル名が group_vars/tag_Env_prod.yml
だとちょっと気持ち悪いので、下記のようなディレクトリ構成にして、
ansible.cfg
site.yml
roles/
...
group_vars/
# 環境ごとのグループ変数
prod.yml
stage.yml
dev.yml
# その他のグループ変数
ap.yml
web.yml
inventory/
ec2.py
ec2.ini
group.conf
group.conf
で ec2.py
によるグループを元にそれっぽいグループを作ります。前半で tag_Env_prod
などの空のグループを複数定義している部分は :children
で指定したグループが存在しないと警告になるので必要です。
# inventory/group.conf
[tag_Env_prod]
[tag_Env_stage]
[tag_Env_dev]
[prod:children]
tag_Env_prod
[stage:children]
tag_Env_stage
[dev:children]
tag_Env_dev
[ap:children]
tag_Role_ap
[web:children]
tag_Role_web
インベントリにはディレクトリを指定します。
# ansible.cfg
[defaults]
inventory = inventory/
これで group_vars/prod.yml
などのファイルを読ませることができます。vars.conf
などのインベントリを作成してそこに環境名のグループ変数を書いても良いです。
# inventory/vars.conf
[prod:vars]
ansible_ssh_common_args = -o ProxyCommand='ssh -W %h:%p ore@192.0.2.123'
[stage:vars]
ansible_ssh_common_args = -o ProxyCommand='ssh -W %h:%p ore@192.0.2.123'
[dev:vars]
ansible_ssh_common_args = -o ProxyCommand='ssh -W %h:%p ore@192.0.2.123'
なお、この方法は AWS_PROFILE
環境変数だけで対象環境を切り替えているので、1つの AWS アカウントにリージョンや VPC を分けて複数の環境を構築する場合は難しいです。
リージョンが違えば AWS_REGION
環境変数で指定できますけど、特定の VPC のインスタンス、とか、特定のタグが付いたインスタンス、とかをやるためには環境変数 EC2_INI_PATH
を指定するなりして ec2.ini
を分けてやる必要があります。
そんなことするぐらいなら後述のインベントリディレクトリで切り替えるほうが良いと思うので、基本的にこの方法はオススメできません。
インベントリディレクトリで切り替える
次のようなディレクトリ構成にします。
ansible.cfg
site.yml
roles/
...
group_vars/
ap.yml
web.yml
envs/
prod/
ec2.py
ec2.ini
group.conf
vars.conf
group_vars/
all.yml
stage/
ec2.py
ec2.ini
group.conf
vars.conf
group_vars/
all.yml
dev/
ec2.py
ec2.ini
group.conf
vars.conf
group_vars/
all.yml
ec2.ini
でプロファイルやタグのフィルタを指定します。
# envs/${env}/ec2.ini
instance_filters = tag:Env=prod
boto_profile = prod
環境固有の変数は vars.conf
に下記のようなインベントリの形式で書いても良いし、
# envs/${env}/vars.conf
[all]
ansible_ssh_common_args = -o ProxyCommand='ssh -W %h:%p ore@192.0.2.123'
group_vars/all.yml
にグループ変数として書いても良いです。
# envs/${env}/group_vars/all.yml
ansible_ssh_common_args: -o ProxyCommand='ssh -W %h:%p ore@192.0.2.123'
group.conf
は ec2.py
による tag_Name_Value
のようなグループからそれっぽい名前のグループを作るために使います。
# envs/${env}/group.conf
[ap:children]
tag_Role_ap
[web:children]
tag_Role_web
Ansible は -i でインベントリディレクトリを指定して実行します。
ansible-playbook -i envs/prod/ site.yml
環境変数 ANSIBLE_INVENTORY
でも良いです。
ANSIBLE_INVENTORY=envs/prod/ ansible-playbook site.yml
この方法は環境変数 AWS_PROFILE
で切り替える方法と比べて ec2.ini
が環境ごとに書けるので自由度が高いです。ec2.py
とかが複数のディレクトリに同じ内容で散らばるのがちょっと気持ち悪いですけど。