Using Ansible on AWS – EC2インスタンスを作成する

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

はじめに

AWSでのプロビジョニングは、AWS公式サイトのドキュメント(AWS CloudFormation のアーティクルとチュートリアル)等にも記述されているように、CloudFormationを中心にPuppetやChefを組み合わせるという方法が多く使われています。

しかしPuppetもChefもサーバ/クライアント構成(またはスタンドアロン)で動作するシステムであるため、サーバとクライアントの両方にソフトウェアをインストールする必要があります。またChefのCookbookは多機能である一方少々煩雑です。

もっと簡単な処理を手軽に行えたらなぁ...ということで、サーバサービス不要でYAMLで記述するプロビジョニングツールであるAnsibleを使ってみました。

Ansibleの良い所

  • sshdで接続してコマンドを投入するだけなので余計なサーバサービスの導入が不要。
  • YAMLなので記述が簡単、コメントも書ける。

Ansibleで出来ること

大きく二つあります。

  • モジュールを使ってリモートノードに対し単発でタスクを実行する。
  • Playbooksというモジュールやコマンドを組み合わせたタスクリストを記述し、リモートノードで実行する。

Ansibleのインストール

まずAnsibleをインストールするEC2インスタンスではIAM Role for EC2でPowerUsersに設定しておきます。理由はAnsibleのec2モジュールを使うときにいちいちaws_access_keyやaws_secret_keyを記述したくないからです。IAMは本当便利ですね!

AnsibleはEPELリポジトリからインストールする必要がありますが、Amazon Linux AMIは最初からEPELリポジトリへのアクセスが設定されているので、yumコマンドにてEPELリポジトリを指定してansibleをパッケージインストールします。

$ sudo yum -y install ansible --enablerepo=epel

設定と動作確認

インベントリファイルにAnsibleの管理対象ホストを記述します。FQDNでもIPアドレスでも記述可能です。まずは動作確認としてlocalhost(127.0.0.1)を記述してみました。

$ sudo vi /etc/ansible/hosts
127.0.0.1

Pingモジュールを使って動作確認してみます。

$ ansible --private-key=./.ssh/mykey.pem 127.0.0.1 -m ping
/usr/lib64/python2.6/site-packages/Crypto/Util/number.py:57: PowmInsecureWarning: Not using mpz_powm_sec.  You should rebuild using libgmp >= 5 to avoid timing attack vulnerability.
  _warn("Not using mpz_powm_sec.  You should rebuild using libgmp >= 5 to avoid timing attack vulnerability.", PowmInsecureWarning)
127.0.0.1 | success >> {
    "changed": false,
    "ping": "pong"
}

Ping自体は通っていますが、Warningメッセージが出ています。出てるメッセージの通り、python-cryptoパッケージはlibgmpのバージョンを5以上にしなさいとのことですが、Amazon Linuxにインストールされているgmpパッケージは「gmp-4.3.2-1.11.amzn1.x86_64」で、gmp-5のパッケージはリポジトリにありません。この事象についてはRedhatのSolutionsにも記載がありました(number.py in python-crypto requires libgmp >=5 to avoid PowmInsecureWarning in RHEL6)将来の解消に期待したいところですが、とりあえずAnsible自体はそのまま動くので先に進みます。

Playbooksを使ってみる

AWSらしく、EC2インスタンスを作成するPlaybookを書いてみます。

$ vi makeec2.yml
- hosts:
  - 127.0.0.1
  connection: local
  gather_facts: False
  tasks:
    - name: Provision a set of instances
      local_action: ec2
          keypair={{keypair}}
          group={{group}}
          instance_type={{instance_type}}
          image={{image}}
          region={{region}}
          wait={{wait}}
      register: ec2

PlaybookのSyntaxチェックを行います。ansible-playbookというコマンドを使います。

$ ansible-playbook --syntax-check ./makeec2.yml
Playbook Syntax is fine

次にPlaybookで行われるタスクを確認します。同じくansible-playbookコマンドを使います。

$ ansible-playbook --list-tasks ./makeec2.yml
playbook: ./makeec2.yml

  play #1 (127.0.0.1):
    Provision a set of instances

「Provision a set of instances」というタスク名(nameに記述したもの)が返ってきています。

それでは実際に動かしてみましょう!

$ ansible 127.0.0.1 -m ec2 -a "image=ami-be1c848e instance_type=t1.micro keypair=mykey group=ec2-servers region=us-west-2 wait=true" -c local
127.0.0.1 | success >> {
    "changed": true,
    "instance_ids": [
        "i-1e9XXXXX"
    ],
    "instances": [
        {
            "ami_launch_index": "0",
            "architecture": "x86_64",
            "dns_name": "ec2-54-201-XXX-XXX.us-west-2.compute.amazonaws.com",
            "hypervisor": "xen",
            "id": "i-XXXXXXXX",
            "image_id": "ami-be1c848e",
            "instance_type": "t1.micro",
            "kernel": "aki-fc8XXXXX",
            "key_name": "mykey",
            "launch_time": "2013-11-18T05:29:37.000Z",
            "placement": "us-west-2a",
            "private_dns_name": "ip-172-31-XXX-XXX.us-west-2.compute.internal",
            "private_ip": "172.31.XXX.XXX",
            "public_dns_name": "ec2-54-201-XXX-XXX.us-west-2.compute.amazonaws.com",
            "public_ip": "54.201.XXX.XXX",
            "ramdisk": null,
            "root_device_name": "/dev/sda1",
            "root_device_type": "ebs",
            "state": "running",
            "state_code": 16,
            "virtualization_type": "paravirtual"
        }
    ]
}

出来ました!

ansiec2

まとめ

導入の敷居が低くYAMLで記述するため簡易で分かりやすいことがAnsibleの強みだと思います。大規模で複雑なシステムではChefのように様々なパターンに対応できるツールのほうが便利だと思いますが、小規模であったり簡易であったりするパターンでは、Ansibleも候補の一つに出来るのでは無いでしょうか。