code up

スポンサーサイト

上記の広告は1ヶ月以上更新のないブログに表示されています。
新しい記事を書く事で広告が消せます。

EC2 - 動的プライベートIPアドレスをどうにかする

複数台のEC2のセットアップ中なのだが、アプリケーションサーバーからデータベースサーバーを参照する方法について模索した。

突き当たる問題点は、EC2のプライベートIPアドレスはDHCPから取得しているということ。いずれのサーバーもIPアドレスはインスタンスを停止すると変わってしまい、プライベートIPアドレスのstatic化(permanent化)はできないというのがEC2の現在の仕様のようだ。これをどうにかした。

まず参考にしたページ。

AWS Developer Forumsにもある通り、OSのシャットダウンまたはEC2のStopにより状態がstoppedとなったインスタンスのプライベートIPアドレスおよびパブリックIPアドレスは、次回起動(Start)時に新しく割り当てられる、OSレベルの再起動、EC2のリブート(Reboot)では変わらないとのこと。

従って先日のscheduled for retirementのようなStopを強制される場合にはアプリケーションサーバーから見たデータベースサーバーのアドレスも変わってしまう。ちなみにこの時は正常に停止しなかったため、新しいインスタンスを作成したのでInstance IDも変わった。

調べて見つけた案はふたつ。ネット検索の寄せ集めで、全部確かめたわけではないため、情報は最新でない可能性もあります。また、各ec2のコマンド(ec2-で始まるコマンド)は秘密鍵と証明書をサーバーにアップロードしておかなければいけないためセキュリティリスクがある点に注意。

案1: EIPを使う(たぶんこっちがお勧め)

ひとつはパブリックIPアドレスにEIP(Elastic IP)アドレスを割り当ててしまうというもの。

そして、アプリケーションサーバーにはデータベースサーバーのEIPのホスト名(ec2-54-000-000-000.ap-northeast-1.compute.amazonaws.com)を参照するように設定する。パブリックなホスト名(Public DNS Name)はEC2インスタンスからのlookup時にはプライベートIPを返すそうだ。EIPのホスト名でもプライベートIPアドレスを返すことは確認したが、異なるAZ間では試してない&調べてないので不明。

EIPを使わないと、ホスト名はプライベートIPと対になる名前(つまり起動時にホスト名(Public DNS Name)も変わってしまう)になるため参照先の固定化ができない。

加えて、インスタンスを停止するとEIPは解除されるがec2-associate-addressなどを使って起動時にAssociate、セキュリティグループをec2-authorizeec2-revokeなどで再作成することで完全自動化できる。またEIPアドレス直(パブリックIPアドレス)で通信をすると通信料が課金されてしまうが、EIPホスト名を指定すれば(プライベートIPが返ってくるので)通信料の課金は行われない

EIPを自動的に割り当ててみる

自動的に割り当てるために必要な情報は『EIPアドレス』、またコマンドラインから実行するのに秘密鍵と証明書も必要。また、Tokyoリージョンで作業しているためリージョン名も確認しておく。コマンドのオプションには『インスタンスID』が必要だが、スクリプトの中で自動的に自分のinstance-idを取得している。

以下rootユーザーにて実行したログ。

1. ec2-associate-addressが存在しているかの確認

# ec2-associate-address -h

使い方などのヘルプメッセージが出てくればOK。なければec2-api-toolsをyumなどからインストールしておく。

2. EIPアドレスの確認

# ec2-describe-addresses -K pk.pem -C cert.pem --region ap-northeast-1

対象となるグローバルIPアドレスを確認しておく。EIPの取得がまだであればAWS Management Consoleec2-allocate-addressコマンドなどで取得しておく。

どこかのブログでec2-allocate-addressがEIPアドレスを確認するためのコマンドと書いてあったが、新規に取得するコマンドである。繰り返し実行すればその都度作成され、その分課金される。コマンドを実行して見当たらないと思っていても、いつも使っているリージョンとは違う場所にさりげなく作成されていたりするかもしれないので注意です。

3. 秘密鍵と証明書のアップロード

/home/awsというフォルダを作成してそこにアップロードした。

4. EIP自動割り当て用のスクリプトを作成

# vi /home/aws/update-eip.sh
#!/bin/sh

# This script is called by /etc/rc.local

# Source global definitions
if [ -f /etc/bashrc ]; then
        . /etc/bashrc
fi

IID=`curl http://169.254.169.254/latest/meta-data/instance-id`

/opt/aws/bin/ec2-associate-address -K /home/aws/pk.pem -C /home/aws/cert.pem --region ap-northeast-1 -i $IID [EIPアドレス]
# chmod +x /home/aws/update-eip.sh

