Home > Ansible | AWS > Ansible で EC2 インスタンスを起動して、Route53 に Public DNS を登録する

Ansible で EC2 インスタンスを起動して、Route53 に Public DNS を登録する

この記事の所要時間: 1452

Ansible は、構成管理ツールとして認知されていますが、AWS 関連のモジュールが多数実装されており、各コンポーネントの起動や設定ができます。

th_ansible_logo_black_square

このエントリでは、Ansible で、検証環境用の EC2 インスタンスを起動して、その Public DNS をRoute 53 に登録してみます。

以前書いたこのエントリの内容 を Ansible で自動化するイメージですね。

準備

今回は、AWS を操作するので、Python の AWS SDK である boto をインストールしておきます。boto は、pip なり、yum なりでインストールできます。

  • OSX
$ pip install boto
  • RHEL / CentOS
$ rpm -ivh http://ftp.riken.jp/Linux/fedora/epel/6/i386/epel-release-6-8.noarch.rpm
$ yum -y install python-boto

AWS 認証情報

AWS 認証情報を設定します。

playbook に直接記載する方法もあるのですが、ここでは、boto の設定ファイルである ~/.boto に記述をします。こうしておけば、playbook では、認証情報を指定する必要がありません。

[Credentials]
aws_access_key_id = xxxxxxxxxxxxxxx
aws_secret_access_key = xxxxxxxxxxxxxxx

EC2 インスタンスの起動

Ansible で EC2 インスタンスを起動するには、ec2 モジュールを使います。

AWS 関連のモジュールを使う場合、対象のインベントリが指定できない場合がある(対象のホストをこのタスクで生成するので)ので、local connection として実行します。

ec2 モジュールには、EC2 インスタンスを起動するためのパラメータを指定します。下記では、VPC で、t2.micro インスタンスを指定しています。各パラメータについては、EC2 インスタンスを起動する際は、お馴染みのものなので、値を指定していきます。あとで識別できるように Name タグに ansible1 を設定しておきます。

ここで起動したインスタンスの Public DNS を、Route 53 に登録するので、register を使って、処理結果をec2という変数に格納しておきます。

- hosts: localhost
  gather_facts: no
  connection: local
  tasks:
    - name: Create ec2 instanse
      ec2:
        key_name: keyA
        instance_type: t2.micro
        image: ami-0xxxxx
        monitoring: yes
        wait: yes
        region: ap-northeast-1
        group_id: sg-xxxxxx
        vpc_subnet_id: subnet-xxxxx
        assign_public_ip: yes
        instance_tags: 
          Name: ansible1
      register: ec2

Route 53 に Public DNS を CNAME に登録

あらかじめ決められた FQDN でアクセスできるように、先ほど起動したインスタンスの Public DNS を CNAME として Route 53 に登録します。

Route 53 の操作には、route53 モジュールを使います。

EC2 インスタンスの情報は、ec2.instances に格納されているので、これを利用します。下記では、ansible1.dev.example.com という FQDN に対して、ec2 の Public DNS を CNAME で割り当てています。

    - name: Set Public DNS to CNAME in Route53
      route53:
        command: create
        zone: dev.example.com
        type: CNAME
        value: "{{ item.public_dns_name }}"
        overwrite: yes
        record: ansible1.dev.example.com
        ttl: 300
      with_items: ec2.instances

playbook の実行

この playbook を ansible-playbook コマンドで実行します。

local connection を使うのですが、インベントリファイルが必要になるので、作成しておきます。

$ cat > hosts <EOF
127.0.0.1
EOF

では、実行してみましょう。ansible-playbook コマンドを実行すると、2 つのタスクが処理されました。

$ ansible-playbook -i hosts aws.yml

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

TASK: [Create ec2 instanse] ***************************************************
changed: [localhost]

TASK: [Set Public DNS to CNAME in Route53] *********************************************
changed: [localhost] => (item={......})

PLAY RECAP ********************************************************************
localhost                  : ok=2    changed=2    unreachable=0    failed=0

AWS の Management Console を確認すると、Name タグに ansible1 が設定されたインスタンスが生成されていました。

ansible-aws-ec2

Route 53 を見ると、想定したいた FQDN の CNAME に EC2 インスタンスの Public DNS が設定されていました。

ansible-aws-route53

起動済の EC2 を破棄

EC2 インスタンスを起動して、Route 53 に登録するという流れはできました。

ただ、このままだと、この playbook を実行する度に新しいインスタンスが作成されるので、不要なインスタンスが残り続けます。そこで、今回は検証環境ということで、古いインスタンスは破棄した後に、新しいインスタンスを作るという流れにします。

起動済のインスタンスを破棄するには、稼働中のインスタンス ID を取得する必要があります。インスタンス ID はec2_factsモジュールを実行します。このモジュールは、インスタンス内で実行するので、インスタンスをインベントリファイルに追加する必要があります。

これを手で行うと、インスタンスを起動するたびにインベントリファイルを書き換えることになるので、Dynamic Inventory を利用します。Dynamic Inventory は、インベントリ情報をスクリプト等で動的に生成することができる仕組みです。これを使うことで、AWS から稼働中のインスタンス情報を取得して、各インスタンスをインベントリとして、タスクを実行することができます。

