この記事はリクルートライフスタイル Advent Calendar 2015 の20日目です。
ホットペッパービューティーで開発陣の周りをお手伝いしている、岡田賢治です。
はじめに
RLSにお世話になりまして、約半年が過ぎました。元は、オンプレサーバのサバ管で、いろいろスクリプトを書いていました。
こちらの環境で、AWSで作業することが非常に多くなりました。AWSは全くの素人だったので、ググりながらの日々が続きました。
作業内容としては、主にサーバの構築。サービスを提供するものや、サービスの検証・サービスのミラー等、様々なサーバを用意します。
サーバのインスタンスが増えるに当たり、増えるものと減るものが出てきます。
増えるもの
インスタンス数
ディスクの使用量
減るもの
ElasticIPの残り数
Elastic IP
AWSを利用するに当たり、最初に面食らったのがElasticIPでした。インスタンスの設定では、内部管理のプライベートIPの他、外部からアクセスできるグローバルIPを割り当てることが出来ます。
しかし、このグローバルIPはインスタンスの起動毎に変わるIP=Public IPになります。
「どうやれば固定できる・・・」で、発見したのがElasic IP(の使用方法)でした。
減ってゆくElastic IPの残り
Elastic IPは、有償でAWSから借り受けるものであり、どの利用者も無尽蔵に利用できるというわけではないと思います。もちろん正式サービスに利用するのであればいいのですが、当方のように「検証環境」とか「ミラー環境」を用意する身としては、常に在庫があるわけではありません。
すると何が始まるか・・・?検証環境のインスタンスを起動するたびに、Route53へAレコードを登録しなくてはいけなくなります。それを忘れて「繋がらない・・・」とハマったことも何度も・・・
要は何ができればいいの?
そもそもElastic IPを利用する理由は「インスタンス起動時に常に同じIPが割あたっている保証がほしい」からなわけです。
なぜ保証がほしいか?といえば「DNS(のAレコード)に、そう登録してあるから」なわけです。
ここでひらめいたのが、AWSのWebAPIを利用する方法です。
・そのインスタンスに割り振られたPublic IP(≠Elastic IP)は、取得ができる。
・DNS/Route53のAレコードは、WebAPIにより登録ができる。
となれば、「常に同じIPじゃなくても、起動時に割あたったPublic IPがそのままRoute53に登録してあるFQDNに割あたってくれればいいんじゃね?」となります。
スクリプトへの反映
そこで考えたスクリプトが以下の2つです。
#!/bin/bash
export PATH=/usr/local/sbin:/usr/local/bin:${PATH}
#変数設定
INSTANCEID=XXXXXXXXX
HOSTEDZONEID=XXXXXXXXX
# PublicIPが有効になるまで2分待つ
sleep 120 ;
cd /root
# AWS CLIを使って、PublicIPを取得
PUBLICIP=`aws ec2 describe-instances --instance-ids ${INSTANCEID} | jq ".Reservations[0].Instances[0].NetworkInterfaces[0].PrivateIpAddresses[0].Association.PublicIp"`
#PublicIPは、"XXX.XXX.XXX.XXX"の形式なので、XXX.XXX.XXX.XXXに変換する
PUBLICIP=`echo ${PUBLICIP} | sed -e 's/"//g'`
# 設定ファイルset.jsonを削除
if [ -f set.json ]; then
rm set.json ;
fi
# テンプレートファイルを元にset.jsonを作成
sed -e "s/PUBLICIP/${PUBLICIP}/" set.json.tmpl > set.json
# Route 53情報を書き換える
aws route53 change-resource-record-sets --hosted-zone-id ${HOSTEDZONEID} --change-batch file://set.json
exit ;
ここでは、
- 16行目でaws ec2 describe-instancesコマンドを利用して、対象インスタンスの情報を取得しています。対象インスタンスは6行目で指定したINSTANCEIDに設定したインスタンスIDです。
- ただしそのコマンドでは、起動直後にはインスタンス情報を取得できません(正確には、PublicIPが割当たるまでの時間差の関係で、PublicIPが取得できません)。有効になるまで一定時間待つ必要があります。ここでは120秒=2分としました(11行目)
- JSON形式で値が返りますので、jqコマンドとsedを使ってCIDR形式のIPアドレスに変換します(19行目)。
- AWS Route53に送るJSONデータを作成します(26行目)。テンプレートファイルset.json.tmplを元にして、set.jsonファイルを作成しています。
- 出来上がったset.jsonファイルを使って、Route53の情報を書き換えます(29行目)。
次にテンプレートファイルset.json.tmplですが、
{
"Comment": "create A record",
"Changes": [
{
"Action": "UPSERT",
"ResourceRecordSet": {
"Name": "XXXX.YYYY.ZZZZ.",
"Type": "A",
"TTL": 300,
"ResourceRecords": [
{
"Value": "PUBLICIP"
}
]
}
}
]
}
- Route53に登録するFQDNは"XXXX.YYYY.ZZZZ"です。
- PUBLICIPの文字列が、r53.shの中のsedコマンドでCIDR形式のIPアドレスに置き換わります(r53.sh:29行目)。
補足情報
上記スクリプトを動かすには、以下の条件が必要です。
- AWSのコマンド操作ツール群、aws-cliがインストールされていること。
- jqがインストールされていること。
- AWS/EC2に、インスタンスの情報取得が可能であるアクセス権(キー・シークレットキー等)を保持していること。
- AWS/Route53に、更新可能なアクセス権とそれに付随するHOSTZONEID情報を保持していること。
まとめ
プログラミングやら何やらいろいろやっていますが、自分のプログラミングの起源はUNIX/Linuxのサーバ管理で使った、スクリプト群が起源であることを最近痛感しています。
最近では、それがWebAPI/RestAPIになったりJSON形式が出てきたり、DevOpsという言葉が生まれたりと、昔を懐かしんでばかりもいられないな、というのが実情です。
仕事では、引き続き他のツール群との連携を取っていくつもりです。
プライベートでは・・・OpenStackをやっているので、AWSの比較をAPIを含めながら行っていきたいな、と考えています。
長い文章を読んでいただき、ありがとうございました。それでは。