5. インスタンス起動時に自動的に実行するように

# vi /etc/rc.local
#!/bin/sh
#
# This script will be executed *after* all the other init scripts.
# You can put your own initialization stuff in here if you don't
# want to do the full Sys V style init stuff.

touch /var/lock/subsys/local

/home/aws/update-eip.sh > /tmp/update-eip.log 2>&1

6. テスト!

インスタンスを停止(Stop)してみて、EIPアドレスの割り当てが解除されていることを確認してから、起動(Start)。しばらくしてEIPアドレスが割り当てられていることが確認できればOK!

案2: 固定ホスト名を/etc/hostsに登録する(ちょっと面倒)

/etc/hostsファイルに各インスタンスのIPアドレスと固定のホスト名をアナログに定義してしまおうというもの。起動時およびcronで定期的に実行しておけば別インスタンスのプライベートIPが変わっても固定ホスト名でアクセスしているアプリケーションが参照先のサーバーを見失うことはない。ただ、サーバーアプリケーションの起動時に/etc/hostsが作成できていない場合は、反映に時間はかかる、またはそのサーバーアプリケーションの再起動が必要かも(まだテスト不十分)。

案1と同様、起動時に(割り当てていれば)EIPの再割り当て、Security Groupの更新を行う。

以下は、アプリケーションサーバーに設定した自動スクリプトの作成までのログ(rootで実行)。インスタンスはふたつ、APというNameを持つアプリケーションサーバーのインスタンスとDBというNameのデータベースサーバーのインスタンスがあることを例とする。

1. ec2-describe-instancesが実行できることの確認

# ec2-describe-instances -?

2. 秘密鍵と証明書のアップロード

/home/ec2-user/serverというフォルダを作成してそこにアップロードした。

3. 現在の/etc/hostsファイルのコピー

# cp /etc/hosts /etc/sysconfig/hosts.template

4. /etc/hosts更新用のスクリプトを作成

# vi /home/ec2-user/server/updatehosts.sh
#!/bin/sh

# This script is called by /etc/rc.local

# Source global definitions
if [ -f /etc/bashrc ]; then
        . /etc/bashrc
fi

APIP=`/opt/aws/bin/ec2-describe-instances -K /home/ec2-user/server/pk.pem -C /home/ec2-user/server/cert.pem --region ap-northeast-1 --filter tag:Name=AP | grep INSTANCE | cut -f 18 | egrep '^10\.'`

DBIP=`/opt/aws/bin/ec2-describe-instances -K /home/ec2-user/server/pk.pem -C /home/ec2-user/server/cert.pem --region ap-northeast-1 --filter tag:Name=DB | grep INSTANCE | cut -f 18 | egrep '^10\.'`

cp -f /etc/sysconfig/hosts.template /etc/hosts

if [ -z "$APIP" ]
then
        APIP='#NG'
fi

if [ -z "$DBIP" ]
then
        DBIP='#NG'
fi

echo "$APIP AP" >> /etc/hosts
echo "$DBIP DB" >> /etc/hosts
# chmod +x /home/ec2-user/server/updatehosts.sh

取得に失敗した場合は/etc/hostsファイルに#NG APというように出力される(つまり、APというホスト名でIPアドレスが参照できなくなる)ので、Nagios等監視アプリケーションでホスト名『AP』を監視しておけば参照先消失に早い段階で気づくことができるだろう。

5. 起動スクリプト(/etc/rc.local)に上記スクリプトの呼び出しを追加

# vi /etc/rc.local
/home/ec2-user/server/updatehosts.sh > /tmp/updatehosts.log 2>&1

スクリプトとか鍵の配置場所は適当。ログのローテションが面倒なので起動毎の実行結果は/tmp/updatehosts.logを上書きするようにした。

これらの設定により自身のアプリケーションサーバーのIPアドレス(curl http://169.254.169.254/latest/meta-data/local-ipv4と同値のはず)とデータベースサーバーのIPアドレスが/etc/hostsに登録される。

/home/ec2-user/server/updatehosts.shをcronで定期的に実行しておけば、ホスト名が参照するIPアドレスが自動的に更新されるでしょう。ただ、インスタンスが生存しているのにec2-describe-instancesが失敗することがあるのか不明、頻繁に発生するようならcronではなくサーバー再起動時に手動でスクリプトを実行した方がいい。

実は案2の作業中に案1を発見した次第なので、案1に置き換える予定。

関連記事
タグ:EC2 AWS Amazon
上記広告は1ヶ月以上更新のないブログに表示されています。新しい記事を書くことで広告を消せます。