Ansibleを使ってEC2インスタンスを立ち上げる

2015.03.11

この記事は公開されてから1年以上経過しています。情報が古い可能性がありますので、ご注意ください。

どうも、先週札幌エスタ10Fのとっぴ〜サーモンを満喫した横山です。 本日は用途を決めずに作業用にEC2をとりあえずたてたいときに流す、 Ansible Playbookのメモ書きです。

準備

AWSのクレデンシャルが通っていてAnsibleの入ったPC、 または、Amazon EC2 PowerUserAccess等のEC2を作成出来る権限Roleの付いているEC2。

上記を満たし、Ansibleの入ったPC。 → インストール手順参考: AWSチーム社内勉強会「Ansible」レポート

検証環境

# Mac
$ ansible --version
ansible 1.8.2
  configured module search path = None

# Linux ami 2014.09
$  ansible --version
ansible 1.8.2
  configured module search path = None

コード

Ansible 公式 ドキュメント もしくはansible-doc ec2の Examplesの「Launch instances, runs some tasks and then terminate them」を参考に書きました。

playbook.yml

- name: Create a sandbox instance
  hosts: localhost
  gather_facts: False
  vars:
    keypair: <キーペア名>
    instance_type: <インスタンスタイプ> #例: t2.micro, t2.small, t2.medium ... etc
    instance_profile_name: <IAM ロール名>
    instance_tags: <Tag> # 入力例: "Name='Test Ansible',Desc='Sample Ansible Playbook"
    security_group: <セキュリティグループID> 
    image: <AMI ID>
    region: <リージョン> #例:ap-northeast-1
  tasks:
    - name: Launch instance
      local_action: ec2 key_name={{ keypair }} group_id={{ security_group }} instance_type={{ instance_type }} instance_profile_name={{ instance_profile_name }} instance_tags={{ instance_tags }} image={{ image }} wait=true region={{ region }}
      register: ec2
    - name: Add new instance to host group
      local_action: add_host hostname={{ item.public_ip }} groupname=launched
      with_items: ec2.instances
    - name: Wait for SSH to come up
      local_action: wait_for host={{ item.public_dns_name }} port=22 delay=60 timeout=320 state=started
      with_items: ec2.instances

使い方

playbook.ymlvars セクションの山成カッコの部分を適宜変え、実行するホストをhostsファイルにlocalhostを追加する。

$ echo 'localhost' > hosts
$ ansible-playbook -i hosts playbook.yml

と実行。 実行結果は以下のように出力される。

$ ansible-playbook -i hosts playbook.yml
ansible-playbook -i hosts playbook.yml

PLAY [Create a sandbox instance] **********************************************

TASK: [Launch instance] *******************************************************
changed: [localhost -> 127.0.0.1]

TASK: [Add new instance to host group] ****************************************
ok: [localhost -> 127.0.0.1] => (item={u'ramdisk': None, u'kernel': None, u'root_device_type': u'ebs', u'private_dns_name': u'ip-172-xxx-xxx-xxx.ap-northeast-1.compute.internal', u'key_name': u'keypair-key', u'public_ip': u'xxx.xxx.xxx.xxx', u'image_id': u'ami-xxxxxxxx', u'private_ip': u'172.xxx.xxx.xxx', u'public_dns_name': u'ec2-xxx-xxx-xxx-xxx.ap-northeast-1.compute.amazonaws.com', u'state_code': 16, u'id': u'i-xxxxxxxx', u'placement': u'ap-northeast-1c', u'ami_launch_index': u'0', u'dns_name': u'ec2-xxx-xxx-xxxxxxxxxxxxxxxxxxxxxxxx-xxx.ap-northeast-1.compute.amazonaws.com', u'region': u'ap-northeast-1', u'ebs_optimized': False, u'launch_time': u'2015-03-11T05:56:45.000Z', u'instance_type': u't2.micro', u'state': u'running', u'root_device_name': u'/dev/xvda', u'hypervisor': u'xen', u'virtualization_type': u'hvm', u'architecture': u'x86_64'})

TASK: [Wait for SSH to come up] ***********************************************
ok: [localhost -> 127.0.0.1] => (item={u'ramdisk': None, u'kernel': None, u'root_device_type': u'ebs', u'private_dns_name': u'ip-172-xxx-xxx-xxx.ap-northeast-1.compute.internal', u'key_name': u'keypair-key', u'public_ip': u'54.92.44.132', u'image_id': u'ami-xxxxxxxx', u'private_ip': u'172.xxx.xxx.xxx', u'public_dns_name': u'ec2-xxx-xxx-xxx-xxx.ap-northeast-1.compute.amazonaws.com', u'state_code': 16, u'id': u'i-xxxxxxxx', u'placement': u'ap-northeast-1c', u'ami_launch_index': u'0', u'dns_name': u'ec2-xxx-xxx-xxx-xxx.ap-northeast-1.compute.amazonaws.com', u'region': u'ap-northeast-1', u'ebs_optimized': False, u'launch_time': u'2015-03-11T05:56:45.000Z', u'instance_type': u't2.micro', u'state': u'running', u'root_device_name': u'/dev/xvda', u'hypervisor': u'xen', u'virtualization_type': u'hvm', u'architecture': u'x86_64'})

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

また、以下のようなエラーに遭遇するかもしれません。 私はMac上で行ってる環境で遭遇しました。

$ ansible-playbook -i hosts playbook.yml

PLAY [Create a sandbox instance] **********************************************

TASK: [Launch instance] *******************************************************
failed: [localhost -> 127.0.0.1] => {"failed": true, "parsed": false}
failed=True msg='boto required for this module'


FATAL: all hosts have already failed -- aborting

PLAY RECAP ********************************************************************
           to retry, use: --limit @/Users/yokoyamafumihito/playbook.retry

localhost                  : ok=0    changed=0    unreachable=0    failed=1

$ python
Python 2.7.9 (default, Jan  7 2015, 11:49:12)
[GCC 4.2.1 Compatible Apple LLVM 6.0 (clang-600.0.56)] on darwin
Type "help", "copyright", "credits" or "license" for more information.
>>> import boto
>>>
>>> exit()

このエラーは こちら を参考に、 hostsファイルにansible_python_interpreterを指定すると動くのを確認出来ました。

$ cat hosts
localhost
$ echo "localhost ansible_python_interpreter=`which python`" > hosts
$ cat hosts
localhost ansible_python_interpreter=/usr/local/bin/python

まとめ

マネージコンソールでEC2インスタンスを作成するのが億劫になった時の参考になればと思います。 まだまだ扱いなれないので、 Ansibleでよく使うファイル操作モジュール を見て、 もっと扱いに慣れて行きたい思います。