AWS-CloudFormation

EventBridge Schedulerでユニバーサルターゲット(AWS SDK)を実行するスケジュールをCloudFormationで作成してみた

はじめに

こんにちは、omkです。
EventBridge Scheduler、いいですよね。

EventBridge RuleからLambdaをキックしてAWS SDKで……という従来のやり方から変わってLambdaを管理せずに多くのAWSリソースを操作出来るようになった点でかなりありがたく思っています。
コードの品質とかランタイムの期限とか面倒ですからねぇ。

そんなわけでCFnでSchedulerを作っていこうと思ったのですが、2022年12月16日現在のドキュメントではまだ充実しておらず、サンプルも無くて具体的にどんな値を入れたらよいのかというイメージがしづらく感じました。
https://docs.aws.amazon.com/AWSCloudFormation/latest/UserGuide/aws-resource-scheduler-schedule.html

とりあえずCLIのhelpから紐解いて作ってみました。あとこの辺参考にしてます。
https://docs.aws.amazon.com/scheduler/latest/UserGuide/managing-schedule-flexible-time-windows.html
https://docs.aws.amazon.com/scheduler/latest/UserGuide/managing-schedule-state.html

他にも困っている方がいるかもしれませんのでドキュメントにサンプルが追加されるまで参考にしてもらえるものを用意できたらと思います。

CFnテンプレート上でやること

  • AWS SDK(ユニバーサルターゲット)でEC2を起動する・停止する2種類のスケジュールを作成
  • スケジュールグループを作成
  • スケジュールで利用するIAMロール・ポリシーを作成

できたもの

AWSTemplateFormatVersion: '2010-09-09'
Description: Scheduler Template

Parameters:
  InstanceId:
    Type: String

Mappings:
  EventSchedule:
    EC2:
      StartCron: "cron(0 9 * * ? *)"
      StopCron: "cron(0 19 * * ? *)"

Resources:

  ScheduleRole:
    Type: AWS::IAM::Role
    Properties: 
      AssumeRolePolicyDocument: 
        {
            "Version": "2012-10-17",
            "Statement": [
                {
                    "Effect": "Allow",
                    "Principal": {
                        "Service": "scheduler.amazonaws.com"
                    },
                    "Action": "sts:AssumeRole"
                }
            ]
        }
      RoleName: blog-schedule-ec2-role

  ScheduleRolePolicy:
    Type: AWS::IAM::Policy
    Properties: 
      PolicyDocument: 
        {
            "Version": "2012-10-17",
            "Statement": [
                {
                    "Sid": "VisualEditor0",
                    "Effect": "Allow",
                    "Action": [
                        "ec2:StartInstances",
                        "ec2:StopInstances"
                    ],
                    "Resource": !Sub "arn:aws:ec2:${AWS::Region}:${AWS::AccountId}:instance/${InstanceId}"
                }
            ]
        }
      PolicyName: "blog-schedule-ec2-role-policy"
      Roles: 
        - !Ref ScheduleRole

  ScheduleGroup:
    Type: AWS::Scheduler::ScheduleGroup
    Properties: 
      Name: "blog-schedule-group"

  EC2StartSchedule:
    Type: AWS::Scheduler::Schedule
    Properties: 
      Description: "Start EC2 Instance"
      FlexibleTimeWindow: 
        Mode: "OFF"
      GroupName: !Ref ScheduleGroup
      Name: "blog-ec2-start-schedule"
      ScheduleExpression: !FindInMap  [ EventSchedule, EC2, StartCron ]
      ScheduleExpressionTimezone: "Asia/Tokyo"
      State: "ENABLED"
      Target: 
        Arn: "arn:aws:scheduler:::aws-sdk:ec2:startInstances"
        Input: !Sub "{ \"InstanceIds\": [ \"${InstanceId}\" ] }"
        RoleArn: !GetAtt ScheduleRole.Arn
        RetryPolicy: 
          MaximumRetryAttempts: 0

  EC2StopSchedule:
    Type: AWS::Scheduler::Schedule
    Properties: 
      Description: "Stop EC2 Instance"
      FlexibleTimeWindow: 
        Mode: "OFF"
      GroupName: !Ref ScheduleGroup
      Name: "blog-ec2-stop-schedule"
      ScheduleExpression: !FindInMap  [ EventSchedule, EC2, StopCron ]
      ScheduleExpressionTimezone: "Asia/Tokyo"
      State: "ENABLED"
      Target: 
        Arn: "arn:aws:scheduler:::aws-sdk:ec2:stopInstances"
        Input: !Sub "{ \"InstanceIds\": [ \"${InstanceId}\" ] }"
        RoleArn: !GetAtt ScheduleRole.Arn
        RetryPolicy: 
          MaximumRetryAttempts: 0

ポイント

まずはスケジュールで利用するIAMロールについて、信頼されたエンティティに入れるサービス名は「scheduler.amazonaws.com」です。

次に本題ですがスケジュールについてです。

「FlexibleTimeWindow」の「Mode」で取る値ですが、フレックスタイムウィンドウを利用する場合は「FLEXIBLE」、利用しない場合は「OFF」を取ります。
上では「Mode: "OFF"」と入れていますが、OFFをダブルクォーテーションで囲っておかないとCFn実行時にエラーが出るので注意です。

「State」の値は「ENABLED」「DISABLED」のいずれかです。全大文字なので注意(ドキュメントには小文字で書かれているが取る値として書かれているわけではない)です。

あと「Target」の「Arn」は何を入れるんだというところですが、今回はAWS SDKのユニバーサルターゲットを作成するのでSDKのARNが入ります。
ここの書き方が全然載っていないように思えたのでちょっと苦労しました。

「Input」はSDKが取る引数(コンパネでいうところのペイロード)が入ります。

「RetryPolicy」はデフォルトで「イベントの最大保持時間: 1日」、「最大再試行回数: 185 回」の設定が入ります。
再試行しない場合は明記する必要があります。
その際は、「MaximumRetryAttempts」に0を入れる必要があり、「MaximumEventAgeInSeconds」は指定しない必要があります(入れるとエラーでます)。

おわりに

分かりづらかったところはこんな感じかなと思いますがもし他にもありましたらコメントに書いていただけると分かる範囲で回答します。
最後までお付き合いありがとうございました。

返信を残す

メールアドレスが公開されることはありません。 が付いている欄は必須項目です

CAPTCHA