AWS

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

More than 1 year has passed since last update.


初めに

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とかで実現すれば良いのでしょうか・・・調査中です(´・ω・`)