タグを指定するだけでEC2インスタンスを自動起動・停止する

# はじめに

EC2インスタンスの自動起動停止は、2016年頃はLambdaFunctionを使って実現してました。

LambdaFunctionが出たばかりで楽しくて書いてみたんですけど、まじめに実現しようとすると仕組みが複雑化したり、バグがでたりすることなどが少し悩みでした。

https://github.com/uzresk/aws-auto-operations-using-lambda

その後SystemManagerのオートメーションが発表され、CloudWatchEventsからSSM Automationの組み込みのドキュメントを使って実現していました。
バグで動かないなんてことも無くなったのでよかったのですが、対象とするEC2インスタンスが増えてくると自動停止・起動対象のEC2インスタンスIDをCloudWatchEventsのパラメータに設定するのが厳しくなってきました。

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/57686/15e87ec1-cf1c-f04f-623d-3a1f033eaf8b.png)

# さてどうしたか

ゴリゴリ書かずに**AWSの機能だけでタグベースで自動起動・停止を実現できないか**を考えていたのですが、AutomationActionにexecuteAwsApiが指定できるようになって実現できるようになりました。

AWS Systems Manager の新しい Automation アクションの使い方を紹介
https://aws.amazon.com/jp/blogs/news/onica-demonstrates-uses-for-new-aws-systems-manager-automation-actions/

つまり、CloudWatch EventsからSSM Automation Document（AWS-StopEC2Instance、AWS-StartEC2Instance）を呼び出すときにはインスタンスIDが必須になるのですが、ドキュメントを自分で作ることでタグやリソースグループを指定して起動停止できるようになります。

早速やってみます。

# ドキュメントの作成

SystemManagerの画面を開き、左メニューのドキュメント→「Create automation」を選びます。

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/57686/ff146111-bb79-65ad-dc9b-8987518a96ab.png)

名前に「StopEC2InstancesUsingTags_StopTime」と入力し、「コンテンツ」→「Edit」をクリックします。

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/57686/0b510f46-feb4-9102-18d8-42d87e0ddaba.png)

警告がでますがそのまま進み以下のyamlをコピペします。

タグ Key:StopTime, Value:8pm～11pmをAWS-StopEC2Instanceドキュメントに引数として渡してあげるように記載されています。

```yaml
description: StopEC2Instances Using Tags:StopTime
schemaVersion: "0.3"
assumeRole: "{{ AutomationAssumeRole }}"
parameters:
  StopTime:
    type: String
    default: 8pm
    description: (Required) 8pm,9pm,10pm,11pm 
    allowedValues:
    - 8pm
    - 9pm
    - 10pm
    - 11pm
  AutomationAssumeRole:
    type: String
    description: (Optional) The ARN of the role that allows Automation to perform the actions on your behalf.
    default: ""
mainSteps:
  - name: StopEC2Instances
    action: aws:executeAwsApi
    inputs:
      Service: ssm
      Api: StartAutomationExecution
      DocumentName: AWS-StopEC2Instance
      TargetParameterName: "InstanceId"
      Targets:
        -
           Key: tag:StopTime
           Values: 
             - "{{ StopTime }}"
```

これでドキュメントの作成は完成です。

# 動作確認してみる

対象のEC2インスタンスのタグにStopTime:8pmというタグを付与します。

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/57686/dfb3da8f-e12a-53cb-e4ab-6f0ee0d3d162.png)

先ほど作ったドキュメントStopEC2InstancesUsingTags_StopTimeを開き、オートメーションの実行をクリックします。

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/57686/0074e883-9267-dcd2-3b1c-1a6eac87c80e.png)

入力パラメータに8pmを指定して、実行します。

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/57686/adfb78af-fb8c-08dd-6154-25e5e30224ea.png)

実行の状況はこのように見えます。
StopEC2InstancesUsingTagsが成功すると、組み込みドキュメントであるAWS-StopEC2Instanceが起動しているのが確認できます。

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/57686/cd7684ae-b348-bdeb-f1f2-8dc7bac5042a.png)

EC2インスタンスが停止したことをマネジメントコンソールで確認しましょう。

# CloudWatchEventでスケジューリングする

午後8時に8pmタグが指定されたEC2インスタンスを停止するようにCloudWatchEventsに設定してみます。

ポイントは「SSM Automation」に先ほど指定したドキュメントを指定してください。

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/57686/c9f2dff6-5635-1d1a-e758-4cecd98b7277.png)
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/57686/0d41d96c-bbb8-0a0a-6c9d-bf5db808f346.png)

# Automationの失敗を通知する

これもCloudWatchEventsで設定します。
Automationのイベントが変更されたタイミングでFailed,Timeout,CancelledになったときにSNSを使って通知します。
CloudWatchEventsは複数設定した場合でもこの通知設定は一つで問題ありません。

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/57686/8c2a1f73-c1f0-b879-2102-f679a8b45b34.png)

時間ごとに設定しないといけないのは少し面倒ですけどしょうがないですね・・・。

# 自動起動バージョン

念のため貼っておきます。

```yaml
description: StartEC2Instances Using Tags:StartTime
schemaVersion: "0.3"
assumeRole: "{{ AutomationAssumeRole }}"
parameters:
  StartTime:
    type: String
    default: 8am
    description: (Required) 7am,8am,9am
    allowedValues:
    - 7am
    - 8am
    - 9am
  AutomationAssumeRole:
    type: String
    description: (Optional) The ARN of the role that allows Automation to perform the actions on your behalf.
    default: ""
mainSteps:
  - name: StartEC2Instances
    action: aws:executeAwsApi
    inputs:
      Service: ssm
      Api: StartAutomationExecution
      DocumentName: AWS-StartEC2Instance
      TargetParameterName: "InstanceId"
      Targets:
        -
           Key: tag:StartTime
           Values: 
             - "{{ StartTime }}"
```


# さいごに

AWS Systems Manager の新しい Automation アクションexecuteAwsApiがサポートされたことでより柔軟にアクションが指定できるようになりました。同じようにEC2の起動や、RDSの停止というアクションも実現可能ですしリソースグループを指定した停止も実現できるようになります。

参考までにリソースグループを指定する場合のドキュメントを張っておきます。
SystemManagerの画面でリソースグループを作成後、リソースグループ名を指定することでリソースグループまとめて停止が可能になります。

```yaml
---
description: Exec AWS-StopEC2Instances
schemaVersion: "0.3"
assumeRole: "{{ AutomationAssumeRole }}"
parameters:
  ResourceGroupName:
    type: String
    description: (Required) ResourceGroup Name to stop
  AutomationAssumeRole:
    type: String
    description: (Optional) The ARN of the role that allows Automation to perform the actions on your behalf.
    default: ""
mainSteps:
  -
    name: StopEC2Instances
    action: aws:executeAwsApi
    inputs:
      Service: ssm
      Api: StartAutomationExecution
      DocumentName: AWS-StopEC2Instance
      TargetParameterName: "InstanceId"
      Targets:
        -
           Key: ResourceGroup
           Values: 
             - "{{ ResourceGroupName }}"
```

# 参考

* [SSMドキュメントの構文](https://docs.aws.amazon.com/ja_jp/systems-manager/latest/userguide/sysman-doc-syntax.html)