EC2インスタンスを定期的に起動/停止する3つの方法

EC2インスタンスを定期的に起動/停止する3つの方法

EC2インスタンスを定期的に起動/停止する3つの方法

EC2インスタンスを定期的に起動/停止する方法を考えます。

1つ目はEventBridgeを使って、インスタンス起動/停止用のLambda関数を定期的に実行する方法です。
「Instance Scheduler」と呼ばれている方法です。

https://aws.amazon.com/jp/solutions/implementations/instance-scheduler-on-aws/

2つ目はメンテナンスウィンドウを定義して、インスタンス起動/停止用のSSM Automationランブック(AWS-StartEC2Instance, AWS-StopEC2Instance)を定期的に実行する方法です。

https://docs.aws.amazon.com/ja_jp/systems-manager-automation-runbooks/latest/userguide/automation-aws-startec2instance.html

https://docs.aws.amazon.com/ja_jp/systems-manager-automation-runbooks/latest/userguide/automation-aws-stopec2instance.html

3つ目はEventBridge Schedulerを使って、インスタンス起動/停止用のAPIを定期的に呼び出す方法です。

https://docs.aws.amazon.com/ja_jp/eventbridge/latest/userguide/scheduler.html

本ページでは、CloudFormationを使って、上記の3つの方法を試します。

構築する環境

Diagram of three ways to start/stop EC2 instances periodically.

3つのEC2インスタンスを作成します。
OSは最新のAmazon Linux 2023とします。

各インスタンスに対して、冒頭でご紹介した設定を行います。
5分ごとにインスタンスを起動/停止させます。

なおLambda関数のランタイム環境はPython3.8とします。

CloudFormationテンプレートファイル

上記の構成をCloudFormationで構築します。
以下のURLにCloudFormationテンプレートを配置しています。

https://github.com/awstut-an-r/awstut-saa/tree/main/04/004

テンプレートファイルのポイント解説

EventBridgeとLambda関数を使用する方法

Lambda関数

Resources:
  StartInstanceFunction:
    Type: AWS::Lambda::Function
    Properties:
      Environment:
        Variables:
          INSTANCE_ID: !Ref Instance
          REGION: !Ref AWS::Region
      Code:
        ZipFile: |
          import boto3
          import os

          instance_id = os.environ['INSTANCE_ID']
          region = os.environ['REGION']

          ec2_client = boto3.client('ec2', region_name=region)

          def lambda_handler(event, context):
            response = ec2_client.start_instances(
              InstanceIds=(instance_id,)
            )
            print(response)
      FunctionName: !Sub "${Prefix}-StartInstance"
      Handler: !Ref Handler
      Runtime: !Ref Runtime
      Role: !GetAtt FunctionRole.Arn
      Timeout: !Ref Timeout

  StopInstanceFunction:
    Type: AWS::Lambda::Function
    Properties:
      Environment:
        Variables:
          INSTANCE_ID: !Ref Instance
          REGION: !Ref AWS::Region
      Code:
        ZipFile: |
          import boto3
          import os

          instance_id = os.environ['INSTANCE_ID']
          region = os.environ['REGION']

          ec2_client = boto3.client('ec2', region_name=region)

          def lambda_handler(event, context):
            response = ec2_client.stop_instances(
              InstanceIds=(instance_id,)
            )
            print(response)
      FunctionName: !Sub "${Prefix}-StopInstance"
      Handler: !Ref Handler
      Runtime: !Ref Runtime
      Role: !GetAtt FunctionRole.Arn
      Timeout: !Ref Timeout
Code language: YAML (yaml)

2つのLambda関数を作成します。
一方はインスタンスの開始、もう一方は停止を行います。

boto3のEC2用クライアントオブジェクトを作成します。
同オブジェクトのstart_instancesおよびstop_instancesメソッドを実行します。

以下が両関数用のIAMロールです。

Resources:
  FunctionRole:
    Type: AWS::IAM::Role
    DeletionPolicy: Delete
    Properties:
      AssumeRolePolicyDocument:
        Version: 2012-10-17
        Statement:
          - Effect: Allow
            Action: sts:AssumeRole
            Principal:
              Service:
                - lambda.amazonaws.com
      ManagedPolicyArns:
        - arn:aws:iam::aws:policy/service-role/AWSLambdaBasicExecutionRole
      Policies:
        - PolicyName: InstanceStartStopPolicy
          PolicyDocument:
            Version: 2012-10-17
            Statement:
              - Effect: Allow
                Action:
                  - ec2:StartInstances
                  - ec2:StopInstances
                Resource: !Sub "arn:aws:ec2:${AWS::Region}:${AWS::AccountId}:instance/${Instance}"
