Posted at

AWS-cli + route53でElasticIPを節約したお話

More than 3 years have passed since last update.

この記事はリクルートライフスタイル 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つです。


r53.sh

#!/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ですが、


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を含めながら行っていきたいな、と考えています。

長い文章を読んでいただき、ありがとうございました。それでは。