ちょっと話題の記事

【Ansible】EC2 External Inventory Scriptを使った動的ホスト一覧生成

2014.11.03

この記事は公開されてから1年以上経過しています。情報が古い可能性がありますので、ご注意ください。

こんにちは。望月です。
Ansibleが便利なので最近よく触っています。今日は覚えておくと便利な機能「Dynamic Inventory」の紹介です。

Dynamic Inventoryとは

Ansibleを実行する際にはAnsibleの実行対象となるホストを予めファイルに記載しておきます。このファイルのことをインベントリファイルと呼びます。公式ドキュメントによると、以下のようなini形式で記載をしておく必要があります。

$ cat hosts
foo.example.com

[web]
foo.example.com
bar.example.com

[application]
baz.example.com
qux.example.com

インベントリファイルを予め用意しておくことのメリットとデメリットは明らかだと思います。メリットは「このファイルを読めばどのホストに適用されるのかが明らかになる」という点です。一方デメリットは「対象となるホストを全てインベントリファイルに記載しておく必要がある」点です。

EC2に限らずクラウド上でシステムを構築する際の特徴としてサーバの台数は固定されないという点が挙げられるかと思います。その特徴を考えると上記のデメリットはなかなか厄介です。インスタンスが変更になった際などに常にこのファイルをメンテナンスし続けなければならないからです。
あるいはサーバの構成を別システムで管理している際に、そのシステムからいちいち静的にini形式でファイルを吐き出さなければならない、というのも面倒になります。

その問題を解消してくれるのがDynamic Inventoryです。Dynamic InventoryとはAnsibleの対象となるホスト一覧を動的に生成することが出来る仕組みのことを指します。以下の通常のansible実行例を見てみましょう。

# -iオプションでインベントリファイルを指定
$ ansible -i hosts all -m ping

上記例では、hostsファイルにあらかじめ記載された全サーバに対してpingを実行します。hostsにはpingを打ちたいサーバを全て羅列しておく必要があります。今はpingなのであまり有り難みがないですが、先日のShellshock脆弱性の時のようにEC2に存在する大量のインスタンスに対して特定のコマンドを打ちたい時など、一つ一つのインスタンスのIPアドレス/DNS名を記載するのは面倒ですね。 *1

ここで活躍するのがDynaic Inventoryです。コマンド実行時に実行権限が付与されたファイルをインベントリファイルに指定した場合、そのファイルに記載されたスクリプトを実行した結果を対象ホストとして認識してくれるのです。動的にホスト一覧を生成するので、Dynamic Inventoryと呼ばれています。

EC2 External Inventory

さて、ここまででDynamic Inventoryの機能を説明してきました。私はEC2上のインスタンスを扱うことが多いのでこの機能を利用して、動的にホスト一覧を生成するスクリプトを書こうかなー、と思っていたところAnsible公式でEC2用のスクリプトを提供してくれていました。なのでこれを利用してみましょう。

まず、当該のファイルをダウンロードしてきます。私は利用しませんでしたが、Ansibleパッケージにも当該ファイルが同梱されているのでそれを利用しても構わないと思います。

$ wget https://raw.githubusercontent.com/ansible/ansible/devel/plugins/inventory/ec2.py
# Dynamic Inventoryとして利用するために実行権限付与
$ chmod a+x ec2.py

デフォルトではAWSのアクセスキーとシークレットキーは環境変数AWS_ACCESS_KEY_IDAWS_SECRET_ACCESS_KEYを経由して渡すことになっているのでそれぞれ適当なものを設定しましょう。

$ export AWS_ACCESS_KEY_ID='AKIAxxxxx.......'
$ export AWS_SECRET_ACCESS_KEY='yyyyy.......'

また、ec2.pyの動作設定用ファイルとして、同一ディレクトリec2.iniというファイルが必要になります。このファイルのテンプレートも公式で提供されているのでダウンロードしてきましょう。ec2.pyと同じく、パッケージ同梱のものでも構いません。

$ wget https://raw.githubusercontent.com/ansible/ansible/devel/plugins/inventory/ec2.ini

最低限必要な準備はこれだけです。あとはいつもと同じようにAnsibleコマンドを実行する時に、スクリプトファイルのファイル名を渡してあげればよいだけです。

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

私の環境で1台のEC2を起動していたので、ec2.pyがその情報を動的に収集して、それをターゲットにpingが実施されました。 *2

また、ec2.pyを単体で実行すると、スクリプトが生成するJSONを読むことができます。どんなGroupが生成されるのか、などの参考になるので一度目を通しておくと良いと思います。

まとめ

今日はAnsible Dynamic Inventory機能を利用して動的に対象サーバ一覧を取得する方法を記載しました。今回はAnsible公式のスクリプトを利用しましたが、本文で書いたとおり、ある決まった形式のJSONが出力されれば、自前のスクリプトファイルを配置しても問題ありません。興味が有る方は公式ドキュメントを参考に書いてみても良いと思います。

私は今回利用したスクリプトに少し手を入れて利用しました。その紹介はまた別のブログエントリで書こうと思います!

参考資料

あわせて読みたい

脚注

  1. 弊社ではbash脆弱性対応の時にはAnsibleが活躍しました。詳細はこちらのブログをどうぞ
  2. もしかしたら実行に少し時間がかかったかもしれません。インベントリファイルの動的生成には多少時間がかかります。EC2 External Inventoryではttlが300のキャッシュを持つので、次回の実行はかなり速いと思います。