CloudWatchとLambdaによるEC2の夜間停止

  • 10
    いいね
  • 0
    コメント

初めに

AWSのアドベントカレンダーもっと盛り上がれ!もう時代遅れか!?

と念じております。

さてさて、前回はWEBアプリケーションの環境を構築しましたが

今回はEC2の夜間停止をCloudWatchとLambdaを利用して実装していきたいと思います。

夜間停止の流れはLambdaで起動用の関数と停止用の関数を作成し

CloudWatchを利用して朝に起動用の関数を、夜に停止用の関数を実行することで実現させます。

第1部 「AWSを避けていたPGがALBとEC2を利用してWEBアプリケーション環境を構築してみた

第2部 「LambdaとCloud WatchによるEC2の夜間停止」←今ここ

第3部 「ALBによるパスルーティング」

前置き

LambdaのScheduleイベントでEC2を自動起動&自動停止してみた#reinventを基本的に参考にして構築をしております。

解釈や説明の誤りなど、コメント欄に記載していただけると幸いです。

Lambda

さて、まずLambdaです。

左のメニューから「Function」を選択肢、「Create a Lambda function」をクリック。

スクリーンショット 2016-12-21 22.17.31.png

Select blueprintと表示されますが無視して、左のメニューから「Configure function」を選択。

スクリーンショット 2016-12-21 22.20.27.png

この画面で起動用の関数と停止用の関数を作成していきます。

まずは起動用の関数から。

項目
Name 適当に
Description 適当に
Runtime Node.js 4.3
Code entry type Edit code inline

スクリーンショット 2016-12-21 22.27.50.png

Lambda function codeには下記、起動用の関数を、記述します。

INSTANCE_IDにはEC2のinstance idを、AWS.config.regionにはリージョンを入れてください。

リージョンに関しては東京なら ap-northeast-1です。

その他リージョンの場合は下記公式から確認してください。

リージョンとアベイラビリティーゾーン

const INSTANCE_ID = '*****';

var AWS = require('aws-sdk'); 
AWS.config.region = '*****';

function ec2Start(cb){
    var ec2 = new AWS.EC2();
    var params = {
        InstanceIds: [
            INSTANCE_ID
        ]
    };

    ec2.startInstances(params, function(err, data) {
        if (!!err) {
            console.log(err, err.stack);
        } else {
            console.log(data);
            cb();
        }
    });
}
exports.handler = function(event, context) {
    console.log('start');
    ec2Start(function() {
        context.done(null, 'Started Instance');
    });
};

Environment variablesは空のままで、Handlerindex.handlerを指定。

RoleはセレクトボックスからCreate a custom roleを選択。

選択すると、別タブでロール作成画面が開きます。

スクリーンショット 2016-12-21 22.58.13.png

別タブで開いた画面では下記のとおりに記述します。

項目
IAM Role Create a new IAM Role
Role Name 適当に

Policy Documentは下記jsonを記述します。

{
  "Version": "2012-10-17",
  "Statement": [
    {
      "Effect": "Allow",
      "Action": [
        "logs:CreateLogGroup",
        "logs:CreateLogStream",
        "logs:PutLogEvents",
        "ec2:StartInstances"
      ],
      "Resource":[
      "arn:aws:logs:*:*:*",
      "arn:aws:ec2:*"
      ]
    }
  ]
}

記述したら右下の「Allow」をクリックします。画面が閉じるので、Lambdaの画面に戻ります。

スクリーンショット 2016-12-21 23.07.46.png

自動でRoleChoose an existing roleになり、Exisiting roleが先程作成したロールになっていると思います。

もしなっていなかったら手動で設定してください。

スクリーンショット 2016-12-21 23.18.49.png

その他設定はいじらず、右下の「Next」をクリック。

スクリーンショット 2016-12-21 23.20.19.png

確認画面に遷移するので、問題なければ右下の「Create function」をクリック。

スクリーンショット 2016-12-21 23.21.10.png

作成した関数のテストをして実際にEC2が起動するか確認したいと思います。

「Test」をクリックします。

スクリーンショット 2016-12-21 23.28.24.png

とくに値をいじらず、右下の「Save and test」をクリックします。

画面にログが表示され、EC2が起動していたら成功です。

スクリーンショット 2016-12-21 23.29.36.png

起動用の関数が確認できたら停止用の関数も作成します。

基本的に起動用の関数と同じ設定です。

Lambda function codeは下記のコードを

const INSTANCE_ID = '*****';

var AWS = require('aws-sdk'); 
AWS.config.region = '*****';

function ec2Stop(cb){
    var ec2 = new AWS.EC2();
    var params = {
        InstanceIds: [
            INSTANCE_ID
        ]
    };

    ec2.stopInstances(params, function(err, data) {
        if (!!err) {
            console.log(err, err.stack);
        } else {
            console.log(data);
            cb();
        }
    });
}
exports.handler = function(event, context) {
    console.log('start');
    ec2Stop(function() {
        context.done(null, 'Stoped Instance');
    });
};

ロールのPolicy Documentは下記jsonを

{
    "Version": "2012-10-17",
    "Statement": [
        {
            "Effect": "Allow",
            "Action": [
                "logs:CreateLogGroup",
                "logs:CreateLogStream",
                "logs:PutLogEvents",
                "ec2:StopInstances"
            ],
            "Resource": [
                "arn:aws:logs:*:*:*",
                "arn:aws:ec2:*"
            ]
        }
    ]
}

これで、起動用の関数と停止用の関数が作成できました。

CloudWatch

さて、次に(最後ですが)CloudWatchを利用して朝と夜にLambdaの関数を実行したいと思います。

CloudWatchのページで、左のメニューから「Rules」を選び、「Create rule」をクリック

スクリーンショット 2016-12-22 20.35.52.png

Event selectorScheduleを選択し、Cron expressionのラジオボタンにチェックを入れます。

Cron expressionの値は、0 0 ? * MON-FRI *を入力してください。

cronの詳細な説明は省きますが、AWSの時間と日本の時間は9時間ずれていて

平日の朝9時に実行したい場合は0 0 ? * MON-FRI *になります。

TargetsにはLambda functionを選択し

Functionには先程作成した開始用の関数を選択してください。

入力が終わったら「Configure details」をクリック。

スクリーンショット 2016-12-22 20.38.27.png

最後にスケジュールの名前や説明文を入力します。

項目
Name 適当に
Description 適当に
State チェックを入れる

入力したら、「Create rule」をクリックして完了です。

スクリーンショット 2016-12-22 20.44.52.png

停止用は平日の18時に停止するようにCron expression

0 9 ? * MON-FRI *を入力して、Functionに停止用の関数を設定してください。

これで、平日朝9時にEC2が起動し、平日夜18時にEC2が停止するようになりました。

最後に

夜間停止は思ったより簡単で、AWSのサービスを組み合わせるだけで実現ができました!

あとは、ALBの夜間停止がしたいのですが、どうやらALBは停止という概念はなく

起動しているか、壊すかの2択っぽいです・・・

terraformとかで実現すれば良いのでしょうか・・・調査中です(´・ω・`)