【AWS】EventBridge SchedulerでEC2の自動起動・自動停止

EC2を使用していると、料金を抑えるために使用する時間帯以外は停止する運用をよくします。
その際今までは、手動だと停止し忘れが発生するので、EventBridge + Lambdaで自動化していました。

しかし、2022/11/10にEventBridge Schedulerが発表されたことにより、この機能のみで様々なリソースの自動停止が実現できるようになりました！
EC2を例にして、機能の特徴と作成方法を説明します。
![event_bridge_scheduler.drawio.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/1166959/81cf816a-0bbc-5cd7-ddc2-531bc72f142f.png)

# ターゲット

- AWSの最新機能を学たい
- EC2, RDS等を自動停止/起動したい
- すでにEventBridge + Lambdaで運用しているが、もっと簡略化したい

# EventBridge Schedulerのいいところ

EventBridge Schedulerの機能で、ここがいいなという点をいくつかまとめます。

## 料金

EventBridge Schedulerは無料利用枠が1400万回/月あります。
それ以上は100万回で1ドルです。

今回紹介するような1日数回の使用では無料です。

## タイムゾーン

EventBridge Schedulerはタイムゾーンを設定できます。
日本時間で設定する場合、わざわざUTC時間から計算する必要はありません。「(UTC +09:00) Asia/Tokyo」を選択するだけです。
UTC時間基準だと、日をまたぐような場合はミスをしやすいので、ありがたいかもしれません。

## 対応するAPI数

公式ブログの[Introducing Amazon EventBridge Scheduler](https://aws.amazon.com/jp/blogs/compute/introducing-amazon-eventbridge-scheduler/)にあるように、270以上のサービスの6000以上のAPIに対応しています。

## 実行ルール

定期的なスケジュールとしてcron式、rate式の2通りがあります。また、一回限りで日時を指定することもできます。
詳しくは、[スケジュールに従って実行する Amazon EventBridge ルールの作成](https://docs.aws.amazon.com/ja_jp/eventbridge/latest/userguide/eb-create-rule-schedule.html)でご確認ください。

# スケジュール作成方法

EventBridge SchedulerでEC2を停止するには以下のリソースが必要です。

- IAM
    - **ポリシー**：スケジュールを実行するロールに紐づける権限
    - **ロール**：スケジュールを実行するロール
- EventBridge
    - **スケジュールグループ**：スケジュールの管理単位
    - **スケジュール**：実行する内容の詳細

順番に作成手順を説明します。
すでに作成済みで必要のない場合はスキップしてください。

## 1. IAMポリシーの作成

スケジュール実行のために作成するIAMロールの権限をIAMポリシーで作成します。

:::note info
すでにEC2インスタンス停止権限を含むポリシーが作成済みの場合は不要です。
:::

**1-1.** IAM > ポリシーで「ポリシーを作成」を押下します。
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/1166959/3da1522c-e242-34cc-c501-9a6db3791e6d.png)

**1-2.** 「JSON」タブを選択し、EC2インスタンスを停止する権限を指定します。
以下の例では、[EC2: タグに基づくインスタンスの開始または停止](https://docs.aws.amazon.com/ja_jp/IAM/latest/UserGuide/reference_policies_examples_ec2-start-stop-tags.html)のベストプラクティスにしたがっています。

- ポリシーを使用できるのは、タグで`Type:Qiita`が付いているプリンシパルのみに制限
- ポリシーで指定した実行権限は、タグで`CanEventBridgeStop:true`が付いているリソースのみに制限

※ここでいうプリンシパルは、後ほど作成するIAMロールです。

:::note warn
**{account-id}** はAWSアカウントIDです。
:::

```json
{
    "Version": "2012-10-17",
    "Statement": [
        {
            "Sid": "StopIfTags",
            "Effect": "Allow",
            "Action": [
                "ec2:StopInstances"
            ],
            "Resource": "arn:aws:ec2:ap-northeast-1:{account-id}:instance/*",
            "Condition": {
                "StringEquals": {
                    "aws:ResourceTag/CanEventBridgeStop": "true",
                    "aws:PrincipalTag/Type": "Qiita"
                }
            }
        }
    ]
}
```

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/1166959/a6cf0062-4df8-d0bc-8030-77f78d85ac1c.png)

**1-3.** 任意でタグを追加します。
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/1166959/4c9f0340-3d34-48c9-d65c-05b4b5c7af44.png)

**1-4.** 名前を入力し、内容を確認して「ポリシーの作成」を押下します。
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/1166959/d08e0b8f-d455-9343-6563-b408fcce3976.png)
これでポリシーの作成は完了です。

## 2. IAMロールの作成

:::note info
すでにEC2インスタンス停止権限を含むポリシーがアタッチされたロールを作成済みの場合は不要です。
:::

EventBridgeがEC2インスタンスを停止できるようにIAMロールを作成します。

**2-1.** IAM > ロールで「ロールを作成」を押下します。
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/1166959/b420d6f0-a41d-f376-4370-b0a83d703490.png)

**2-2.** カスタム信頼ポリシーを選択します。
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/1166959/dd3e2675-813e-11b6-dad4-9f4237933432.png)

**2-3.** カスタム信頼ポリシーのJSONを設定します。
サービスで`scheduler.amazonaws.com`を指定すると、EventBridge Schedulerがこのロールを使用できるようになります。

```json
{
    "Version": "2012-10-17",
    "Statement": [
        {
            "Effect": "Allow",
            "Principal": {
                "Service": "scheduler.amazonaws.com"
            },
            "Action": "sts:AssumeRole"
        }
    ]
}
```

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/1166959/2587118c-425a-047f-50ec-6f1138db8a9f.png)

