毎日0時にEC2インスタンスを自動で停止させる方法

クラウド

EC2インスタンスを切り忘れることが多く、さすがにちょっと自分に嫌気がさしてきたので、強制的に停止させる仕組みを作ることにしました。

なお、タイトルは0時としていますが、任意の時間(曜日、特定日・・・)を選択可能です。

前提条件

今回やりたいことは以下になります。

  • 毎日0時になったら、もしEC2インスタンスが停止していなければ停止させる
  • 停止対象のEC2インスタンスが複数ある

調べたところ、EC2インスタンスが1つだけの場合だと Systems Manager によりサクッと停止処理を実現できそうなのですが、複数のEC2インスタンスを停止させるとなると Lambda を使用しないと難しそうです。(Systems Manager の停止処理のイベントを複数定義する方法もありますが・・・)

ということで、上記条件を満たして毎日0時に自動停止する方法の備忘録します。

概要

使用するAWSサービス

今回の条件を実現するために必要なサービスは以下の通りでした。

  • IAM
  • Lambda
  • EventBridge

仕組みのイメージ

EventBridge によりスケジュールイベントを発行

Lambdaをコール

LambdaからEC2インスタンスの停止処理

参考サイト

【AWS】EC2の自動起動・自動停止を実装する方法 - BFT名古屋 TECH BLOG
2022/12/10 最新の情報に更新しました。また一部の文章を修正・更新しています。 こんにちは! BFT名古屋支店の佐野です。 今回はEC2インスタンスが一定時刻に起動、停止する仕組み作りについてのお話です。 EC2インスタンスは起動している間だけ料金が発生するので、誰も触っていない時間帯に起動させておくのは非常に...
Lambda 関数を使用して EC2 インスタンスを定期的に停止し、起動する
Amazon EC2 の使用量を減らすために、Amazon Elastic Compute Cloud (Amazon EC2) インスタンスを自動的に停止し、起動したいと思います。

実行手順

大まかな流れは以下の感じです。

  1. LambdaがEC2インスタンスを停止できるように、Lambda用のIAMロール作成
  2. EC2インスタンスを停止させるためのLambda関数を作成
    • IAMロールもアタッチ
  3. EventBridgeにてスケジュールイベントを設定し、Lambdaをコールするように設定

Lambda用のIAMロールの作成

ポリシーの作成

IAMのサービス画面に行き、下記の通りポリシー作成を選択します。

作成画面では、「JSON」タブを選択し、下記の JSON を直入力します。

(下記、公式より抜粋)

{
  "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": "*"
    }
  ]
}

画面をそのまま進めて作成します。(名前は任意のものでよいです)

IAMロールの作成

IAMのサービス画面に行き、下記の通りロール作成を選択します。

Lambdaを選択します。

ポリシーの選択では、先ほど作成したポリシーのみを選択します。

以降は、画面をそのまま進めて作成します。(名前は任意のものでよいです)

EC2インスタンスを停止させるための Lambda の作成

Lambdaのサービス画面に行き、下記の通り「関数の作成」を選択します。

次画面で以下の通り、入力します。
ロールは、先ほど作成したものを選択します。


関数の作成については、下記のように入力します。

EventBridgeから呼ばれる際の引数でリージョンやインスタンスの配列、開始か停止かのフラグを与えるようにしています。

import boto3

# event引数で以下を渡されることとする
# 'Region':リージョン名
# 'Instances':インスタンスIDの配列(複数インスタンス可能)
# 'Action':Start or Stop
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)
    elif event['Action'] == 'stop':
        ec2.stop_instances(InstanceIds=instances)

上記入力したら、「Deploy」ボタンを押します。

ここで、関数の作成は完了ですが、追加設定やテストをしておきます。

タイムアウトを変更

デフォルトではタイムアウトが3秒になっているみたいなので、ちょっとシビアです。
ケースバイケースですが、一応30秒とかにしてみます。

下記の通り、画面そのままで「設定」タブを選択し、編集ボタンを押します。

任意の秒数に変更して保存します。

Lambda関数の動作確認

続いていったん動作確認しておきます。
以下の画面で「Test」ボタンを押します。

下記のような画面が出てくるので、下記の通り入力します。

テストに入力するJSONは以下。

{
  "Action": "stop",
  "Region": "ap-northeast-1",
  "Instances": ["i-xxxxx", "i-xxxxx", "i-xxxxx"] // インスタンスIDの配列
}

下記の通り、Testボタンを押してテストを実行してみます。

うまくいけば、指定したインスタンスが全て停止になっているはずです。

EventBridgeにLambda関数を登録する

EventBridgeのサービス画面に行き、「EventBridgeスケジュール」を選択し、「スケジュールを作成」を押します。

スケジュール名には任意の名前を入力します。
スケジュールのパターンについては、下記の通り「定期的なスケジュール」を選択→「cronベースのスケジュール」を選択します。

cron式は、0 15 ? * * * としていますが、「分」と「時間」のところは任意のものでよいです。
注意:UCT時間になっている場合があります


ターゲットの選択は Lambda を選択します。


再試行ポリシーはいったん無効でいいと思います。

以降はそのまま進んでスケジュール作成完了です。

以上で、目的達成です。

コメント

タイトルとURLをコピーしました