Ansible で EC2 の環境をプロビジョニングするときの 本番やステージングなどを切り替える方法

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.confec2.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.confec2.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 とかが複数のディレクトリに同じ内容で散らばるのがちょっと気持ち悪いですけど。

Sign up for free and join this conversation.
Sign Up
If you already have a Qiita account log in.