17日目担当のゴトウです。当初は勢い余って「こんなCDPはいやだ」というタイトルで参戦しようとしたCDP Advent Calendarですが、みなさんマジメにやられているようなのでひよってしまい、まぁまぁ使える感じや〜つに変更することにしました。
さてAWS環境を有効に活用している多くのシステムでは、インスタンスの自動起動やオートスケールなど、予めサーバー台数や名前が決まってないことが多いです。そんなときでも現状起動中のインスタンス一覧を参照できないといけないケースが多々あります。
たとえばオートスケールする環境でも監視ツールによるモニタリングが必要な場合。または同様にオートスケールする環境でELBではないロードバランサーを利用して負荷分散しているケース。いずれのケースも設定ファイルに現在稼働しているインスタンスのホスト名ないしはIPアドレス一覧を更新する必要があります。
そのための元ネタとしてSimpleDBを使って起動中のインスタンスメタデータを保管する方法を実装したのでPHPのサンプルコードと共にご紹介します。いまいちいい名前が思いつかないのですが、名付けて Self Server Registrationパターン。(気に入ってないので名前は募集します!)
以下のようなファイルを用意します。
■config.php – 各種スクリプト用AWS設定ファイル
<?php define('AWSAccessKeyId', '<your Access Key Id HERE!>'); define('AWSSecretKey', '<your Security Key HERE!>'); define('REGION', AmazonSDB::REGION_TOKYO); define('DOMAIN', 'server-list'); ?>
■add-server.php – 自身のメタデータを登録するスクリプト
#!/usr/bin/php <?php require_once("sdk/sdk.class.php"); require_once("config.php"); if ($argc < 6) { print("Usage: $argv[0] <instance-id> <instance-type> <availability-zone> <public-hostname> <local-ipv4> <status>\n"); exit(1); } $sdb = new AmazonSDB(array( "key" => AWSAccessKeyId, "secret" => AWSSecretKey )); $sdb->set_region(REGION); $res = $sdb->put_attributes(DOMAIN, $argv[1], array( 'instance-type' => $argv[2], 'availability-zone' => $argv[3], 'public-hostname' => $argv[4], 'local-ipv4' => $argv[5], 'status' => $argv[6] ), true); if($res->isOK()){ # print_r($res); } else{ # print_r($res); print("Failed.\n"); exit(1); } ?>
■delete-server.php – 自身のメタデータを削除するスクリプト
#!/usr/bin/php <?php require_once("sdk/sdk.class.php"); require_once("config.php"); if ($argc <= 1) { print("Usage: $argv[0] <instance-id>\n"); exit(1); } $sdb = new AmazonSDB(array( "key" => AWSAccessKeyId, "secret" => AWSSecretKey )); $sdb->set_region(REGION); $res = $sdb->delete_attributes(DOMAIN, $argv[1]); if($res->isOK()){ # print_r($res); } else{ # print_r($res); print("Failed.\n"); exit(1); } ?>
■/etc/init.d/self-server-registration – インスタンス起動・停止時用スクリプト
#!/bin/bash # # EC2 instance metadata self server regitration # # chkconfig: 2345 60 60 # description: self server registration script to manage & list current running EC2 instances # # source function library . /etc/rc.d/init.d/functions RETVAL=0 lockfile=/var/lock/subsys/self-server-registration srcdir=/opt/self-server-registration endpoint=http://169.254.169.254/latest/meta-data get_meta_data() { ID=`curl -s ${endpoint}/instance-id` TYPE=`curl -s ${endpoint}/instance-type` AZ=`curl -s ${endpoint}/placement/availability-zone` DNSNAME=`curl -s ${endpoint}/public-hostname` IP=`curl -s ${endpoint}/local-ipv4` } start() { if [ ! -f ${srcdir}/config.php ]; then echo "${srcdir}/config.php does NOT exist." failure fi echo if [ -x ${srcdir}/add-server.php ]; then echo -n $"Running: add-server.php " ${srcdir}/add-server.php $ID $TYPE $AZ $DNSNAME $IP 'running' && success || failure echo fi touch ${lockfile} } stop () { if [ ! -f ${srcdir}/config.php ]; then echo "${srcdir}/config.php does NOT exist." failure fi echo if [ -x ${srcdir}/delete-server.php ]; then echo -n $"Running: delete-server.php " ${srcdir}/delete-server.php $ID && success echo fi rm -f ${lockfile} } case "$1" in start) get_meta_data start ;; stop) get_meta_data stop ;; restart) get_meta_data stop start ;; *) echo $"Usage: $0 {start|stop|restart}" RETVAL=1 esac exit $RETVAL
以下を前提としていますのでご注意を。
・config.php中のAWSAccessKeyIdとAWSSecretKeyを自身のものへ書き換え必須
・config.php中のDOMAINは好きなものに変更
・add-server.phpとdelete-server.phpは実行権限付きで/opt/self-server-registrationに設置されている
・self-server-registrationは実行権限付きで/etc/init.dに設置されている
テスト実行をするのであればドメインを作成してから、以下のようにコマンド実行してください。
(ドメイン作成スクリプトはサンプルがgithubにおいてあります)
$ sudo /etc/init.d/self-server-registration start Running: add-server.php [ OK ]
SimpleDBで指定してドメインの中をみてましょう。RazorSQLを使って確認してみるとこうなってます。
同様に、削除してみましょう。
$ sudo /etc/init.d/self-server-registration stop Running: delete-server.php [ OK ]
当然消えてますね。ここまでくれば設定はほぼ完了。最後に以下のようなコマンドを実行して起動・停止スクリプトとして登録します。
$ sudo chkconfig --add self-server-registration $ sudo chkconfig --list | grep self-server-registration self-server-registration0:off1:off2:on3:on4:on5:on6:off $ ls -al /etc/rc3.d/ | grep self-server-registration lrwxrwxrwx 1 root root 34 12月 17 11:15 2012 S60self-server-registration -> ../init.d/self-server-registration
あとはRebootしても、Stop→Startしても正確な情報が保存されることが確認できると思います。特にStop→Startの場合はIPが変わるので情報がよくわかると思います。
さてそれでは複数台起動してみましょう。自前で作成したAMIを元にして…
10台起動します。
無事10台起動しました。
一方RazorSQLで確認してみると…
無事10件あることが確認できました。
今度は停止してみましょう。5台停止してみると
無事に5件になっていることが確認できます。
あとはこの状態から必要なフォーマットにあわせて出力して使うことになります。
とりあえずダンプでよければ…
$ ./list-servers.php sql = SELECT * FROM `server-list` CFSimpleXML Object ( [Item] => Array ( [0] => CFSimpleXML Object ( [Name] => i-06157105 [Attribute] => Array ( [0] => CFSimpleXML Object ( [Name] => availability-zone [Value] => ap-northeast-1a ) [1] => CFSimpleXML Object ( [Name] => public-hostname [Value] => ec2-54-248-189-143.ap-northeast-1.compute.amazonaws.com ) [2] => CFSimpleXML Object ( [Name] => status [Value] => running ) [3] => CFSimpleXML Object ( [Name] => local-ipv4 [Value] => 10.128.21.18 ) [4] => CFSimpleXML Object ( [Name] => instance-type [Value] => t1.micro ) ) ) [1] => CFSimpleXML Object ( [Name] => i-0a157109 [Attribute] => Array ( [0] => CFSimpleXML Object ( [Name] => availability-zone [Value] => ap-northeast-1a ) [1] => CFSimpleXML Object ( [Name] => public-hostname [Value] => ec2-54-248-199-208.ap-northeast-1.compute.amazonaws.com ) [2] => CFSimpleXML Object ( [Name] => status [Value] => running ) [3] => CFSimpleXML Object ( [Name] => local-ipv4 [Value] => 10.128.29.151 ) [4] => CFSimpleXML Object ( [Name] => instance-type [Value] => t1.micro ) ) ) [2] => CFSimpleXML Object ( [Name] => i-0815710b [Attribute] => Array ( [0] => CFSimpleXML Object ( [Name] => availability-zone [Value] => ap-northeast-1a ) [1] => CFSimpleXML Object ( [Name] => public-hostname [Value] => ec2-54-248-183-207.ap-northeast-1.compute.amazonaws.com ) [2] => CFSimpleXML Object ( [Name] => status [Value] => running ) [3] => CFSimpleXML Object ( [Name] => local-ipv4 [Value] => 10.128.20.135 ) [4] => CFSimpleXML Object ( [Name] => instance-type [Value] => t1.micro ) ) ) [3] => CFSimpleXML Object ( [Name] => i-0e15710d [Attribute] => Array ( [0] => CFSimpleXML Object ( [Name] => availability-zone [Value] => ap-northeast-1a ) [1] => CFSimpleXML Object ( [Name] => public-hostname [Value] => ec2-54-248-25-102.ap-northeast-1.compute.amazonaws.com ) [2] => CFSimpleXML Object ( [Name] => status [Value] => running ) [3] => CFSimpleXML Object ( [Name] => local-ipv4 [Value] => 10.128.19.95 ) [4] => CFSimpleXML Object ( [Name] => instance-type [Value] => t1.micro ) ) ) [4] => CFSimpleXML Object ( [Name] => i-04157107 [Attribute] => Array ( [0] => CFSimpleXML Object ( [Name] => availability-zone [Value] => ap-northeast-1a ) [1] => CFSimpleXML Object ( [Name] => public-hostname [Value] => ec2-54-248-26-190.ap-northeast-1.compute.amazonaws.com ) [2] => CFSimpleXML Object ( [Name] => status [Value] => running ) [3] => CFSimpleXML Object ( [Name] => local-ipv4 [Value] => 10.128.19.111 ) [4] => CFSimpleXML Object ( [Name] => instance-type [Value] => t1.micro ) ) ) ) )
こんな感じですね。ちなみにcloudpackではこいつを整形してNagiosやHAProxyなんかへ利用しています。
サンプルソースはgithubにおいてありますので、適当にカスタマイズして使ってみてください。(環境はAmazon Linuxを前提としています。PHPのAWS SDKは各種PHPスクリプトと同一ディレクトリ内に sdk/ でアクセス可能な状態で設置してください。)
明日は @k_yokokura さんですね。
それでは!