EC2の定時自動起動・停止をLambdaで実装する

今回は、複数のEC2インスタンスをInstanceIDを指定して定時に自動起動・自動停止する処理をLambdaで実装してみたいと思います。
よりシンプルに、ハードコーディングはせず値はCloudWatchから渡すやり方で実装しました。

使うリソースは以下。

1. IAM Role(Lambda用)
2. Lambda(処理を記載)
3. CloudWatch Events(時刻を指定してLambdaをキック)

それではやっていきます。

1. IAMロールの作成

1-1. IAMポリシーの作成

▼ポリシー名
StartStopEC2Policy
▼コード

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

1-2. IAMロールの作成

以下のロール名でIAMロールを作成し、1-1.で作成したIAMポリシーをアタッチします
▼ロール名
lambda_start_stop_ec2

以下の通りに作成されればOK

f:id:tomomiik:20200303101735p:plain

2. Lambdaの作成

以下のLambda名でLambdaを作成し、1で作成したIAMロールを指定する
▼Lambda名
StartStopEC2Instances

2-1.Lambdaの作成

「関数の作成」> 「一から作成」を選択し、基本的な情報に以下を入力し、「関数の作成」ボタンを押下 ・関数名:StartStopEC2Instances
・ランタイム:Python2.7
・アクセス権限(実行ロールの選択または作成):「既存のロールを使用する」を選択し、既存のロールのプルダウンから1で作成したIAMロールを指定する

2-2.Lambdaの設定(コード)

関数コードに以下のコードを上書きする
・コードエントリタイプ:コードをインラインで編集
・ランタイム:Python 2.7
・ハンドラ:変更なし

import boto3
 
def lambda_handler(event, context):
    region = event['Region']
    instances = event['Instances']
    ec2 = boto3.client('ec2', region_name=region)
    if event['Action'] == 'start':
        ec2.start_instances(InstanceIds=instances)
        print 'started your instances: ' + ", ".join(instances)
    elif event['Action'] == 'stop':
        ec2.stop_instances(InstanceIds=instances)
        print 'stopped your instances: ' + ", ".join(instances)

※ Lambdaへのハードコーディングは避け、必要な値はCloudWatch Eventsから渡すようにしています

2-3.Lambdaの設定(基本設定)

基本設定でのタイムアウト値を2分に設定し、画面上の「保存」ボタンを押下 ※ デフォルトで3秒になっているため、3秒だと停止する前に終了しエラーになってしまいます。適切な停止時間に合わせたタイムアウト値を設定をしてください。

3. CloudWatchEventの作成

CloudWatch Eventでは、EC2の起動用のルールとEC2の停止用のルールの2つを作成します。各々、cronでLambdaをキックする時間を指定し、関数コードに渡す値はjsonで指定します。 ここでは夜8時に停止し、朝8時に起動するよう設定していきます。

3-1. EC2の停止のルールを作成(20時停止)

CloudWatchEventの画面にて「ルールの作成」を押下し、以下を入力します。
・イベントソース:スケジュールを指定し、Cronには以下を指定する(cronの時間はUTCなので注意しましょう)

0 11 * * ? *

・ターゲット:Lambda関数のプルダウンから作成した関数名を選択し、「入力の設定」で「定数(JSONテキスト)」を指定した上で、入力箇所に以下を入力する。対象のEC2のInstanceIDをセットし、複数指定したい場合はカンマ「,」で繋いで記載する。

{"Action": "stop", "Region": "ap-northeast-1", "Instances": ["<InstanceID>"]}

3-2. EC2の起動のルールを作成(8時起動)

CloudWatchEventの画面にて「ルールの作成」を押下し、以下を入力します。
・イベントソース:スケジュールを指定し、Cronには以下を指定する(cronの時間はUTCなので注意しましょう)

0 23 * * ? *

・ターゲット:Lambda関数のプルダウンから作成した関数名を選択し、「入力の設定」で「定数(JSONテキスト)」を指定した上で、入力箇所に以下を入力する。対象のEC2のInstanceIDをセットし、複数指定したい場合はカンマ「,」で繋いで記載する。

{"Action": "start", "Region": "ap-northeast-1", "Instances": ["<InstanceID>"]}

Lambda画面にてCloudWatchEventが以下のようにセットされればOK

f:id:tomomiik:20200303105612p:plain

4. 動作確認

CloudWatchEventsのCronの設定を一時的に直近の時間に指定して対象のEC2が停止 /起動するかを確認する

今回は、以下の参考サイトをもとに「やってみた」系の記事になりましたが、とてもシンプルに実装されているのでおすすめです。

▼参考サイト

dev.classmethod.jp

dev.classmethod.jp