#はじめに
AnsibleにはAWSのリソースを操作できるモジュールが豊富に用意されています。
今回は、定番のEC2をAnsibleで管理してみます。
#やること
- EC2インスタンス作成
##ポイント
ec2モジュールは、セキュリティグループについては名前で指定できるのですが、サブネットはIDで指定する必要があります。
しかし、サブネットIDをAnsibleのYAMLに書きたくないので、サブネット名からIDを取得する実装とします。
#前提
AWS関連のモジュール実行にはbotoが必要です。
credential情報は環境変数かaws configure
でセットしてある必要があります。
下記リソースを前提に進めます。
- VPC
- AnsibleVPC
- キーペア
- keypair
- サブネット
- public-a
- public-c
- セキュリティグループ
- common
- web_server
#sample
以下のようなEC2インスタンスを作成します。
- testinstance1
- AmazonLinux
- アベイラビリティゾーンA
- セキュリティグループ
- common,web_server
- testinstance2
- AmazonLinux
- アベイラビリティゾーンC
- セキュリティグループ
- common
##ディレクトリ構成
site.yml
roles/
|--ec2/
| |--tasks/
| | |--main.yml
hosts/aws #inventory
host_vars/
|--localhost.yml
##inventory
AWSリソース関連モジュールはすべてlocalhostで実行するので、下記のようなインベントリファイルを用意します。
[aws]
localhost
##vars
こんな感じに変数を定義します。今回はhost_varsで定義しました。
---
my_vars:
aws:
common:
region: ap-northeast-1
vpc:
name: AnsibleVPC # ターゲットのVPC名
ec2:
testinstance1:
ami_image: ami-56d4ad31 # Amazon Linux
key_name: keypair # キーペア名
security_group:
- common
- web_server
instance_type: t2.micro
device_name: /dev/xvda
device_type: gp2
volume_size: 8 # EBSのディスクサイズ(GB)
subnet: public-a # サブネット名
assign_public_ip: yes
tags:
Name: testinstance1
Role: test
testinstance2:
ami_image: ami-56d4ad31 # Amazon Linux
key_name: keypair # キーペア名
security_group:
- common
instance_type: t2.micro
device_name: /dev/xvda
device_type: gp2
volume_size: 8 # EBSのディスクサイズ(GB)
subnet: public-c # サブネット名
assign_public_ip: yes
tags:
Name: testinstance2
Role: test
##Role
まずVPCを特定するためにidが必要ですが、こちらと同様、VPC名でidを取得します。
今回はリストではなくディクショナリとしてEC2インスタンスを定義しましたので、with_dict
でループさせます。
前述のように、サブネットはIDで指定する必要があるので、ec2_vpc_subnet_facts
モジュールでIDを取得します。
定義されたEC2インスタンスの全てのサブネット名とIDのディクショナリを作成し、後続taskで参照します。
あとはec2
モジュールで作成しますが、exact_count: 1
を指定することで重複作成を防止します(stop状態だと作成されてしまいますが)。
---
- name: vpc_id取得
ec2_vpc_net_facts:
region: "{{ my_vars.aws.common.region }}"
filters:
"tag:Name": "{{ my_vars.aws.vpc.name }}"
register: vpc_net_fact
check_mode: no
- debug: var=vpc_net_fact
- name: subnet id取得
ec2_vpc_subnet_facts:
region: "{{ my_vars.aws.common.region }}"
filters:
vpc_id: "{{ vpc_net_fact.vpcs[0].id }}"
"tag:Name": "{{ item.value.subnet }}"
with_dict: "{{ my_vars.aws.ec2 }}"
register: subnet_fact
when: my_vars.aws.ec2 is defined
- name: subnet dict作成
set_fact:
subnet_dict: >-
{%- set dict = {} -%}
{%- for i in range(subnet_fact.results|length) -%}
{%- set _ = dict.update({subnet_fact.results[i].subnets[0].tags.Name: subnet_fact.results[i].subnets[0].id}) -%}
{%- endfor -%}
{{ dict }}
when: my_vars.aws.ec2 is defined
- name: EC2インスタンスを作成
ec2:
image: "{{ item.value.ami_image }}"
instance_type: "{{ item.value.instance_type }}"
region: "{{ my_vars.aws.common.region }}"
key_name: "{{ item.value.key_name }}"
group: "{{ item.value.security_group }}"
vpc_subnet_id: >-
{%- set id = subnet_dict[item.value.subnet] -%}
{{ id }}
instance_tags: "{{ item.value.tags }}"
assign_public_ip: "{{ item.value.assign_public_ip }}"
private_ip: "{{ item.value.private_ip | default(omit) }}"
wait: yes
wait_timeout: 300
volumes:
- device_name: "{{ item.value.device_name }}"
device_type: "{{ item.value.device_type }}"
volume_size: "{{ item.value.volume_size }}"
delete_on_termination: true
count_tag:
Name: "{{ item.value.tags.Name }}"
exact_count: 1
user_data: |
#!/bin/bash
# 初期設定スクリプトなど
with_dict: "{{ my_vars.aws.ec2 }}"
register: ec2
when: my_vars.aws.ec2 is defined
- debug: var=ec2
##site.yml
---
- name: ec2
hosts: localhost
connection: local
roles:
- role: ec2
##実行
$ ansible-playbook -i hosts/aws -l localhost site.yml
#まとめ
ネット上のサンプルでもサブネットIDを指定している例がほとんどですが、実際YAMLで管理する場合、IDではなく名前の方が分かりやすいと思います。
参考になれば幸いです。
#参考