テンポラリ稼働な EC2 インスタンスから Route53 をダイナミック DNS っぽく使う

最近はコード書くより AWS の色んな機能を弄ってる方が楽しかったりするので、プログラマとしてのアイデンティティが揺らぎはじめている Mariyudu@どうせ野良だし楽しければいーんじゃねーの、です。はい、矜持もプライドも野末のどっかに忘れてきましたw

そんな訳で今、某サービスを構成するサーバを AWS EC2 上で開発中です。開発用のインスタンスだとキホン、作業の時だけ起動して料金を節約するってのがパターンだと思いますが、そんな時ちょっと不便なのが起動の度に変わってしまう IP やホスト名。そこで、このサービスのドメインもやはり AWS の Route53 (以下、R53)で DNS 運営していることもあり、インスタンス起動時に当該ホストの A レコードを書き換える仕組みをちょこちょこっと作ってみました。R53 de Dynamic DNS って感じですな。以下、手順です。

  1. R53 の認証や API 実行を行う Perl スクリプト dnscurl.pl をここからダウンロードして、適当なディレクトリ(例 : ~/bin/r53/)にインストールしてセットアップ(ここが参考になります)。
  2. インスタンス起動時に割り当てられた IP を調べて、当該 FQDN の A レコードの書き換え処理を行うシェルスクリプト(下記)を、同ディレクトリに配置(例 : ~/bin/r53/update-r53.sh)。

    #!/bin/sh
    
    cd ~/bin/r53/
    
    # 各種パラメータ(アカウント・ゾーンID・当該インスタンスのFQDN・TTL)
    KEYNAME="foobar@mariyudu.jp"
    ZONEID=XXXXXXXXXXXXX
    FQDN=develop001.mariyudu.jp
    TTL=300
    
    # 現在、DNS にセットされてる当該 FQDN の IP
    OLDIP=`/usr/bin/dig $FQDN +short`
    
    # インスタンス起動時に割り当てられた IP
    NEWIP=`/usr/bin/curl -s "http://169.254.169.254/2008-02-01/meta-data/public-ipv4"`
    
    # 上記パラメタを使って R53 API へリクエストする XML を生成
    TMPFILE="/tmp/update_r53.$$.xml"
    cat << EOS > $TMPFILE
    <?xml version="1.0" encoding="UTF-8"?>
    <ChangeResourceRecordSetsRequest xmlns="https://route53.amazonaws.com/doc/2010-10-01/">
     <ChangeBatch>
      <Comment>Update A Record of $FQDN</Comment>
      <Changes>
       <Change>
        <Action>DELETE</Action>
         <ResourceRecordSet>
          <Name>$FQDN.</Name>
          <Type>A</Type>
          <TTL>$TTL</TTL>
          <ResourceRecords>
           <ResourceRecord>
            <Value>$OLDIP</Value>
           </ResourceRecord>
         </ResourceRecords>
        </ResourceRecordSet>
       </Change>
       <Change>
        <Action>CREATE</Action>
         <ResourceRecordSet>
          <Name>$FQDN.</Name>
          <Type>A</Type>
          <TTL>$TTL</TTL>
          <ResourceRecords>
           <ResourceRecord>
            <Value>$NEWIP</Value>
           </ResourceRecord>
         </ResourceRecords>
        </ResourceRecordSet>
       </Change>
      </Changes>
     </ChangeBatch>
    </ChangeResourceRecordSetsRequest>
    EOS
    
    # dnscurl で R53 API を利用
    /usr/bin/perl dnscurl.pl --keyname $KEYNAME -- -H "Content-Type: text/xml; charset=UTF-8" -X POST --upload-file $TMPFILE https://route53.amazonaws.com/2010-10-01/hostedzone/$ZONEID/rrset > /dev/null 2>&1
    
    rm $TMPFILE
    


  3. 上記スクリプトを、インスタンス起動時に実行するようにする(下記のように @reboot ディレクティブを使って crontab 登録するのがお手軽)。

    @reboot /bin/sh ~/bin/r53/update-r53.sh
    


以上っす。「別に Elastic IP をアサインしておきゃいーんじゃね? 1日の2/3くらい使わなくても、それで発生する料金なんて月数百円くらいだし」という意見が圧倒的かと思いますがw、まあそれでもインスタンスが数十台くらいになったらちょっとした節約になるかと。

それから、上記 update-r53.sh では A レコードの書き換えの際に、R53 API に編集という手段が用意されていないっぽいので、当該 A レコードを削除してから再度追加するという手順になっていますが、その削除がクセ者。FQDN だけでなく TTL まで現状と一致したものを指定してやらないとエラーになっちゃいます。なので、例えば TTLスクリプトで定義されている300秒から後で手動で変更したりすると、この仕組みは上手く動かなくなってしまうのでご注意を。ちゃんと API 経由で A レコードを問合せした上で削除→追加してやれば良いんでしょうが、時間がなかったので。