AWS CLIでもっと快適に開発環境を起動する
最近、時間がないことを理由に開発環境構築だけで、私的にプログラムを全然書いていないのですが、忙しさを理由に平日のコーディングをサボってはいけないなと思えてきました。では、仕事を終えてコードを書こうと決心すると、
- AWSマネージメントコンソールにログイン
- Authyでワンタイムパスワードを確認して入力
- EC2メニューにアクセスして、インスタンスを起動
- ステータスチェックを終えたらパブリックDNSを確認
- Route53メニューにアクセスして、対象レコードのCNAMEをパブリックDNSで更新
という流れになりますが、まぁ面倒臭い!
これでは平日に帰ってきてからコード書く気力も失ってしまいます。そこで、今回はこの手順をAWS CLIを使うことで、コマンド一発で済ませるようにしてみます。
AWS CLIでインスタンスを起動
まず、EC2インスタンス起動までの手順は明らかに冗長ですよね。別にマネージメントコンソールにログインしなくても、ただインスタンスを起動するだけなら、AWS CLIで簡単にできます。導入や使用例は以下の記事で。
start-instanceコマンドで起動してみる
では早速、クライアントPCからインスタンスの起動をやってみましょう。
$ aws ec2 start-instances --instance-ids [インスタンスID] { "StartingInstances": [ { "InstanceId": "[インスタンスID]", "CurrentState": { "Code": 0, "Name": "pending" }, "PreviousState": { "Code": 80, "Name": "stopped" } } ] }
はい。起動できました。
冒頭で挙げた手順と比較すればだいぶ楽ですが、それでもインスタンスID直打ちって面倒臭いですね。いちいちインスタンスIDなんか覚えてられませんし。
せっかくインスタンスにはNameタグを付与しているので、それをベースにインスタンスの起動とかできないものかと模索してみたのですが、調べた限りでは、残念ながらそういった機能はなさそうでした。
さて、無いなら書きましょう。エンジニアなら当然ですよね。
Nameタグの値からインスタンスIDを取得
まず、実現するためにはNameタグの値からインスタンスIDを取得する手順が実現できなくてはいけません。幸いなことに、インスタンスの情報を取得するdescribe-instancesコマンドがあるので、これを使います。
オプションとして--filtersを設定することで、条件に合致するインスタンスの情報だけを取得することができます。今回はNameタグの値がapp1というインスタンスの情報を取得します。
$ aws ec2 describe-instances --filters "Name=tag-key,Values=Name" --filters "Name=tag-value,Values=app1" { "Reservations": [ { "OwnerId": "XXXXXXXXXX", "ReservationId": "r-XXXXXXX", "Groups": [], "Instances": [ { "Monitoring": { "State": "disabled" }, "PublicDnsName": null, "RootDeviceType": "ebs", "State": { "Code": 80, "Name": "stopped" }, "EbsOptimized": false, "LaunchTime": "2015-02-15T08:13:32.000Z", "PrivateIpAddress": "XXX.XXX.XXX.XXX", "ProductCodes": [], "VpcId": "vpc-XXXXXXX", "StateTransitionReason": "User initiated (2015-02-15 11:07:50 GMT)", "InstanceId": "i-XXXXXXX", "ImageId": "ami-XXXXXXXX", /* 中略 */ "VirtualizationType": "hvm", "Tags": [ { "Value": "app1", "Key": "Name" } ], "AmiLaunchIndex": 0 } ] } ] }
aws configurationでデフォルトの返り値フォーマットはJSONに指定しています。しかし、情報量が多くてわかりにくいですね。JSONのパースが必要です。
パースといえば、rubyやらpythonやらでスクリプトをガリガリ書くべきかもしれませんが、jqコマンドという便利なコマンドがあるらしいので、これを使います。brewコマンドでインストール。
$ brew install jq
jqコマンドを使うと、コマンドベースでJSONのパースができますので、describe-instancesコマンドの返り値をパイプで繋いでパースします。こんな感じ。
$ aws ec2 describe-instances --filters "Name=tag-key,Values=Name" --filters "Name=tag-value,Values=app1" | jq -r '.Reservations[].Instances[].InstanceId'
インスタンスIDの情報はJSONのReservations.Instance.InstanceIdに格納されるので、jqコマンドでこの値を指定します。出力にダブルクオーテーションが入ってくると邪魔なので、-rオプションを使います。
これでNameタグ名を入力することでインスタンスIDを返すスクリプトができました。
Nameタグの値からインスタンスを起動する
さて、後はこのインスタンスIDを使ってstart-instancesコマンドを実行するだけです。xargsとか使えばワンライナーでも書けるのですが、いちいち入力するのも面倒臭いほど長いコマンドになるので、bashスクリプトにまとめました。こんな感じです。
#!/bin/bash # example: sh instance-controler.sh [action] [name] # action -> [start,stop] # name -> ec2 tag name if [ $# -ne 2 ]; then echo "Error: Invalid argument count." 1>&2 exit 1 fi action=$1 name=$2 id=`aws ec2 describe-instances \ --filters "Name=tag-key,Values=Name" \ --filters "Name=tag-value,Values=${name}" | jq -r '.Reservations[].Instances[].InstanceId'` if [ ${id} ]; then if [ ${action} = "start" ]; then aws ec2 start-instances --instance-ids ${id} elif [ ${action} = "stop" ]; then aws ec2 stop-instances --instance-ids ${id} else echo "Error: Invalid action." 1>&2 exit 1 fi else echo "Error: ${name} instance not found." 1>&2 exit 1 fi
極めて簡単なスクリプトですが、一応停止もできるようにしてあります。実行が成功すれば、通常のstart-instancesやstop-instancesの返り値が標準出力で返ってきます。入力されたNameタグの値を検証せずにdescribe-instancesコマンドに渡すのはちょっと気持ち悪いですが、あくまでも個人利用専用なので、まぁよしとします。
cli53でRoute53のレコードを更新
さて、インスタンスの起動だけなら、このように単純なのですが、問題はここから。そう、起動したインスタンスのパブリックDNSを如何にしてRoute53に自動で登録させるかですね。
とはいえ、Route53に対する操作もAWS CLIを用いればできるはずですから、そこまで難しくないはず。AWS CLIを使ってもできるのですが、用意されている機能では、レコードの更新のためにJSONを用意して、それをインポートするような形にならざるを得ないようで、ちょっと面倒臭いです。
そこで、単純なコマンドでRoute53に対する操作ができるcli53を使って、レコード更新を自動化してみましょう。
cli53のインストール
cli53はGitHubで公開されているスクリプトです。GitHubからバイナリを落としてきてもよいのですが、pipでインストールしたほうが楽そうなので、pipでインストールしましょう。
$ sudo pip install cli53
helpを見てインストールできたか確認
$ cli53 --help usage: cli53 [-h] [-d] [--logconfig LOGCONFIG] {info,xml,create,list,instances,export,rrdelete,rrcreate,import,rrlist,rrpurge,delete} ... route53 command line tool positional arguments: {info,xml,create,list,instances,export,rrdelete,rrcreate,import,rrlist,rrpurge,delete} sub-command help list list hosted zones info get details of a hosted zone export export dns in bind format import import dns in bind format instances dynamically update your dns with instance names create create a hosted zone delete delete a hosted zone rrcreate create a resource record rrdelete delete a resource record rrpurge purge all resource records rrlist list all resource records optional arguments: -h, --help show this help message and exit -d, --debug Turn on debugging --logconfig LOGCONFIG Specify logging configuration
よさそう。
自身のインスタンスのパブリックDNSを取得する
まず、インスタンス上で自身のパブリックDNSを取得する方法を確認します。
AWSでは、パブリックDNSなどのインスタンスメタデータを取得する方法が公式に案内されています。以下のように、URLをcurlコマンドなどで叩けば取得できます。
$ curl -s http://169.254.169.254/latest/meta-data/public-hostname
これで返り値が実行したインスタンスのパブリックDNSになります。接続先のIPアドレスは固定らしいですね。
後は、この値を引数に、cli53コマンドを叩くだけです。
cli53で自身のパブリックDNSをRoute53に登録する
cli53コマンドを使うと、以下のようなコマンドでRoute53のレコード更新ができます。
$ cli53 rrcreate example.com www CNAME [パブリックDNS名] -x 60 -r
rrcreateはレコードの作成を行う明示です。第1引数にドメイン、第2引数にサブドメイン、第3引数に種別、第4引数にセットする値を記述します。-xオプションはTTLの設定で、-rオプションはレコードを更新するという意味です。
これでRoute53のレコード更新ができますので、パブリックDNS取得とあわせて、パイプで繋いでやれば、自分のパブリックDNSをRoute53に登録するスクリプトのできあがりです。
$ curl -s http://169.254.169.254/latest/meta-data/public-hostname | xargs -i cli53 rrcreate example.com www CNAME {} -x 60 -r --replace
あ、もちろん、対象のインスタンスにはRoute53に対するフルアクセス権限をIAM roleで指定してあげないとダメですよ。僕はIAM roleをNoneにしてインスタンスを作成してしまっていたので、AMI Imageとって、最初から作りなおしました。こういった作業も一瞬でできちゃうのはいいことですね。
crontabに登録して、起動時にパブリックDNSをRoute53に自動登録
このコマンドをインスタンス起動時に実行させるだけです。crontabの@rebootに記載します。
$ crontab -e @reboot curl -s http://169.254.169.254/latest/meta-data/public-hostname | xargs -i cli53 rrcreate example.com www CNAME {} -x 60 -r --replace
これで起動時に自動でRoute53にパブリックDNSを登録してくれます!
あれだけ複雑だった手順が
$ sh instance-controller.sh start app1
だけで解決するようになったわけですから、非常に有益だと言えるでしょう。
まとめ
これで毎日のコーディングが楽になりますね
やはり面倒なオペレーションは簡単する努力をしないといけませんね。ただ、あまりこういった作業に手間をかけ過ぎると開発が進まないという問題はありますが・・・
環境はとりあえず構築できたので、バリバリFuelPHPでコード書いていきます!
参考
aws-cli ec2 describe-instances --filterオプションでタグの値を指定する
# describe-instancesコマンドでハマったときに助けていただきました。
jq コマンドを使う日常のご紹介 - Qiita
# jqコマンドについて。否定論もあるようですが、あれば便利だなと思います。
jq コマンドが強力すぎてヤバい件 | CUBE SUGAR STORAGE
# jqコマンドで色々できるよという話。大変参考になりました。
barnybug/cli53 · GitHub
# cli53のGitHubページ。基本的な導入方法や使用方法はこちらで。
EC2インスタンス起動時にRoute53のリソースレコードを更新する - azuki note
# Route53の自動登録はほぼこちらの記事を参考にさせていただきました。ありがとうございます。
cli53 | インフラ関係のメモ書き
# cli53の操作方法で色々参考になりました。