Ansible のソースコードには、稼働中の EC2 インスタンス情報を取得するスクリプト(plugins/inventory/ec2.py, plugins/inventory/ec2.ini)が含まれているので、これを利用します。

https://github.com/ansible/ansible/blob/devel/plugins/inventory/ec2.py
https://github.com/ansible/ansible/blob/devel/plugins/inventory/ec2.ini

ec2.py はインベントリを取得するスクリプトで、ec2.ini がその設定ファイルです。

まず、ec2.ini の設定を変更します。ec2.py は、デフォルトでは取得した情報をキャッシュ仕組みになっているのですが、今回は実行時に最新の情報を取得したいので、このキャッシュを無効にします。

$ vim ec2.ini
cache_max_age = 300 # デフォルトは 300 秒なので、0 にする
↓
cache_max_age = 0

次に、playbook にインスタンス情報を取得するタスクを追加します。このタスクは、先頭に記述しておきます。hosts には、tag_Name_ansible1を指定しています。これは ec2.py で動的に取得したインベントリの内、タグ Name の値が ansible1 のホストを対象にするということです。このように ec2.py では稼働中の全インスタンスを利用するだけでなく、タグやインスタンスタイプなど様々な切り口でインベントリを絞り込むことができます。

---
- hosts: tag_Name_ansible1
  gather_facts: no
  user: root
  tasks:
    - ec2_facts:

つづいて、取得したインスタンス情報を使って、インスタンスを破棄します。インスタンスの破棄には ec2 モジュールを利用します。state=absentを指定することで、instance_idsで指定したインスタンスが破棄されます。

下記では、with_items で、インスタンスID を指定しているので、タグ名が ansible1 のインスタンスは全て破棄されます。

- hosts: tag_Name_ansible1
  gather_facts: no
  connection: local
  tasks:
    - name: Remove ec2 previous instances
      ec2: state=absent
           region=ap-northeast-1
           instance_ids={{ item }}
           wait=true
      with_items: ansible_ec2_instance_id

完成した playbook の実行

playbook が完成しました。実行してみましょう。

-iオプションで、ec2.py を指定して、下記のように実行します。

実行すると下記の流れでタスクが実行されていきます。これで、何度実行しても起動しているインスタンスは一つのみになりました。

  1. タグ名=ansible1 の EC2 インスタンス情報取得
  2. 1 で取得した EC2 インスタンスを破棄
  3. EC2 インスタンス作成
  4. 3 で作成したインスタンスの Public DNS を Route 53 に登録
$ ansible-playbook -i ec2.py aws.yml

PLAY [tag_Name_ansible1] ******************************************************

TASK: [ec2_facts ] ************************************************************
ok: [xxx.xxx.xxx.xxx]

PLAY [tag_Name_ansible1] ******************************************************

TASK: [Remove ec2 previous instances] *****************************************
changed: [xxx.xxx.xxx.xxx] => (item=i-xxxxxx)

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

TASK: [Create ec2 instanse] ***************************************************
changed: [localhost]

TASK: [Set Public DNS to CNAME in Route53] *********************************************
changed: [localhost] => (item={...})

PLAY RECAP ********************************************************************
xxx.xxx.xxx.xxx            : ok=2    changed=1    unreachable=0    failed=0
localhost                  : ok=2    changed=2    unreachable=0    failed=0

最終的な playbook は以下です。

---
- hosts: tag_Name_ansible1
  gather_facts: no
  user: root
  tasks:
    - ec2_facts:

- hosts: tag_Name_ansible1
  gather_facts: no
  connection: local
  tasks:
    - name: Remove ec2 previous instances
      ec2: state=absent
           region=ap-northeast-1
           instance_ids={{ item }}
           wait=true
      with_items: ansible_ec2_instance_id

- hosts: localhost
  gather_facts: no
  connection: local
  tasks:
    - name: Create ec2 instanse
      ec2:
        key_name: keyA
        instance_type: t2.micro
        image: ami-0xxxxx
        monitoring: yes
        wait: yes
        region: ap-northeast-1
        group_id: sg-xxxxxx
        vpc_subnet_id: subnet-xxxxx
        assign_public_ip: yes
        instance_tags: 
          Name: ansible1
      register: ec2

    - name: Set Public DNS to CNAME in Route53
      route53:
        command: create
        zone: dev.example.com
        type: CNAME
        value: "{{ item.public_dns_name }}"
        overwrite: yes
        record: ansible1.dev.example.com
        ttl: 300
      with_items: ec2.instances

さいごに

Ansible で AWS を操作してみました。

インスタンス情報の取得やその情報の利用(インスタンス破棄)などは少しコツが必要ですが、それさえ分かれば、思ったとおりに動作しました。はじめは同じことを Terraform で行っていたのですが、プロビジョンには Ansible を使っていたので、どうせなら Ansible で完結させようと思い、試してみました。

このエントリでは、AWS の操作のみ行っていますが、実際は、インスタンス生成後にプロビジョンやデプロイを行う playbook を挟む形になります。こうすれば、EC2 インスタンス生成、プロビジョン、デプロイが Ansible だけで行うことができます。

Pocket

follow us in feedly

Home > Ansible | AWS > Ansible で EC2 インスタンスを起動して、Route53 に Public DNS を登録する

検索
フィード
メタ情報

Return to page top