Using Ansible on AWS – EC2インスタンスを作成する
はじめに
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" } ] }
出来ました!
まとめ
導入の敷居が低くYAMLで記述するため簡易で分かりやすいことがAnsibleの強みだと思います。大規模で複雑なシステムではChefのように様々なパターンに対応できるツールのほうが便利だと思いますが、小規模であったり簡易であったりするパターンでは、Ansibleも候補の一つに出来るのでは無いでしょうか。