Code language: YAML (yaml)

インスタンスの起動/停止アクションを許可する内容です。

EventBridgeルール

本ページでは、EC2インスタンスを定期的に起動・停止する方法を中心に取り上げます。

EventBridgeルールを使って、Lambda関数を定期的に実行する方法については、以下のページをご確認ください。

あわせて読みたい
EventBridge(CloudWatch Events)のスケジュール式で、Lambda関数を定期的に実行する 【Lambda関数を定期的に実行する】 EventBridgeを使用することで、定期的なアクションを設定することができます。 今回はLambda関数を定期的に実行します。 【構築する...
Resources:
  StartInstanceScheduleRule:
    Type: AWS::Events::Rule
    Properties:
      ScheduleExpression: cron(0,10,20,30,40,50 * * * ? *)
      State: ENABLED
      Targets:
        - Arn: !GetAtt StartInstanceFunction.Arn
          Id: !Sub "${Prefix}-StartInstanceScheduleRule"

  StopInstanceScheduleRule:
    Type: AWS::Events::Rule
    Properties:
      ScheduleExpression: cron(5,15,25,35,45,55 * * * ? *)
      State: ENABLED
      Targets:
        - Arn: !GetAtt StopInstanceFunction.Arn
          Id: !Sub "${Prefix}-StopInstanceScheduleRule"
Code language: YAML (yaml)

一方は起動用で、もう一方は停止用です。
それぞれ先述の関数をターゲットとしています。

cron式で起動状況を設定します。
起動用関数は毎時0, 10, … 50分に呼び出します。
停止用関数は毎時5, 15, … 55分を呼び出します。
これらを組み合わせると、5分ごとに起動・停止を繰り返すことになります。

EventBridgeルールを使ってLambda関数を定期的にする場合、EventBridgeが関数を呼び出す形となります。
ですからEventBridgeに関数を呼び出す権限を与える必要があります。

Resources:
  StartInstanceFunctionPermission:
    Type: AWS::Lambda::Permission
    Properties:
      Action: lambda:InvokeFunction
      FunctionName: !GetAtt StartInstanceFunction.Arn
      Principal: events.amazonaws.com
      SourceArn: !GetAtt StartInstanceScheduleRule.Arn
Code language: YAML (yaml)

上記は起動用関数を呼び出すためのパーミッションですが、停止用も同様です。
EventBridgeルールとLambda関数と指定します。

SSM Automationランブックを使用する方法

メンテナンスウィンドウを設定して、SSM Automationランブックを定期的に実行します。

こちらの詳細については、以下のページをご確認ください。

あわせて読みたい
SSM Automationを使用してAMIを作成する(単発/定期) 【SSM Automationを使用してAMIを作成する(単発/定期)】 AMIを作成する方法はいくつかあります。 例えばマネージメントコンソールから作成する方法が、以下のページで紹...

なお今回は使用しませんが、EventBridgeルールを使用して、SSM Automationランブックを定期的に実行することもできます。

こちらについては、以下のページをご確認ください。

あわせて読みたい
EventBridgeルールを使用して、SSM Automationランブックを定期的に実行する 【EventBridgeルールを使用して、SSM Automationランブックを定期的に実行する】 以下のページで、SSM Automationランブックを実行する方法をご紹介しました。 https://...

まずメンテナンスウィンドウを確認します。

Resources:
  MaintenanceWindow1:
    Type: AWS::SSM::MaintenanceWindow
    Properties:
      AllowUnassociatedTargets: true
      Cutoff: 1
      Description: StartInstance
      Duration: 2
      Name: !Sub "${Prefix}-MaintenanceWindow1"
      Schedule: cron(0,10,20,30,40,50 * * * ? *)
      ScheduleTimezone: Asia/Tokyo
Code language: YAML (yaml)

上記は起動用のウィンドウですが、停止用も同様です。
Scheduleプロパティでランブックを実行するタイミングを指定できます。
設定内容は1つ目の方法と同様です。

次にメンテナンスウィンドウのターゲットを確認します。

Resources:
  MaintenanceWindowTarget1:
    Type: AWS::SSM::MaintenanceWindowTarget
    Properties:
      Name: !Sub "${Prefix}-MaintenanceWindowTarget1"
      ResourceType: INSTANCE
      Targets:
        - Key: InstanceIds
          Values:
            - !Ref Instance
      WindowId: !Ref MaintenanceWindow1
