AWS EC2インスタンスの夜間休日停止設定【CloudFormation】

# はじめに
EC2インスタンスのコスト削減を行いたくて調査をしていたところ、
EventBridgeを用いて夜間＋土日の停止設定ができるとのこと。

AWS マネジメントコンソール上でポチポチ行う方法でもいいが、どうせならCloudFormationでテンプレ化したい。

ということで、実際にCfnで記述していく。

# やったこと
EventBridgeのルールを用いて夜間の停止設定を行う。
具体的には以下のルールを設定。

- 月～金の9:00にインスタンスを起動
- 月～金の22:30にインスタンスの停止


作成したCloudFormationテンプレートはこの通り。
EC2インスタンスのIDは停止させたいものを都度選択する。


```yaml:EC2夜間設定
AWSTemplateFormatVersion: '2010-09-09'
Description: Night time shutdown settings for EC2 instance

# CloudFormation作成時に利用される
Metadata:
  AWS::CloudFromation::Interface:
    ParameterGroups:
    - Label:
        default: Schedule Time
      Parameters:
        - ScheduleStartTime
        - ScheduleStopTime

# パラメータ設定
Parameters:
  ScheduleStartTime:
    Type: String
    Default: "cron(0 24 ? * SUN-THU *)"
  ScheduleStopTime:
    Type: String
    Default: "cron(30 13 ? * MON-FRI *)"
  InstanceID:
    Description: Target EC2 ID
    Type: String
    Default: {停止させたいEC2インスタンスのIDを設定}

Resources:
# 起動のルール
  StartEventRule:
    Type: AWS::Events::Rule
    Properties:
      EventBusName: default
      Name: !Sub EC2-Start-${InstanceID}
      Description: Scheduled EC2 start time
      ScheduleExpression: !Ref ScheduleStartTime
      State: Enabled
      Targets:
        - Id: StartEc2
          Arn: !Sub arn:aws:ssm:${AWS::Region}::automation-definition/AWS-StartEC2Instance:$DEFAULT
          RoleArn: !GetAtt ExecuteStartStopRole.Arn
          Input: !Sub |-
            {
              "InstanceId": ["${InstanceId}"]
            }
            
# 停止のルール
  StartEventRule:
    Type: AWS::Events::Rule
    Properties:
      EventBusName: default
      Name: !Sub EC2-Stop-${InstanceID}
      Description: Scheduled EC2 stop time
      ScheduleExpression: !Ref ScheduleStoptTime
      State: Enabled
      Targets:
        - Id: StopEc2
          Arn: !Sub arn:aws:ssm:${AWS::Region}::automation-definition/AWS-StartEC2Instance:$DEFAULT
          RoleArn: !GetAtt ExecuteStartStopRole.Arn
          Input: !Sub |-
            {
              "InstanceId": ["${InstanceId}"]
            }

# IAMロールの作成
  ExecuteStartStopRole:
    Type: AWS::IAM::Role
    Properties:
      AssumeRolePolicyDocument:
        Version: '2012-10-17'
        Statement:
        - Effect: Allow
          Principal:
            Service:
            - ssm.amazonaws.com
            - ec2.amazonaws.com
            - events.amazonaws.com
          Action:
            - sts:AssumeRole
        ManagedPolicyArns:
          - "arn:aws:iam::aws:policy/service-role/AmazonSSMAutomationRole"
        Path: "/"
```

あとは上記テンプレートをCfnで流すだけで設定完了です。

### 注意点
上記のコードは以下の点に気をつけてください。
- cron式はUTC時間で記入する必要がある。詳しくは[Amazon EventBridgeをCfnで作成するときのcron式](https://qiita.com/HiaHia/items/4045697ed1ee8ecbeb09)を参考。
- インスタンスは都度設定する必要あり。


# おわりに
これで夜間の停止設定が完了した。
しかし、インスタンス数が増えればその度にCfnを流す必要が。。。
VPCに対して適用させることで対処できるが、他のリソースも含まれている場合の考慮が必要になるなぁ。

# 参考
- [【コスト削減】AWS EC2インスタンス 夜間休日自動停止方法 (4) AWS Instance Scheduler](https://qiita.com/mksamba/items/d4d8eeb1200562d5de23)
- [https://techblog.techfirm.co.jp/entry/aws-ec2-automation](https://techblog.techfirm.co.jp/entry/aws-ec2-automation)
- [EC2 インスタンスの起動と停止を自動化することは出来ますか？](https://dev.classmethod.jp/articles/tsnote-ec2-ssm-automation/)
- [CloudFormationで実装してみた](https://techblog.nhn-techorus.com/archives/24724)