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

  • 16
    Like
  • 0
    Comment
More than 1 year has 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が定義されるので期待通り動くと思います。