Code language: YAML (yaml)

IDを指定して、起動・停止する対象のインスタンスを定めます。

最後にメンテナンスウィンドウで実行するタスクを確認します。

Resources:
  MaintenanceWindowTask1:
    Type: AWS::SSM::MaintenanceWindowTask
    Properties:
      MaxConcurrency: 1
      MaxErrors: 1
      Name: !Sub "${Prefix}-MaintenanceWindowTask1"
      Priority: 10
      Targets:
        - Key: WindowTargetIds
          Values:
            - !Ref MaintenanceWindowTarget1
      TaskArn: AWS-StartEC2Instance
      TaskInvocationParameters:
        MaintenanceWindowAutomationParameters:
          Parameters:
            AutomationAssumeRole:
              - !GetAtt SSMAutomationRole.Arn
            InstanceId:
              - "{{RESOURCE_ID}}"
      TaskType: AUTOMATION
      WindowId: !Ref MaintenanceWindow1
Code language: YAML (yaml)

起動用タスクとして、SSM AutomationランブックAWS-StartEC2Instanceを指定します。
停止用では、AWS-StopEC2Instanceを指定します。

以下がこのタスクを実行する上でのIAMロールです。

Resources:
  SSMAutomationRole:
    Type: AWS::IAM::Role
    DeletionPolicy: Delete
    Properties:
      AssumeRolePolicyDocument:
        Version: 2012-10-17
        Statement:
          - Effect: Allow
            Action: sts:AssumeRole
            Principal:
              Service:
                - ssm.amazonaws.com
      Policies:
        - PolicyName: CreateImagePolicy
          PolicyDocument:
            Version: 2012-10-17
            Statement:
              - Effect: Allow
                Action:
                  - ec2:StartInstances
                  - ec2:StopInstances
                Resource: !Sub "arn:aws:ec2:${AWS::Region}:${AWS::AccountId}:instance/${Instance}"
Code language: YAML (yaml)

インスタンスの起動/停止アクションを許可する内容です。

EventBridge Schedulerを使用する方法

Resources:
  StartInstanceSchedule:
    Type: AWS::Scheduler::Schedule
    Properties:
      Description: StartInstance
      FlexibleTimeWindow:
        Mode: "OFF"
      Name: !Sub "${Prefix}-StartInstanceSchedule"
      ScheduleExpression: cron(0,10,20,30,40,50 * * * ? *)
      State: ENABLED
      Target:
        Arn: arn:aws:scheduler:::aws-sdk:ec2:startInstances
        Input: !Sub '{"InstanceIds": ["${Instance}"]}'
        RoleArn: !GetAtt SchedulerRole.Arn

  StopInstanceSchedule:
    Type: AWS::Scheduler::Schedule
    Properties:
      Description: StopInstance
      FlexibleTimeWindow:
        Mode: "OFF"
      Name: !Sub "${Prefix}-StopInstanceSchedule"
      ScheduleExpression: cron(5,15,25,35,45,55 * * * ? *)
      State: ENABLED
      Target:
        Arn: arn:aws:scheduler:::aws-sdk:ec2:stopInstances
        Input: !Sub '{"InstanceIds": ["${Instance}"]}'
        RoleArn: !GetAtt SchedulerRole.Arn
Code language: YAML (yaml)

上が起動用、下が停止用のスケジュールです。

ポイントは2つです。

1つ目はScheduleExpressionプロパティです。
本プロパティでアクションをスケジュールできます。
こちらもcron式でスケジュールを定義します。

2つ目はTargetプロパティです。

Arnプロパティに実行するAPIオペレーションを指定します。

Arn — ターゲットとする API オペレーションを含む完全なサービス ARN を次の形式で示します

arn:aws:scheduler:::aws-sdk:service:apiAction

ユニバーサルターゲットの使用

EC2用のAPIは以下の記法で指定します。

arn:aws:scheduler:::aws-sdk:ec2:[apiAction]

今回の要件では、起動はstartInstances、停止はstopInstancesを実行します。

Inputプロパティに両APIを呼び出すための引数を指定します。

EventBridge スケジューラがターゲット API に送信するリクエストパラメータで指定する、整形された JSON。

ユニバーサルターゲットの使用

以下のページを見ると、両APIを呼び出す際は、InstanceIdsに対象のインスタンスのIDを渡せば良いことがわかります。

https://docs.aws.amazon.com/ja_jp/AWSEC2/latest/APIReference/API_StartInstances.html