**2-4.** 許可ポリシーで先ほど作成したポリシーを選択します。
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/1166959/c5687f25-0793-20c0-9ef5-a2ee224d08a1.png)

**2-5.** 名前を入力します。
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/1166959/624e4fb6-0c3d-91b5-5dcc-00039c96e834.png)

タグはポリシーのプリンシパルタグで指定したタグを追加します。例では、`Type:Qiita`です。
内容を確認して「ポリシーの作成」を押下します。
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/1166959/50996fb7-770a-36c7-43bc-9ff38d8ae6f3.png)
これでロールの作成は完了です。

## 3. EventBridgeスケジュールグループの作成

スケジュールをグルーピングするための機能である、EventBridgeスケジュールグループを作成します。

:::note info
EventBridgeスケジュールグループに最初から存在する`default`を使う場合は不要です。
:::

**3-1.** EventBridge > Schedule group(スケジュールグループ)を押下します。
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/1166959/d1ff41b9-777b-5aa1-375f-434d1f1acd73.png)

**3-2.** 「スケジュールグループを作成」を押下します。
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/1166959/e7779403-189c-9166-7901-d9c9ae86ac0b.png)

**3-3.** 名前を入力します。必要であればタグを追加します。
「スケジュールグループを作成」を押下します。
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/1166959/4c137ae8-87ed-bad6-c7ce-ab33d2a29e3b.png)

**3-4.** 正常に作成されたことを確認します。
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/1166959/b086e427-dec2-4513-b71b-47a05efcc489.png)
スケジュールグループの作成は完了です。

## 4. EventBridgeスケジュールの作成

EventBridgeスケジュールを作成します。
今回はEC2インスタンスの停止を設定します。

**4-1.** EventBridge > Schedules(スケジュール)で「スケジュールを作成」を押下します。
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/1166959/dc9b4076-a959-3ce4-86a6-65b101bb4b17.png)

**4-2.** スケジュール名を入力します。説明は任意です。
[3. EventBridgeスケジュールグループの作成](#3-EventBridgeスケジュールグループの作成)で作成したスケジュールグループを選択します。作成していない場合は、defaultを選択します。
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/1166959/2a808b8f-a6e8-6eaa-e1dc-cb8c436837cd.png)

頻度は「定期的なスケジュール」を選択します。
スケジュールの種類は「cronベースのスケジュール」を選択します。[cronベースのスケジュールのルール](https://docs.aws.amazon.com/ja_jp/scheduler/latest/UserGuide/schedule-types.html?icmpid=docs_console_unmapped#cron-based)に従ってcronを入力します。
フレックスタイムウィンドウ[^1]は「オフ」を選択します。
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/1166959/e6377f3c-4a19-2555-5361-46dc49ba62a7.png)

タイムゾーンは「(UTC +09:00) Asia/Tokyo」を選択します。
「開始日時」と「終了日時」は任意です。スケジュールの有効期間を指定できます。指定しない場合は期間に関係なく実行されます。
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/1166959/a939bd3f-15e8-41bb-e25c-babd8131232f.png)

**4-3.** ターゲットの選択で実行したいAPIを選択します。
今回はEC2インスタンスの起動・停止なので、「すべてのAPI」を選択し、「ec2」で検索します。
検索結果の「Amazon EC2」を押下します。
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/1166959/78482dad-06d8-154a-99b8-5330a96cdafc.png)

A. 起動：`starti`で検索し、「StartInstances」を選択します。
B. 停止：`stop`で検索し、「StopInstances」を選択します。
以下はB. 停止の例です。
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/1166959/aa63aa08-d744-a9cd-1933-a62fa8811959.png)

入力に対象のEC2インスタンスのインスタンスIDを指定します。
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/1166959/dc84c582-46ad-7dd4-8376-b66eee31bee9.png)

**4-4.** 「有効化」をオンにし、「再試行」はオフにします。デットレターキューは「なし」を選択します。
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/1166959/39cc1458-cbbe-fdf1-9223-1e463611cae3.png)

「既存のロールを使用」を選択し、[2. IAMロールの作成](#2-IAMロールの作成)で作成したロールを選択します。
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/1166959/c6478b27-40f3-06af-0b88-753d53e8ab62.png)

**4-5.** 設定内容を確認し、「スケジュールを作成」を押下します。
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/1166959/89da369e-5552-9498-0f93-7d7aa1df2233.png)
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/1166959/57264c20-ca0b-375d-6d73-350f2790daeb.png)
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/1166959/d3137416-ecea-b410-4a72-ff421e218867.png)

スケジュールの作成は完了です。

# 動作確認

[1. IAMポリシーの作成](1-IAMポリシーの作成)でポリシーの条件に指定したリソースタグ`Type:Qiita`が指定したEC2インスタンスについていいれば、スケジュール通りに起動/停止します。

# おわりに

Lambdaのコードを書かなくていいのは、難易度面でも管理面でも嬉しいですね！
かなりの数のAPIに対応しているようなので、工夫次第でまだまだ便利な使い方ができるかもしれません。

# 参考

[Amazon EventBridge SchedulerでEC2定期停止処理を簡単に実装する](https://tech.nri-net.com/entry/easy_implementation_with_eventbridge_scheduler)
[EC2: タグに基づくインスタンスの開始または停止](https://docs.aws.amazon.com/ja_jp/IAM/latest/UserGuide/reference_policies_examples_ec2-start-stop-tags.html)

[^1]: 実行タイミングに時間幅を持たせる場合は「オン」に設定します。