Ansible

aws上に作成したansibleサーバーでテストサイトを構築する(3) EC2インスタンスの作成

More than 1 year has passed since last update.

はじめに

前回までで、AWSのテストサイト用のVPCとネットワーク、キーペアの作成までできました。
今回はEC2インスタンスを登録、SSHにて接続するまでを実装します。

インベントリファイル作成

まずは作成するインスタンスを記載したインベントリファイルを作成します。
とりあえず、Webサーバーを1台登録。

inventories/hosts
[webapps]
web01 type="t2.micro" image="ami-2a69be4c" secgrp="SG_webapps" subnet="webapp1"

ここで指定している変数は以下の通り。

変数名 ここでの設定値 備考
type t2.micro EC2インスタンスの種類
無料枠で使用できるものを選択
image ami-2a69be4c 構成に使用するAMIの指定
同じく無料枠で使用できるものを選択
secgrp SG_webapps インスタンスに適用するセキュリティグループ
前回作成したセキュリティグループを指定
subnet webapp1 インスタンスが所属するサブネット名
こちらも前回作成したもの

ansibleコマンドに毎回-iオプションを指定しなくてもいいように、ansible.cfgを作成し、以下の設定を行います。

ansible.cfg
[defaults]
inventory = ./inventories

EC2インスタンス作成

EC2インスタンスを作成するロールaws_ec2を新しく作成することにします。

まず、呼び出すaws_infra.ymlを修正。
このロールはインベントリに記載した全ホストに対して実行したいのでhosts: allのPlayとして追加します。
AWSに対するEC2作成要求はAnsibleサーバー(localhost)から実行しなければいけないので、'connection: local'を設定。

aws_infta.yml
- hosts: localhost
  roles:
  - { role: aws_network, tags: [aws_network] }

- hosts: all
  connection: local
  roles:
  - { role: aws_ec2, tags: [aws_ec2] }

インスタンス配置先のサブネットIDが必要となるため、ec2_vpc_subnet_factsモジュールを使用して情報を取得します。

roles/aws_ec2/tasks/main.yml
---
- name: get subnet id
  ec2_vpc_subnet_facts:
    region: "{{ vpc.region }}"
    filters:
      "tag:Name": "{{ subnet }}"
  register: aws_get_subnet

取得したサブネットIDと、インベントリファイルに記載した情報を使ってEC2インスタンスを作成するタスクを作成します。
exact_countcount_tagを使用して、同じインスタンスが複数起動されることのないようにします。

roles/aws_ec2/tasks/main.yml(追記)
- name: create ec2 instance
  ec2:
    instance_tags:
      Name: "{{ inventory_hostname }}"
    key_name: "{{ keypair.name }}"
    instance_type: "{{ type }}"
    image: "{{ image }}"
    wait: yes
    group: "{{ secgrp }}"
    vpc_subnet_id: "{{ aws_get_subnet.subnets[0].id }}"
    region: "{{ vpc.region }}"
    assign_public_ip: yes
    count_tag:
      Name: "{{ inventory_hostname }}"
    exact_count: 1
  register: aws_create_ec2

実行結果

$ ansible-playbook site.yml

PLAY [localhost] ***********************************************************************************************************

TASK [Gathering Facts] *****************************************************************************************************
ok: [localhost]

TASK [aws_network : create vpc] ********************************************************************************************
ok: [localhost]

TASK [aws_network : create vpc subnets] ************************************************************************************
ok: [localhost] => (item={u'cidr': u'172.22.1.0/24', u'az': u'ap-northeast-1a', u'name': u'webapp1'})
ok: [localhost] => (item={u'cidr': u'172.22.2.0/24', u'az': u'ap-northeast-1c', u'name': u'webapp2'})

TASK [aws_network : create internet gateway] *******************************************************************************
ok: [localhost]

TASK [aws_network : make subnet list] **************************************************************************************
ok: [localhost]

TASK [aws_network : Set up public subnet route table] **********************************************************************
ok: [localhost]

TASK [aws_network : create security group] *********************************************************************************
ok: [localhost] => (item={u'rules': [{u'to_port': 80, u'from_port': 80, u'cidr_ip': u'0.0.0.0/0', u'proto': u'tcp'}, {u'to_port': 443, u'from_port': 443, u'cidr_ip': u'0.0.0.0/0', u'proto': u'tcp'}, {u'to_port': 22, u'from_port': 22, u'cidr_ip': u'0.0.0.0/0', u'proto': u'tcp'}], u'name': u'SG_webapps', u'description': u'for WebApplication Servers'})

TASK [aws_network : create keypair] ****************************************************************************************
ok: [localhost]

TASK [aws_network : create keypair file] ***********************************************************************************
skipping: [localhost]

TASK [aws_network : keypair write] *****************************************************************************************
skipping: [localhost]

PLAY [all] *****************************************************************************************************************

TASK [Gathering Facts] *****************************************************************************************************
ok: [web01]

TASK [aws_ec2 : get subnet id] *********************************************************************************************
ok: [web01]

TASK [aws_ec2 : create ec2 instance] ***************************************************************************************
changed: [web01]

