クラウドインテグレーションサービス「雲斗」のブログ

芝公園にある創研情報株式会社がAWS を 中心にクラウドの基本から便利な使いかたまでをお伝えしていきます。

Amazon EC2 Amazon Route53 AWS CLI

AWS CLIを利用してEC2のElasticIPを節約ぅ!

2018/08/31

最近、安室奈美恵さん引退という衝撃ニュースが駆け回っておりますが、一方では私の大好きな女性アーティストさんが、新譜を引っ提げてかなり久しぶり(=10年ぶり!)に活動再開され歓喜に沸いております。
このことに触発され、「自分も!」という気持ちがでてきています。
このブログ記事も、AWSに関するネタとかもっといっぱい書いていければと思ってます。

----------

【限りある資源、頭髪 Elastic IP】
Amazon EC2で仮想サーバを立てて様々な用途で使いだすと、知らず知らずにサーバが増えてきます。
サーバを起動しているとそれだけコストがかかりますので、開発や検証で一時的に起動、使い終わったら停止するといった運用を行うことも多くなりますね。

この時意外に面倒なのが、サーバに割り当てるグローバルIPアドレスの扱いです。
普段からEC2を利用されている方はお分かりかと思いますが、このグローバルIPアドレス、EC2を起動するたびにアドレスが変わってしまいますので、都度都度このIPアドレスを確認する必要があります。

用途によっては「これが固定されないと困るんだけど・・・」ということもあるかもしれません。
この悩みを解消してくれるのが「Elastic IP」と呼ばれる固定IPアドレスです。
このIPアドレスをAWSから払い出してもらい、EC2に割り当てることで、常にこのIPアドレスで接続ができるようになります。

しかし、このElastic IPですが、以下の条件をすべて満たさないと、別途利用料がかかってきます。
・EC2インスタンス1つに対して割り当てるElasticIPは1つまで
・割り当てたEC2インスタンスが利用中であること
つまり、EC2を停止している間はEC2の料金がかからない代わりにElastic IPの利用料はかかってきます。
また、1つのアカウントで付与できるElastic IPには上限(=デフォルトで1リージョンあたり5つまで)が設定されているため、必要だからといって無尽蔵にElastic IPを取得することはできません。

IPv4のグローバルIPアドレスは枯渇してきており、限りある資源は有効に利用する必要がある、ということですね。

【それでも、できるだけコストは削減したい】
最近、当社提供サービスの営業デモ向けにEC2のサーバ環境を構築したのですが、このサーバ環境、そこそこスペックが高いインスタンスタイプが必要です。
利用するメンバーが営業担当ということもあり、「いちいちサーバの停止/起動してIP調べて接続するのは大変!」と言われてしまいましたが、起動している時間がそれほど多くないこのサーバを起動しっぱなしにしておくことを容認できるほど安価なインスタンスタイプでもなく、さてどうするか・・・

IPが変わっても不変にできる情報・・・ドメイン名(FQDN)で接続できればいいかも!
すなわち、IPアドレスではなく、つねに同じドメイン(FQDN、例:hoge.kumoto.jp)で接続できるようにしておけばいける!

ということで、サーバ起動時に次のようなことができる簡単なバッチを作ってみました。
動きとしては、

(1)当該EC2サーバを起動。
(2)(1)のサーバに割り当てられたグローバルIP(Public IP)を取得。
(3)(2)のIPを、当社の権威DNS(=Route53)に当社ドメイン(FQDN、例:hoge.kumoto.jp)のAレコードとして割り当てる
(4)(3)のFQDNでサーバに接続する。

実現にあたっては、AWSのコマンドラインインターフェース(=CLI)を利用します。
普段はLinuxのコマンドのほうが慣れているのでシェルスクリプトで作りたかったのですが、営業担当が使っているPCがWindowsということもあるので、一部追加アプリケーションをインストールし、Linuxベースで作ったものを移植する形にしております。

<EC2起動ならびにDNS割り当てバッチの材料>
AWS CLI
jq
sed
④EC2サーバの起動/停止/情報確認、Route53のレコードセット追加/変更が可能な権限を持つIAMアカウント
⑤起動/停止制御するEC2インスタンスのインスタンスID
⑥ドメイン設定の対象となるRoute53レコードセットのホストゾーンID

<下ごしらえ>
(1)①~③のインストール、セットアップを完了しておきます。
(2)④のアカウント情報をAWS CLIの定義情報として登録しておきます。

<作ったWindows用バッチ>
以下のファイル群をすべて同じフォルダに配備します。

[startServer.bat] ※起動バッチ本体となります。

@echo off

rem 対象EC2インスタンスの起動
call startInstance

echo ec2起動処理完了。

rem DNS書き換え
call changeRecordSet

echo DNS設定完了。
echo サーバ環境の準備が完了しました。
echo 「hoge.kumoto.jp」に接続してください。
echo 何かキーを押してください。
pause > NUL
exit

[startInstance.bat]

@echo off

rem 変数設定
set INSTANCEID=i-xxxxxxxxxxxxxxxxx

rem 対象EC2インスタンスの起動
aws ec2 start-instances --instance-ids %INSTANCEID%
echo サーバ起動中です。しばらくお待ちください。 
rem 対象EC2インスタンスの起動待ち
aws ec2 wait instance-running --instance-ids %INSTANCEID%

* INSTANCEIDに⑤のインスタンスIDをセットします。

[changeRecordSet.bat]

@echo off

rem 変数設定
set INSTANCEID=i-xxxxxxxxxxxxxxxxx
set HOSTEDZONEID=ZZZZZZZZZZZZZZ

rem AWS CLIを使って、PublicIPを取得
for /f "usebackq tokens=*" %%i in (`aws ec2 describe-instances --instance-ids %INSTANCEID% ^| jq ".Reservations[0].Instances[0].NetworkInterfaces[0].PrivateIpAddresses[0].Association.PublicIp"`) do set PUBLICIP=%%i

chcp 932
echo 起動したサーバのIPアドレス: %PUBLICIP%

rem 設定ファイルset.jsonを削除
if EXIST "set.json" (
del set.json
)

rem テンプレートファイルを元にset.jsonを作成
sed -e "s/PUBLICIP/%PUBLICIP%/" set.json.tpl > set.json

rem Route53情報を書き換える
aws route53 change-resource-record-sets --hosted-zone-id %HOSTEDZONEID% --change-batch file://set.json

* INSTANCEIDに⑤のインスタンスIDをセットします。
** HOSTEDZONEの⑥のホストゾーンIDをセットします。

[set.json.tpl]

{
    "Comment": "create A record",
    "Changes": [
        {
            "Action": "UPSERT",
            "ResourceRecordSet": {
                "Name": "hoge.kumoto.jp.",
                "Type": "A",
                "TTL": 300,
                "ResourceRecords": [
                    {
                        "Value": "PUBLICIP"
                    }
                ]
            }
        }
    ]
}

* hoge.kumoto.jp にAレコードとして登録するFQDNを指定します。

[stopServer.bat] ※停止バッチとなります。

@echo off

rem 変数設定
set INSTANCEID=i-xxxxxxxxxxxxxxxxx

rem 対象EC2インスタンスの停止
aws ec2 stop-instances --instance-ids %INSTANCEID%
exit

-Amazon EC2, Amazon Route53, AWS CLI

Bitnami