EC2

y.kimura

こんにちは、R&D グループの y.kimura です。

今回は Amazon Web Service の EC2 に Route53 を利用して、
お好きなホスト名でアクセスできるようにしようというお話です。

AWS に固定ホスト名でアクセスするには、以下の方法が有名です。

  1. アクセスする端末の hosts ファイルを書き換える
    メリット: 余計な費用が掛からない
    デメリット: EC2 側の変更に追従するのが面倒
     
  2. EC2 の Elastic IPを割り当てる
    メリット: 5 つまでなら無料で割り当てられる
    デメリット: 5 つ以上 EC2 インスタンスに割り当てると、申請+追加料金が必要
     
  3. Route53 に登録する
    メリット: EC2 インスタンス数の制限が無いに等しい
    デメリット: 元々使用していれば問題ないですが、そうでない場合はRoute53 をこれだけのために利用する手間と費用がかかる
     

それぞれ一長一短ありますが、
私の関わっているプロジェクトで実際に採用している 3 番目の方法をご紹介します。

やることはいたって単純で、次の通りになります。

EC2インスタンスの起動/再起動時に次の処理を実行するスクリプトを走らせる。

  1. EC2インスタンス自身のメタデータを取得する
  2. メタデータ(もしくはタグ情報)を元にホスト名を決定する
  3. ホスト名を Route53 から削除する(古いホスト名)
  4. ホスト名を Route53 に登録する(レコード名=ホスト名 の CNAME に PublicDNS を登録)

 

EC2 の API は、様々な言語の SDK が用意されていますが、今回は Ruby の SDK を使用します。
Ruby 本体のバージョンは 2.1.1、AWS-SDK のバージョンは 2014 年 2 月時点での最新 (1.34.1) です。

Route53 の設定、EC2 インスタンスの作成は実行済み、
EC2 インスタンスの OS は CentOS6.4 64bit とします。

1. Ruby のインストール

rvm を使ってインストールするのが簡単ですね。せっかくなので現在の最新版の 2.1.1 をインストールします。

$ curl -L https://get.rvm.io | bash -s stable

一旦ログアウトして再度ログイン。rvm コマンドが使用できるようになります。

rvm で ruby 本体をインストールする前に、epel のリポジトリをインストール

# wget http://ftp-srv2.kddilabs.jp/Linux/distributions/fedora/epel/6/x86_64/epel-release-6-8.noarch.rpm
# rpm -Uvh epel-release-6-8.noarch.rpm

必要なパッケージをインストール

# yum install -y patch libyaml-devel libffi-devel glibc-headers gcc-c++ glibc-devel readline-devel zlib-devel openssl-devel autoconf automake libtool bison

ruby 本体のインストール

$ rvm install 2.1.1

続いて AWS-SDK のインストール

$ gem install --no-ri --no-doc aws-sdk

これで準備完了です。

2. スクリプトを設置

次の ruby スクリプトを ruby をインストールしたユーザの home に設置します。

hostname_to_route53.rb

#!/usr/bin/env ruby
require 'rubygems'
require 'aws-sdk'

## 設定項目

# AWS のアクセスキーIDとシークレットアクセスキー
ACCESS_KEY_ID     = "アクセスキーID"
SECRET_ACCESS_KEY = "シークレットアクセスキー"

# EC2のリージョン=Asia Pacific/Tokyo
EC2_ENDPOINT = "ec2.ap-northeast-1.amazonaws.com"

# Route53のHosted-zone id
HOSTED_ZONE_ID = "Hosted Zone ID"

# ホスト名の元になるドメイン名
# 最後にピリオドを必ず付けること!
DOMAIN_NAME = "ec2.tricorn-labs.jp."

# TTL
TTL = 300

## 実行コード

SELF_META_URL  = "http://169.254.169.254/latest/meta-data"

# EC2インスタンスのメタデータ
MY_PUBLIC_DNS  = `curl #{SELF_META_URL}/public-hostname 2>/dev/null`
MY_PUBLIC_IP   = `curl #{SELF_META_URL}/public-ipv4     2>/dev/null`
MY_INSTANCE_ID = `curl #{SELF_META_URL}/instance-id     2>/dev/null`

# APIキー、秘密鍵の設定
AWS.config({:access_key_id => ACCESS_KEY_ID, :secret_access_key => SECRET_ACCESS_KEY})

# APIキーに対応したアカウントのEC2インスタンスコレクション
ec2 = AWS::EC2.new(:ec2_endpoint => EC2_ENDPOINT)

# このEC2インスタンス情報の取得
my_ins = ec2.instances[MY_INSTANCE_ID]

# たまにメタデータの取得に失敗する 念のためチェック
raise "#{MY_INSTANCE_ID.to_s} was not found on your EC2" unless my_ins.exists?

sub_domain = my_ins.tags['sub-domain'] ? my_ins.tags['sub-domain'] : my_ins.instance_id
hostname = "#{sub_domain}.#{DOMAIN_NAME}"
r53 = AWS::Route53::Client.new()

rrsets = AWS::Route53::HostedZone.new(HOSTED_ZONE_ID).rrsets
rrset = rrsets[hostname, 'CNAME']

# レコードセットの削除
begin
  cur_rec = rrset.resource_records[0][:value]
rescue => error
  cur_rec = ''
end