PLAY RECAP *****************************************************************************************************************
localhost                  : ok=8    changed=0    unreachable=0    failed=0
web01                      : ok=3    changed=1    unreachable=0    failed=0

Ansibleアクセス用hostsエントリ追加

作成したEC2にansibleサーバーからインベントリファイル上のホスト名でアクセスさせるため、EC2のグローバルIPをansibleサーバー上のhostsファイルに追加。
(ローカルのhostsをいじるより、もっといい方法があるはずだとは思いますが…)

roles/aws_ec2/tasks/main.yml(追記)
---
- name: write host list
  run_once: true
  become: true
  lineinfile:
    path: "/etc/hosts"
    create: true
    regexp: '{{ item }}.{{ vpc.name }}'
    state: present
    line: "{{ hostvars[item].aws_create_ec2.tagged_instances[0].public_ip }}    {{ item }} {{ item }}.{{ vpc.vpc_name }}"
  with_items: "{{ play_hosts }}"

ちなみに、hosts: allなPlayなので、それぞれのホストのタスクで書き込ませたほうがわかりやすいのですが、当初そのように実装したところ/etc/hostsへの書き込みが競合したのか一部のホストにて書き込まれない事象が発生したため、run_oncewith_items: play_hostsを使用して1回のタスクですべてのホスト情報を書き込ませています。

roles/aws_ec2/tasks/main.yml(失敗版)
---
- name: write host list
  become: true
  lineinfile:
    path: "/etc/hosts"
    create: true
    state: present
    regexp: '{{ inventory_hostname }}.{{ vpc.name }}'
    line: "{{ aws_create_ec2.tagged_instances[0].public_ip }}    {{ inventory_hostname }} {{ inventory_hostname }}.{{ vpc.vpc_name }}"

実行結果。

command
$ ansible-playbook site.yml

PLAY [localhost] ***********************************************************************************************************

TASK [Gathering Facts] *****************************************************************************************************
ok: [localhost]

TASK [aws_network : create vpc] ********************************************************************************************
ok: [localhost]

TASK [aws_network : create vpc subnets] ************************************************************************************
ok: [localhost] => (item={u'cidr': u'172.22.1.0/24', u'az': u'ap-northeast-1a', u'name': u'webapp1'})
ok: [localhost] => (item={u'cidr': u'172.22.2.0/24', u'az': u'ap-northeast-1c', u'name': u'webapp2'})

TASK [aws_network : create internet gateway] *******************************************************************************
ok: [localhost]

TASK [aws_network : make subnet list] **************************************************************************************
ok: [localhost]

TASK [aws_network : Set up public subnet route table] **********************************************************************
ok: [localhost]

TASK [aws_network : create security group] *********************************************************************************
ok: [localhost] => (item={u'rules': [{u'to_port': 80, u'from_port': 80, u'cidr_ip': u'0.0.0.0/0', u'proto': u'tcp'}, {u'to_port': 443, u'from_port': 443, u'cidr_ip': u'0.0.0.0/0', u'proto': u'tcp'}, {u'to_port': 22, u'from_port': 22, u'cidr_ip': u'0.0.0.0/0', u'proto': u'tcp'}], u'name': u'SG_webapps', u'description': u'for WebApplication Servers'})

TASK [aws_network : create keypair] ****************************************************************************************
ok: [localhost]

TASK [aws_network : create keypair file] ***********************************************************************************
skipping: [localhost]

TASK [aws_network : keypair write] *****************************************************************************************
skipping: [localhost]

PLAY [all] *****************************************************************************************************************

TASK [Gathering Facts] *****************************************************************************************************
ok: [web01]

TASK [aws_ec2 : get subnet id] *********************************************************************************************
ok: [web01]

TASK [aws_ec2 : create ec2 instance] ***************************************************************************************
ok: [web01]

TASK [aws_ec2 : write host list] *******************************************************************************************
changed: [web01] => (item=web01)

PLAY RECAP *****************************************************************************************************************
localhost                  : ok=8    changed=0    unreachable=0    failed=0
web01                      : ok=4    changed=1    unreachable=0    failed=0

hostsはこうなりました。

/etc/hosts
127.0.0.1       localhost localhost.localdomain localhost4 localhost4.localdomain4
::1             localhost localhost.localdomain localhost6 localhost6.localdomain6
xxx.xxx.xxx.xxx web01 web01.testsite

sshできることを確認。

command
$ ssh -i ~/.ssh/testsite_key.pem web01
The authenticity of host 'web01 (xxx.xxx.xxx.xxx)' can't be established.
ECDSA key fingerprint is bf:78:c8:fb:bb:a9:f2:33:ee:f4:8a:3a:a2:2b:07:3a.
Are you sure you want to continue connecting (yes/no)? yes
Warning: Permanently added 'web01,xxx.xxx.xxx.xxx' (ECDSA) to the list of known hosts.

       __|  __|_  )
       _|  (     /   Amazon Linux AMI
      ___|\___|___|

https://aws.amazon.com/amazon-linux-ami/2017.03-release-notes/
2 package(s) needed for security, out of 6 available
Run "sudo yum update" to apply all updates.
[ec2-user@ip-172-22-1-216 ~]$

次回

次回は作成したEC2上のAmazon Linuxに共通の設定を適用していきます。