AnsibleのDynamic InventoryをEC2で使う

Apr 19, 2015   #ansible  #aws  #ec2 

本記事では、Ansibleが標準で備えているDynamic Inventoryという機能について解説します。

Ansibleはインベントリファイルに記載されているサーバに対し、処理を実行します。 こちらの入門用の記事でも紹介しましたが、インベントリファイルは下記のようなini形式で対象を記載しておく必要があります(公式から引用)。

mail.example.com

[webservers]
foo.example.com
bar.example.com

[dbservers]
one.example.com
two.example.com
three.example.com

インベントリファイルを見れば操作対象のサーバが明らかになる点は嬉しいですが、サーバ台数が固定化されないクラウド環境だとインスタンスの変更に応じて都度メンテナンスしていく必要があります。 また、既にサーバ一覧のマスタファイルを管理している場合は二重管理となってしまいます。

そんな問題を解決するのがDynamic Inventoryという機能です。

Dynamic Inventoryとは

Dynamic Inventoryとは、その名の通りインベントリファイルを動的にする機能です。 下記のようなjsonを返すスクリプトファイル(公式から引用)を作成し、実行権限を付けて-iオプションでインベントリに指定します。

{
    "databases"   : {
        "hosts"   : [ "host1.example.com", "host2.example.com" ],
        "vars"    : {
            "a"   : true
        }
    },
    "webservers"  : [ "host2.example.com", "host3.example.com" ],
    "atlanta"     : {
        "hosts"   : [ "host1.example.com", "host4.example.com", "host5.example.com" ],
        "vars"    : {
            "b"   : false
        },
        "children": [ "marietta", "5points" ]
    },
    "marietta"    : [ "host6.example.com" ],
    "5points"     : [ "host7.example.com" ]
}

Ansibleは指定されたインベントリファイルの権限を確認し、実行権限があればDynamic Inventoryとして認識する動きをします。

また、Dynamic Inventory用のファイルはいくつか用意されています。EC2, Azure, Vagrantなどなど、色々揃ってます。
ansible/plugins/inventory at devel · ansible/ansible

公式ドキュメントはこちらです。
Developing Dynamic Inventory Sources — Ansible Documentation

EC2で試してみる

GitHubからスクリプト(ec2.py)と設定ファイル(ec2.ini)をダウンロードし、スクリプトに実行権限を付与します。

$ wget https://raw.githubusercontent.com/ansible/ansible/devel/plugins/inventory/ec2.py
$ wget https://raw.githubusercontent.com/ansible/ansible/devel/plugins/inventory/ec2.ini
$ chmod a+x ec2.py

ec2.pyとec2.iniは基本的に同じディレクトリに置きます。 別のディレクトリに置く場合は、iniファイルのパスを環境変数EC2_INI_PATHで指定します。

また、実行にはAWSのアクセスキーとシークレットキーが必要になります。 アクセスキー ID と秘密アクセスキーの取得 - Amazon Simple Queue Serviceを参考にキーを取得し、環境変数AWS_ACCESS_KEY_IDAWS_SECRET_ACCESS_KEYで指定します。

$ export AWS_ACCESS_KEY_ID='YOURACCESSKEYID'
$ export AWS_SECRET_ACCESS_KEY='YOURSECRETACCESSKEY'

Ansibleで試す前に、下記のコマンドで正常にインベントリを生成できるか確認します。

$ ./ec2.py --list

json形式で応答があれば成功です。 デフォルトだとグローバルIPを引っ張ってくるので、プライベートIPで取得したい場合はec2.inidestination_variablevpc_destination_variableを編集します。

# This is the normal destination variable to use. If you are running Ansible
# from outside EC2, then 'public_dns_name' makes the most sense. If you are
# running Ansible from within EC2, then perhaps you want to use the internal
# address, and should set this to 'private_dns_name'. The key of an EC2 tag
# may optionally be used; however the boto instance variables hold precedence
# in the event of a collision.
# destination_variable = public_dns_name
destination_variable = private_dns_name

# For server inside a VPC, using DNS names may not make sense. When an instance
# has 'subnet_id' set, this variable is used. If the subnet is public, setting
# this to 'ip_address' will return the public IP address. For instances in a
# private subnet, this should be set to 'private_ip_address', and Ansible must
# be run from within EC2. The key of an EC2 tag may optionally be used; however
# the boto instance variables hold precedence in the event of a collision.
# vpc_destination_variable = ip_address
vpc_destination_variable = private_ip_address

あとは-iオプションでインベントリファイルを指定してあげるだけです。 今回は1台だけインスタンスが立ち上がっていたので下記の結果となりました。

$ ansible -i ec2.py all -m ping
172.31.15.20 | success >> {
    "changed": false,
    "ping": "pong"
}

$