if !cur_rec.empty? then
  batch = AWS::Route53::ChangeBatch.new(HOSTED_ZONE_ID)
  batch << AWS::Route53::DeleteRequest.new(hostname, 'CNAME', :ttl => TTL, :resource_records =>[{:value => cur_rec}])
  batch.call
end

# レコードセットの登録
batch = AWS::Route53::ChangeBatch.new(HOSTED_ZONE_ID)
batch << AWS::Route53::CreateRequest.new(hostname, 'CNAME', :ttl => TTL, :resource_records => [{:value => MY_PUBLIC_DNS }])
batch.call

なお、設定するアクセスキーID・シークレットアクセスキーに対応する IAM ユーザの権限としては以下が割り当てられていれば動作します (不要なものもあるかもしれませんが)。

  • ec2
    • DescribeInstanceAttribute
    • DescribeInstanceStatus
    • DescribeInstances
    • DescribeTags
  • route53
    • * (全ての権限)

では、スクリプトに実行権限を付けましょう

$ chmod 700 hostname_to_route53.rb

EC2インスタンスに、「sub-domain」というタグが設定されていると、
そちらをサブドメインとして使用します。
タグがない場合は、インスタンスID (i-XXXXXXXX) をサブドメインとして使用します。

スクリプト内の DOMAIN_NAME が 「ec2.tricorn-labs.jp」となっており、「sub-domain」タグに「web01」が設定されている EC2 インスタンスで実行した場合、Route53 に登録されるホスト名は、「web01.ec2.tricorn-labs.jp」となります。
※「tricorn-labs.jp」というドメインは実際には存在しません。

複数の EC2 インスタンスで使用する場合は、
「sub-domain」タグの値が重複しないよう注意してください。

さて試しに実行してみましょう。

$ ./hostname_to_route53.rb

マネジメントコンソールの Route53 で確認すると、新たにレコードが登録されていることがわかります。

CNAME に PublicDNS を登録するため、
同一リージョンの EC2 同士でホスト名を使用して通信した場合、
PrivateIP に変換されるため外部ネットワークを経由せずに通信することができます。

3. サーバ起動時に実行する

最後に、EC2 の PublicIP,PublicDNS が変更される
「Stop」⇒「Start」時に自動的にスクリプトを実行するようにします。

以下の様な init スクリプトを用意します。
ruby をインストールしたユーザを仮に ec2-user、スクリプトのパスを /home/${USER}/aws-tools/hostname_to_route53.rb としていますが、適宜変更して下さい。

r53

#!/bin/sh
#
#    /etc/rc.d/init.d/r53
#
# Register hostname to Route53
#
# chkconfig: 345 44 56
#
USER=ec2-user
SCRIPT=/home/${USER}/aws-tools/hostname_to_route53.rb

start() {
    su -l $USER -c "$SCRIPT"
    return $?
}

stop()
{
    return 0
}

restart() {
    stop
    start
}

case "$1" in
    start)
        start
        ;;
    stop)
        stop
        ;;
    restart)
        restart
        ;;
    *)
        echo "Usage: $0 {start|stop|restart}"
        RETVAL=2
esac
exit $RETVAL

/etc/init.d/ 以下に設置し、実行権限を付与した上で、chkconfig で起動時に実行されるよう登録します。

# mv r53 /etc/init.d/
# chown root:root /etc/init.d/r53
# chmod 700 /etc/init.d/r53
# chkconfig r53 on

さて、準備が出来ましたので試しに EC2 インスタンスを「Stop」アンド「Start」してみます。
しばらく待つと、Route53 にホスト名が登録されます!

このように、EC2 インスタンスの boot 時自動的に
Route53のレコードを更新するような仕組みを入れた AMI を作成しておけば、
PublicDNSは長すぎる!
IPだと覚えにくい!
うかつにインスタンスを停止できない!(するな)
などの悩みから解消されます。

Tags: , ,

morikawa

インフラグループの Morikawa です。今回は AWS EC2 のインスタンスに SSH ログインする際にちょっと便利なツールのご紹介です。

ちなみに AWS は初心者でして、最近時間を見つけてはちょっとずつ勉強してるところです。…で、使い始めて思ってしまったわけです。

  • EC2 (起動のたびにグローバルIP変わる) に SSH ログインするの毎度面倒くさいな、と…。 (もっと他に学ぶところはあるはずなんですが ^^;)

Web 上を探してみますと同じような不満を持ってる方はやっぱりいらっしゃいまして、以下のサイトで migrs さんが、EC2 上のインスタンスの名称を指定して SSH ログインできる ec2-ssh というツールを紹介して下さってます。ツールは GitHub Gist で公開されてます。

これはログインのたびに ec2-api-tools を介してインスタンスの名称と Public DNS の対応を自動取得してくれるツールです。単独で動くシェルスクリプトですのでセットアップも簡単で非常に便利です。ただ ログインのたびに API での Public DNS 情報の取得に数秒必要 のがどうも気になってました。

そんなわけで (ここが本題)、migrs さんの ec2-ssh を Fork して Public DNS 情報のキャッシュ機能を追加した ec2-ssh を作ってみました (こちらも Gist にて公開 してます)。今のところ CentOS 6.4 と Mac OS X 10.8.4 で動作確認してます。

既にオリジナルの ec2-ssh を利用されてる方や、ec2-api-tools を普段から利用している方は単にダウンロードして実行してもらえればサクッと使えると思います。今回の記事では、私のような AWS 初心者向けに関連ツールのセットアップも含めてまとめてみました。

続きを見る >>>

Tags: , , , ,