https://docs.aws.amazon.com/ja_jp/AWSEC2/latest/APIReference/API_StopInstances.html

本プロパティにJSON形式でインスタンスIDを渡します。

RoleArnプロパティは以下の通り説明されています。

RoleArn— ターゲットに使用したい実行ロールの ARN。指定する実行ロールには、スケジュールの対象とする API オペレーションを呼び出す権限が必要です。

ユニバーサルターゲットの使用

以下のIAMロールを指定します。

Resources:
  SchedulerRole:
    Type: AWS::IAM::Role
    DeletionPolicy: Delete
    Properties:
      AssumeRolePolicyDocument:
        Version: 2012-10-17
        Statement:
          - Effect: Allow
            Action: sts:AssumeRole
            Principal:
              Service:
                - scheduler.amazonaws.com
      Policies:
        - PolicyName: CreateImagePolicy
          PolicyDocument:
            Version: 2012-10-17
            Statement:
              - Effect: Allow
                Action:
                  - ec2:StartInstances
                  - ec2:StopInstances
                Resource: !Sub "arn:aws:ec2:${AWS::Region}:${AWS::AccountId}:instance/${Instance}"
Code language: YAML (yaml)

インスタンスの起動/停止アクションを許可する内容です。

環境構築

CloudFormationを使用して、本環境を構築し、実際の挙動を確認します。

CloudFormationスタックを作成し、スタック内のリソースを確認する

CloudFormationスタックを作成します。
スタックの作成および各スタックの確認方法については、以下のページをご確認ください。

あわせて読みたい
CloudFormationのネストされたスタックで環境を構築する 【CloudFormationのネストされたスタックで環境を構築する方法】 CloudFormationにおけるネストされたスタックを検証します。 CloudFormationでは、スタックをネストす...

各スタックのリソースを確認した結果、今回作成された主要リソースの情報は以下の通りです。

  • 1つ目の構成
    • EC2インスタンス1:i-0b9e6d15e61ee820c
    • Lambda関数1:saa-04-004-StartInstance
    • Lambda関数2:saa-04-004-StopInstance
    • EventBridgeルール1:saa-04-004-LambdaStack-HT-StartInstanceScheduleRul-RUFGLCMCBAMB
    • EventBridgeルール2:saa-04-004-LambdaStack-HT-StopInstanceScheduleRule-Q509A3N87K0U
  • 2つ目の構成
    • EC2インスタンス2:i-0c9f61ea77b7a59e4
    • メンテナンスウィンドウ1:mw-01d6f438ebac17258
    • メンテナンスウィンドウ2:mw-03e3e07dfcdd5a7fb
  • 3つ目の構成
    • EC2インスタンス3:i-0e54794687e579ba1
    • EventBridge Scheduler 1:saa-04-004-StartInstanceSchedule
    • EventBridge Scheduler 2:saa-04-004-StopInstanceSchedule

準備が整いましたので、AWS Management Consoleから各リソースを確認します。

1つ目の構成

Lambda関数を確認します。

Deetail of Lambda 1.
Deetail of Lambda 2.

両関数が正常に作成されていることがわかります。

EventBridgeを確認します。

Detail of EventBridge 1.
Detail of EventBridge 2.
Detail of EventBridge 3.
Detail of EventBridge 4.

5分ずれで、10分おきに関数を実行するルールが作成されています。

2つ目の構成

メンテナンスウィンドウの作成状況を確認します。

Detail of SSM 1.
Detail of SSM 2.
Detail of SSM 3.

起動用のメンテナンスウィンドウです。

Detail of SSM 4.
Detail of SSM 5.
Detail of SSM 6.

停止用のメンテナンスウィンドウです。

どちらも正常に作成されています。

3つ目の構成

Detail of EventBridge 5.
Detail of EventBridge 6.

起動用のスケジューラです。

Detail of EventBridge 7.
Detail of EventBridge 8.

停止用のスケジューラです。

どちらも正常に作成されています。

動作確認

準備が整いましので、EC2インスタンスを確認します。

1台目

Detail of EC2 1.
Detail of EC2 2.

2台目

Detail of EC2 3.
Detail of EC2 4.

3台目

Detail of EC2 5.
Detail of EC2 6.

確かに3台とも5分おきに起動と停止を繰り返します。

3つの全ての方法で、インスタンスを定期的に起動・停止させることができました。

まとめ

EC2インスタンスを定期的に起動・停止する方法を3つご紹介しました。