今回は、SQSのメッセージ数をCloudWatchにカスタムメトリクスとして登録し、そのカスタムメトリクスでAuto Scalingします。

仕様としては、一日一回の頻度でSQSに一気にメッセージを登録して、それを複数インスタンスで処理するものです。
メッセージ数が1以上になれば、10インスタンス立ち上げ、メッセージ数が0になったら、全てのインスタンスをターミネートするようにしています。

SQSのメッセージ数をCloudWatchにカスタムメトリクスとして登録する部分は、SQSのキューのサイズをCloudWatchに登録で、SQSのメッセージを処理するインスタンスは、SQSのキューのメッセージがなくなたらEC2インスタンスをシャットダウン下記で紹介しています。
(ちなみにここでは、シャットダウンはしないようにしています。)

そして、今回もいつも通りPHP(AWS SDK)で実現してみました。

はじめに、共通設定です。

▼ common.php

define("AWS_KEY"         , "AAAAAAAA");
define("AWS_SECRET_KEY"  , "SSSSSSSS");
define("CP_SQS_URL_CRAWL", "https://sqs.ap-northeast-1.amazonaws.com/000000000000/crawl");
define("CP_AS_NAME"      , "crawl");
date_default_timezone_set("Asia/Tokyo");

次に、Auto Scalingのlaunch-configurationを作成します。
指定しているami-xxxxxxxxは、起動と同時にSQSのメッセージを処理し続けるAMIです。

▼ create-launch-configuration

require_once("/opt/cloudpack/bin/common.php");
require_once("/opt/aws/php/sdk.class.php");
$as = new AmazonAS();
$as->set_region(AmazonAS::REGION_APAC_NE1);
$response = $as->create_launch_configuration(
    CP_AS_NAME,
    "ami-xxxxxxxx",
    "t1.micro",
    array(
        "KeyName"        => "suz-lab_ap-northeast-1",
        "SecurityGroups" => array(
            "default",
            "crawl"
        )
    )
);
var_dump($response->isOK());

そして、Auto Scalingのauto-scaling-groupを作成します。
インスタンス数のMINを0、MAXを10としています。

▼ create-auto-scaling-group

require_once("/opt/cloudpack/bin/common.php");
require_once("/opt/aws/php/sdk.class.php");
$as = new AmazonAS();
$as->set_region(AmazonAS::REGION_APAC_NE1);
$response = $as->create_auto_scaling_group(
    CP_AS_NAME,
    CP_AS_NAME,
    0,
    10,
    array(
        "ap-northeast-1a",
        "ap-northeast-1b"
    )
);
var_dump($response->isOK());

PHP側の最後は、scaling-policyの設定です。
ここでは、scale-outのポリシー(10インスタンスになるように起動)とscale-inのポリシー(全て100%のインスタンスをターミネート)を作成しています。

▼put-scaling-policy

require_once("/opt/cloudpack/bin/common.php");
require_once("/opt/aws/php/sdk.class.php");
$as = new AmazonAS();
$as->set_region(AmazonAS::REGION_APAC_NE1);
$response = $as->put_scaling_policy(
    CP_AS_NAME,
    "scale-out",
    10,
    "ExactCapacity"
);
var_dump($response->body->PutScalingPolicyResult->PolicyARN);
$response = $as->put_scaling_policy(
    CP_AS_NAME,
    "scale-in",
    -100,
    "PercentChangeInCapacity"
);
var_dump($response->body->PutScalingPolicyResult->PolicyARN);

上記で作成したポリシーを、scale-outはSQSのメッセージ数が1以上の場合、
scale-inはSQSのメッセージ数が0になった場合に実施されるようにするのですが、
この設定はCloudWatchの方で行います。
(下記のようにAWS Management Consoleで行うことも可能です。)

はじめに、CloudWatchのタブからアラームを作成します。

そして、対象のメトリクス名(queue_size)を指定して、統計情報の扱い方(Average)とチェックのインターバル(5分)を選択します。

次に、アラームに名前(has-messages)と条件(queue_sizeが1以上になったらアラーム)を指定します。

アラームの状態が変わったときのアクションを指定します。
今回は、状態がアラームになった時(queue_sizeが1以上)に、先程作成したAuto Scalingポリシーのscale-out(10インスタンスになるように起動)状態が、OKになると(queue_sizeが0)はscale-in(全て100%のインスタンスをターミネート)が、実施されるようにしています。

確認画面にて問題がなければ、AWS Management ConsoleのCloudWatchの設定は終了です。

実際、SQSにメッセージを追加すると、EC2インスタンスが10起動されます。
そしてメッセージの処理が進んで、SQSのメッセージ数が0になった時に、全てのEC2インスタンスがターミネートされることがわかります。
(下記はアラームの状態とSQSのメッセージ数の推移です)

CloudWatchがデフォルトでSQSのメッセージ数を取れれば、
CloudWatchにデータを投入する管理インスタンスがいらなくなるな

こちらの記事はなかの人(suz-lab)監修のもと掲載しています。
元記事は、こちら