AWS
Ansible

Ansible Dynamic Inventoryを使ってAWSのEC2インスタンスに付与されたタグでプロビジョニング対象を決める

More than 3 years have passed since last update.

http://docs.ansible.com/ansible/intro_dynamic_inventory.html#example-aws-ec2-external-inventory-script

これの話です。


何がやれるのか

こんな感じにタグ付けした時に、インベントリファイルに対象ホストのIPとかを直接書かずにタグ名でホストを扱うことができます。

インベントリファイルにこんな風に書いたのと同じ動作になります。


インベントリファイル

[tag_role_api]

xxx.xxx.xxx.xxx
[tag_role_db]
yyy.yyy.yyy.yyy

ec2を使うとサーバーのIPがコロコロ変わるのでインベントリファイルにIPを直で書くとインベントリファイルを都度都度更新することになってしまうので有用な方法です。


やり方


AWSのAPIを内部的に使用するのでアクセスキーが必要

EC2のread/writeが可能な権限を持ったIAMアカウントのAPIキーが必要です。AWSコンソールで事前に作っておく必要があります。

そして、環境変数にセットします。

export AWS_ACCESS_KEY_ID='AK123'

export AWS_SECRET_ACCESS_KEY='abc123'


ec2.py, ec2.iniを取得する

https://github.com/ansible/ansible/tree/devel/contrib/inventory このへんにいっぱいあるので取得します。見たらわかると思いますが、EC2以外にもいろんなクラウド用があります。


インベントリのディレクトリ構造

playbook

├── site.yml
├── hosts
│   ├── prod
│   │   ├── ec2.ini
│   │   └── ec2.py
│   └── stg
│      ├── ec2.ini
│       └── ec2.py
└── roles


ec2.iniをカスタマイズ


使わない種類のものを対象にしない

なんかエラーが出たのでroute53,RDS,elasticacheはFalseに設定しました。

# To tag instances on EC2 with the resource records that point to them from

# Route53, uncomment and set 'route53' to True.
route53 = False

# To exclude RDS instances from the inventory, uncomment and set to False.
rds = False

# To exclude ElastiCache instances from the inventory, uncomment and set to False.
elasticache = False


stageを絞るためにinstance_filtersを指定


hosts/stg/ec2.ini

# Filters are key/value pairs separated by '=', to list multiple filters use

instance_filters = tag:stage=stg


hosts/prod/ec2.ini

# Filters are key/value pairs separated by '=', to list multiple filters use

instance_filters = tag:stage=prod


試してみる


まずはec2.pyが何を返すか見てみよう

$ k$ ./host/stg/ec2.py

{
"_meta": {
"hostvars": {
"52.69.149.28": {
"ec2__in_monitoring_element": false,
:

JSON形式で色々とれてきます。重要なのはこの辺りです。

  "tag_role_api": [

"52.69.236.80"
],
"tag_role_db": [
"52.69.149.28"
],
"tag_stage_stg": [
"52.69.236.80",
"52.69.149.28"
],

tag_タグ名_タグの値という名前が付けられています。

これがAnsbleで言うグループ名になります。


-m ping してみる

$ ansible -i host/stg all -m ping

52.69.149.28 | success >> {
"changed": false,
"ping": "pong"
}

52.69.236.80 | success >> {
"changed": false,
"ping": "pong"
}

$ ansible -i host/stg tag_role_api -m ping

52.69.236.80 | success >> {
"changed": false,
"ping": "pong"
}


応用編


roleの兼任

dev環境とかはコスト削減の名のもとに、一個のサーバーにいろいろ入れて誤魔化せと言われます。

タグ名

stage
dev

role
api,db

こんな感じでroleの値をカンマ区切りにすると・・・tag_role_api_dbというグループでくくられます。


group of group


site.yml

---

- hosts: tag_role_api
roles:
- nginx
- tomcat
- hosts: tag_role_db
roles:
- mysql

こんなsite.ymlだったとすると、

$ ansible-playbook -i hosts/dev site.yml

とした時には空振ってしまいます。devのインベントリにはtag_role_api_dbというグループがあるだけで、tag_role_apitag_role_dbも無いからです。

ここにちょろっと書いてありますが、


hosts/dev/groupDefine

[tag_role_api_db]

[tag_role_api:children]
tag_role_api_db

[tag_role_db:children]
tag_role_api_db


こんなファイルを書くとtag_role_apitag_role_dbが定義されるので期待通り動くと思います。