この記事は公開されてから1年以上経過しています。情報が古い可能性がありますので、ご注意ください。
渡辺です。
過去にも同様のエントリーが存在するのですが、AWSといえばEC2ということで、最新のAWSモジュールを利用してEC2インスタンスを作成してみます。
グループ変数でインスタンス定義を明確にする
可読性の高いグループ変数は、このシリーズのテーマです。 今回は、次のようなグループ変数でEC2インスタンスを定義したいと思います。
ec2:
- name: FrontWebA
instance_type: t2.small
image: ami-1a15c77b
instance_profile_name: web
key_name: dev-key
subnet_name: FrontA
group:
- Internal
- Mainte
root_volume_size: 8
assign_public_ip: false
- name: FrontWebC
instance_type: t2.small
image: ami-1a15c77b
instance_profile_name: web
key_name: dev-key
subnet_name: FrontC
group:
- Internal
- Mainte
root_volume_size: 8
assign_public_ip: false
EC2を作成するPlaybook
Playbookはこんな感じです。
- hosts: localhost
connection: local
gather_facts: False
become: False
tasks:
- name: Facts subnet
ec2_vpc_subnet_facts:
profile: "{{ profile }}"
region: "{{ region }}"
register: _subnet_facts
- debug: var=_subnet_facts verbosity=1
- name: "EC2"
ec2:
image: "{{ item.image }}"
instance_profile_name: "{{ item.instance_profile_name }}"
instance_type: "{{ item.instance_type }}"
key_name: "{{ item.key_name }}"
vpc_subnet_id: "{{ _subnet_facts.subnets | selectattr('tags.Name', 'defined') | selectattr('tags.Name', 'equalto', item.subnet_name) | map(attribute='id') | first }}"
group: "{{ item.group }}"
volumes:
- device_name: /dev/xvda
volume_type: gp2
volume_size: "{{ item.root_volume_size }}"
delete_on_termination: true
instance_tags:
Name: "{{ item.name }}"
count_tag:
Name: "{{ item.name }}"
exact_count: 1
assign_public_ip: "{{ item.assign_public_ip }}"
profile: "{{ profile }}"
region: "{{ region }}"
with_items: "{{ ec2 }}"
ec2_vpc_subnet_factsモジュールでサブネットIDを収集する
はじめに、EC2インスタンスを配置するサブネットの情報を取得するため、ec2_vpc_subnet_factsモジュールを実行します。
Ansibleでは多くの_facts
とサフィックスがついたモジュールが提供されており、様々な情報を取得するために利用できます。
AWS CLIであれば、describe
系のコマンドと考えて良いでしょう。
- name: Facts subnet
ec2_vpc_subnet_facts:
profile: "{{ profile }}"
region: "{{ region }}"
register: _subnet_facts
ここでは、filter
などのオプションは指定せず、指定したリージョンの全サブネットを取得し、register
で変数に格納しておきます。
実行結果は次のような形式です。
TASK [debug] *******************************************************************
ok: [localhost] => {
"_subnet_facts": {
"changed": false,
"subnets": [
{
"availability_zone": "ap-northeast-1c",
"available_ip_address_count": 250,
"cidr_block": "172.31.101.0/24",
"default_for_az": "false",
"id": "subnet-xxxxxxxx1",
"map_public_ip_on_launch": "false",
"state": "available",
"tags": {
"Name": "FrontC"
},
"vpc_id": "vpc-xxxxxxxx"
},
{
"availability_zone": "ap-northeast-1a",
"available_ip_address_count": 250,
"cidr_block": "172.31.100.0/24",
"default_for_az": "false",
"id": "subnet-xxxxxxxx2",
"map_public_ip_on_launch": "false",
"state": "available",
"tags": {
"Name": "FrontA"
},
"vpc_id": "vpc-xxxxxxxx"
}
]
}
}
ec2モジュール
ec2モジュールはEC2インスタンスの構成管理だけでなく、stop/startなどもサポートするモジュールです。 設定次第で色々とできてしまう点は注意してください。
- name: "EC2"
ec2:
image: "{{ item.image }}"
instance_profile_name: "{{ item.instance_profile_name }}"
instance_type: "{{ item.instance_type }}"
key_name: "{{ item.key_name }}"
vpc_subnet_id: "{{ _subnet_facts.subnets | selectattr('tags.Name', 'defined') | selectattr('tags.Name', 'equalto', item.subnet_name) | map(attribute='id') | first }}"
group: "{{ item.group }}"
volumes:
- device_name: /dev/xvda
volume_type: gp2
volume_size: "{{ item.root_volume_size }}"
delete_on_termination: true
instance_tags:
Name: "{{ item.name }}"
count_tag:
Name: "{{ item.name }}"
exact_count: 1
assign_public_ip: "{{ item.assign_public_ip }}"
profile: "{{ profile }}"
region: "{{ region }}"
with_items: "{{ ec2 }}"
ec2モジュールでは、instance_profile_name
にはプロファイル名を、instance_type
にはインスタンスタイプを、と想像通りのパラメータを持ちます。
ポイントとなるパラメータに絞って解説しますので、それ以外のパラメータはドキュメントを参照してください。
image
image
にはイメージIDを指定します。
image: "{{ item.image }}"
今回はイメージIDをグループ変数に直接定義しましたが、最新のAmazon Linuxなど動的にイメージIDを取得することもできます。 取得する場合は、AWS CLIを実行してもよいですが、ec2_ami_findモジュールも利用できます。
vpc_subnet_id
vpc_subnet_id
はサブネットIDを指定します。
IDであるため、グループ変数でIDを指定するか、動的に取得するかの二択ですが、今回はec2_vpc_subnet_factsモジュールを使って動的に取得しています。
Jinja2のフィルタ機能を利用し、タグ名から要素をフィルタし、IDのみを抽出しました。
_subnet_facts.subnets | selectattr('tags.Name', 'defined')
| selectattr('tags.Name', 'equalto', item.subnet_name)
| map(attribute='id') | first
group
group
にはセキュリティグループ名のリストを指定します。
group: "{{ item.group }}"
グループ変数に定義された名前でセキュリティグループを適用するので、IDを指定する必要がありません。
なお、group_id
を利用してID指定も可能です。
count_tag, exact_count
count_tag
とexact_count
はセットで利用します。
このパラメータは、AnsibleからEC2インスタンスを識別するために利用します。
count_tag:
Name: "{{ item.name }}"
exact_count: 1
count_tag
がEC2を識別するためのタグを定義します。
ここでは、Nameタグとその値を指定しました。
count_tag
で識別したインスタンスが存在する場合、EC2インスタンスを新しく作成しません。
exact_count
は識別したインスタンスが幾つ存在すべきかを定義します。
ここでは、1を指定しているため、識別したインスタンスが1つあれば、それ以上のEC2インスタンスを作成しません。
通常、Nameタグで指定したEC2インスタンスの名前でインスタンスが識別できれば良いので、この設定を覚えておくと良いでしょう。
まとめ
ec2モジュールでEC2インスタンスを作成する時には、count_tag
とexact_count
を利用し、EC2インスタンスの識別方法を定義することがポイントです。
また、可読性の高いグループ変数の定義があれば、EC2インスタンスの仕様書となります。
宣言的で解りやすい仕様書があれば、構築作業もスムーズに進むことでしょう。