2012年4月23日月曜日

定時にEC2を起動 & バッチが終了したらターミネート

スズキです。

CDPネタです。今回の対象は「Scheduled Autoscalingパターン」です。



このパターンの注意点に
バッチ処理が終了する時刻を決めるのが難しい場合は、
EC2上のバッチ処理が終了してから、EC2自身が自分を終了する
作り込みを行う方法もよく用いられる。
といった記載があります。

今回は上記の方法を実際に作りこんでみました。

まずは、"Auto Scaling"にてスケールアウトに使われるAMIの作成です。
このAMIはEC2起動にバッチ処理を開始し、バッチ処理が終了するときに
自分自身(EC2)もターミネートされるようにする必要があります。

具体的には起動時にバッチ処理(/opt/suz-batch/bin/run-batch)が開始されるように、
下記の起動スクリプト(/etc/init.d/suz-batch)を用意します。
#!/bin/bash
#
# suz-batch        Run Batch.
#
# chkconfig: 2345 99 10
# description: Run Batch

# Source function library.
. /etc/init.d/functions

prog=suz-batch
lock=/var/lock/subsys/$prog
log=/opt/suz-batch/log/error.log

# Source config
if [ -f /etc/sysconfig/$prog ] ; then
    . /etc/sysconfig/$prog
fi

case "$1" in
    start)
        echo `date +"%Y-%m-%d %T"` "begin" > $log
        /opt/suz-batch/bin/run-batch &
        touch $lock
        ;;
    stop)
        echo `date +"%Y-%m-%d %T"` "end" >> $log
        /opt/suz-batch/sbin/upload-log
        rm -f $lock
        ;;
    *)
        echo $"Usage: $0 {start|stop}"
        exit 1
esac

exit $?
※終了時はログをS3にアップロード(/opt/suz-batch/sbin/upload-log)します。

当然、上記の起動スクリプトが有効になるようにもしておきます。
# chkconfig --add suz-batch
# chkconfig suz-batch on
# chkconfig --list suz-batch
suz-batch       0:off 1:off 2:on 3:on 4:on 5:on 6:off
バッチ処理のスクリプト(/opt/suz-batch/bin/run-batch)は下記の通りで、
バッチ終了時に自分自身(EC2)をターミネート(/opt/suz-batch/sbin/terminate-instance)
するようにしています。
log=/opt/suz-batch/log/error.log
echo `date +"%Y-%m-%d %T"` "run" >> $log
/opt/suz-batch/sbin/terminate-instance
exit 0
自分自身(EC2)をターミネート(/opt/suz-batch/sbin/terminate-instance)する
スクリプトは下記のようにしています。
require_once("/opt/aws/php/latest/sdk.class.php");
date_default_timezone_set("Asia/Tokyo");

$as = new AmazonAS(array(
    "key"    => "ACCESS KEY",
    "secret" => "SECRET KEY"
));
$as->set_region(AmazonAS::REGION_APAC_NE1);
$response = $as->update_auto_scaling_group(
    "as-test",
    array(
       "MinSize"         => 0,
       "MaxSize"         => 0,
       "DesiredCapacity" => 0
    )
);

if(!$response->isOK()) {
    error_log(
        date("Y-m-d H:i:s") . " " . basename($_SERVER["PHP_SELF"]) . " " . $response->body->Error->to_json() . "\n",
        3,
        "/opt/suz-batch/log/error.log"
    );
    exit(1);
}
exit(0);
見ての通り、EC2をターミネートしているのではなく、"Auto Scaling"のEC2起動数を
0にすることで、結果、自分自身(EC2)がターミネートされるようにしています。

ちなみに自分自身(EC2)がターミネートするときに実行される、ログをS3にアップロードする
スクリプト(/opt/suz-batch/sbin/upload-log)は下記のようにしています。
require_once("/opt/aws/php/latest/sdk.class.php");
date_default_timezone_set("Asia/Tokyo");

$s3 = new AmazonS3(array(
    "key"    => "ACCESS KEY",
    "secret" => "SECRET KEY"
));
$s3->set_region(AmazonS3::REGION_APAC_NE1);
$s3->use_ssl = false;
$response = $s3->create_object("www.suz-lab.com", "test/error-" . date("YmdHis") . ".log", array(  
    "fileUpload" => "/opt/suz-batch/log/error.log"
)); 

if(!$response->isOK()) {
    error_log(
        date("Y-m-d H:i:s") . " " . basename($_SERVER["PHP_SELF"]) . " " . $response->body->to_json() . "\n",
        3,
        "/opt/suz-batch/log/error.log"
    );
    exit(1);
}
exit(0);

次に、このAMIを使って"Auto Scaling"の設定を行います。
具体的には"Launch Configuration"と"Auto Scaling Group"を設定するのですが、
以前紹介した、下記記事が参考になると思います。
"Auto Scaling"でEC2を自動復旧
特に"Auto Scaling Group"の設定は、初期時はEC2は起動して無い状態にしたいので
最大起動数と最小起動数を共に0にしておきます。(ELB関係の設定も必要ありません)

最後に、今回の記事のポイントである、定期的にAutoScalingがEC2を起動
("0 → 1"にスケール)する部分です。

設定は下記のようにPHP(AWS SDK)で行なっています。
require_once("/opt/aws/php/latest/sdk.class.php");

$as = new AmazonAS(array(
    "key"    => "ACCESS KEY",
    "secret" => "SECRET KEY"
));
$as->set_region(AmazonAS::REGION_APAC_NE1);
$response = $as->put_scheduled_update_group_action(
    "as-test", // auto scaling group name
    "as-test", // scheduled action name
    array(
        "Recurrence"      => "*/5 * * * *", // unix cron syntax format
        "MinSize"         => 1,
        "MaxSize"         => 1,
        "DesiredCapacity" => 1
    )
);

var_dump($response->body);

APIは"put_scheduled_update_group_action"を利用しており、"Recurrence"に"cron"の文法で
スケールアウトする時刻を指定することができます。

そして上記は、5分毎にEC2が1インスタンス稼働している状態にするように設定しています。
つまり、もともと稼働していない(0インスタンス)の場合は、上記のタイミングで
1インスタンス、新規に稼働することになります。

結果として、
5分後 → EC2起動 → バッチ終了 → EC2ターミネート → 5分後 → EC2起動 → ...
と動作し、S3へのログも、下記のように5分毎にアップロードされることがわかります。


図にすると、こんな感じでしょうか?


今回は、ちょっと「あらびき」な内容だったなー...
--------
http://www.suz-lab.com/

0 コメント: