[Ansible]インベントリプラグインを使ってEC2インスタンス情報を動的に取得する
本記事では、Ansible のインベントリプラグインを使用してEC2インスタンスを動的に取得する方法について紹介します。
Ansible のインベントリ(ターゲットノードの接続情報等をまとめたファイル)に接続対象のホスト情報を記載するのですが、クラウド環境でEC2インスタンスが頻繁にホストが追加・削除される状況では管理が難しくなります。そこで、Ansible ではクラウドから提供されている API(AWS であれば EC2 API)によってホスト情報を動的に取得し管理するダイナミックインベントリという機能が提供されています。
Ansible 2.9までは GitHub 上の ec2.py をダウンロードして使う方法が主流でしたが、2.10 からはこのファイルが削除されていて使うことができず、インベントリプラグインをつかうことが推奨されています。
Ansible のバージョン
手元の実行環境です。
$ ansible --version
ansible 2.10.8
config file = /home/ansible/workspace/ansible.cfg
configured module search path = ['/home/ansible/.ansible/plugins/modules', '/usr/share/ansible/plugins/modules']
ansible python module location = /usr/local/lib/python3.8/site-packages/ansible
executable location = /usr/local/bin/ansible
python version = 3.8.9 (default, Apr 10 2021, 15:55:09) [GCC 8.3.0]
$ pip list | grep ansible
ansible 3.2.0
ansible-base 2.10.8
ansible-lint 5.0.7
$ pip list | grep boto
boto 2.49.0
boto3 1.17.62
botocore 1.20.62
EC2インスタンス例
今回は ansible-target-node01~05
という EC2 インスタンスが実行されているとします。Application
というタグで EC2 インスタンスをグルーピングしています。
Nameタグ | Applicationタグ | インスタンスタイプ |
---|---|---|
ansible-target-node01 | なし | t3a.medium |
ansible-target-node02 | なし | t3a.medium |
ansible-target-node03 | bar | t3a.medium |
ansible-target-node04 | foo | t3a.medium |
ansible-target-node05 | foo | t3.medium |
インベントリプラグインの有効化
Amazon EC2 のインベントリプラグイン(aws_ec2
)を使う場合、Ansible Galaxy から amazon.aws
コレクションをインストールします。
$ ansible-galaxy collection install amazon.aws
$ ansible-galaxy collection list | grep amazon.aws
amazon.aws 1.4.1
また、aws_ec2
インベントリプラグインを実行するホスト上で boto3 と botocore が必要です。
$ pip install boto3 botocore
インベントリの設定
インベントリファイルですが、ファイル名の末尾を aws_ec2.(yml|yaml)
にする必要があります。このインベントリファイルに取得するための設定やフィルタを書いていきます。詳細はドキュメントをご参照ください。
今回は aws_ec2.yml
というファイル名で以下のように記載しました。
plugin: aws_ec2
regions:
- ap-northeast-1
# フィルタの設定
# 起動しているEC2インスタンスのみを対象とする
filters:
instance-state-name: running
# グルーピングの設定
# タグ毎にEC2インスタンスのグループをまとめる
keyed_groups:
- key: tags.Application
prefix: tag_Name_
separator: ""
# inventory_hostnameの設定項目の優先順位
# 上から優先され、取得できなければ下に下がっていく
# この例だと Nameタグがなければ `ip-address`(パブリックIPv4アドレス)を採用し、
# それも設定されていなければプライベートIPv4アドレスを採用する
hostnames:
- tag:Name
- ip-address # パブリックIPv4アドレス
- private-ip-address
compose:
# inventory_hostnameを変更せずにansible_hostを変更する場合
# プライベートIPv4アドレスでホストに接続したい場合
ansible_host: private_ip_address
# SSM Session Managerでホストに接続したい場合は以下のようにする
# ansible_host: instance_id
ansible-inventory
コマンドでインベントリの状況を確認できます。@
が接頭辞になっているものはグループ名で、複数の EC2 インスタンスを指定する際に使用できます。インベントリの設定で Application タグの値でグルーピングし、接頭辞に tag_Name_
をつけるようにしました。
$ ansible-inventory -i aws_ec2.yml --graph
@all:
|--@aws_ec2:
| |--ansible-target-node01
| |--ansible-target-node02
| |--ansible-target-node03
| |--ansible-target-node04
| |--ansible-target-node05
|--@tag_Name_bar:
| |--ansible-target-node03
|--@tag_Name_foo:
| |--ansible-target-node04
| |--ansible-target-node05
|--@ungrouped:
プレイブック例
今回は簡単な例として、Name タグの値を取得するのみのプレイブックとしました。EC2 インスタンスに SSH 接続するための設定値(ansible_user
、ansible_ssh_private_key_file
)は適宜変更してください。
# playbook.yml
---
- name: Example dynamic inventory
hosts: "{{ target_hosts }}"
vars:
ansible_user: ec2-user
ansible_ssh_private_key_file: ~/.ssh/<KEY PAIR>.pem
tasks:
- name: Print Name tag
debug:
msg: "{{ tags.Name }}"
target_hosts
に Ansible を実行するホスト名を指定します。以下のようにコマンドから渡すことでプレイブック内に変更を加えることなく柔軟に EC2 インスタンスを指定できます。
# Applicationタグ: foo(tag_Name_foo)のEC2インスタンスに対して実行する
$ ansible-playbook -i aws_ec2.yml sample.yml -e "target_hosts=tag_Name_foo"
PLAY [Example dynamic inventory] ***********************************************************************************************
TASK [Print Name tag] **********************************************************************************************************
ok: [ansible-target-node04] => {
"msg": "ansible-target-node04"
}
ok: [ansible-target-node05] => {
"msg": "ansible-target-node05"
}
PLAY RECAP *********************************************************************************************************************
ansible-target-node04 : ok=1 changed=0 unreachable=0 failed=0 skipped=0 rescued=0 ignored=0
ansible-target-node05 : ok=1 changed=0 unreachable=0 failed=0 skipped=0 rescued=0 ignored=0
# EC2インスタンス ansible-target-node04 のみ実行する
$ ansible-playbook -i inventory/aws_ec2.yml sample.yml -e "target_hosts=ansible-target-node04"
PLAY [Example dynamic inventory] ***********************************************************************************************
TASK [Print Name tag] **********************************************************************************************************
ok: [ansible-target-node04] => {
"msg": "ansible-target-node04"
}
PLAY RECAP *********************************************************************************************************************
ansible-target-node04 : ok=1 changed=0 unreachable=0 failed=0 skipped=0 rescued=0 ignored=0
キャッシュ
Cache プラグインを利用してインベントリ情報をキャッシュできます。aws_ec2.yml
に以下のように追記します。
# インベントプラグインのキャッシュ有効化
cache: yes
# キャッシュプラグイン。JSON形式のファイルで保持
cache_plugin: jsonfile
# キャッシュの有効期限(1時間)
cache_timeout: 3600
# キャッシュファイルの保存場所
cache_connection: $HOME/.ansible/aws_inventory
ansible.cfg
で設定できますが、インベントリプラグイン全体の設定ですので、インベントリプラグイン毎に設定をカスタマイズしたい場合は aws_ec2.yml
のようなインベントリファイルに記載します。
[inventory]
cache = yes
cache_plugin = jsonfile
cache_timeout = 3600
cache_connection = $HOME/.ansible/ansible_inventory
注意点としては、Ansible から EC2 インスタンスを作成する場合、キャッシュが更新されず作成した EC2 インスタンスの情報を取得できない可能性があります。
Discussion