cronやEventBridge Schedulerとは別の方法で休日祝日のカレンダーに応じたEC2の起動/停止をやってみた

## はじめに
AWSなどのクラウドを利用する際、リソースを必要な時だけ使いたいといった要望があるかと思います。例えば、EC2を使い社内システムを運用している場合、EC2を会社の営業日にあわせて起動/停止したいというケースはありませんか？
定期実行であればcronやAmazon EventBridge Schedulerの使用が考えられます。この場合、規則的な繰り返しは簡単に設定できますが、祝日や会社の休日に配慮した例外的な対応を考慮すると、定義の作成に工夫が必要です（※）。
※例えばAWS Step FunctionsとAWS Systems Manager Change Calendarを連携する方法がありますが、ジョブを“実行する”ためのカレンダーと“実行しない”ためのカレンダーの作成や、ワークフローの設計が必要になります。
[[AWS Step Functions] AWS Systems Manager Change Calendarと連携して定期実行処理のイレギュラーケースに対応してみた | DevelopersIO (classmethod.jp)](https://dev.classmethod.jp/articles/linking-aws-step-functions-and-aws-systems-manager-change-calendar-to-handle-irregularities-in-periodic-execution-processes/)

クラウド型ジョブスケジューラーサービスを使うと、GUIから簡単にカレンダーを作成し、業務の実行予定に合わせてスケジューリングすることができます。
スケジュールにしたがってAmazon EventBridgeにイベントを送信することで、クラウド上の業務アプリケーションなどの自動実行が可能になります。
<img width="600" alt="QiitaPic1_gaiyou.png" src="https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/3889837/9bc25efd-d396-6e5e-b88a-83c5952603b4.png">
実際に、以下のケースを試してみました。
\- EC2を毎日10時に起動、17時に停止する。
\- 週末（土日）や、祝日、年末年始などの長期休みは、利用しない（起動しない）。
<img width="300" alt="QiitaPic2_case.png" src="https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/3889837/ea82e399-164f-c67a-2fd7-03b1301e276e.png">

## やること
クラウド型ジョブスケジューラーサービスでやること
- カレンダーの作成
- イベント送信先の作成
- ジョブの作成とスケジューリング

AWSでやること
- Amazon EventBridgeの設定

## カレンダーの作成
まず始めに、クラウド型ジョブスケジューラーサービスにサインインして、祝日や会社の休日を反映したカレンダーを設定していきます。カレンダーは[カレンダー作成]画面から作成します。
休業日は、チェックボックスによる曜日や日本の祝日の一括設定や、日付クリックによる個別設定が可能です。サンプルでは、土日や、日本の祝日、年末年始などの長期休み（12/30～1/3）を休業日に設定します。
<img width="700" alt="QiitaPic3_Calendar.png" src="https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/3889837/cd0ef5ee-5c3c-5a8d-d44d-9bb9e7b5d12f.png">

## スケジューリングと実行
作成したカレンダーを使い、業務の実行予定に合わせてスケジューリングします。
具体的には、クラウド型ジョブスケジューラーサービスでは「イベント送信先」と「ジョブ」の作成、AWSではEventBridgeの設定をします。
### イベント送信先の作成
使用中のAWS環境をクラウド型ジョブスケジューラーサービスと連携するため、イベント送信先を設定していきます。イベント送信先は[イベント送信先作成]画面から作成します。
作成にはアカウントIDとリージョン情報が必要です。サンプルでは、イベント送信先としてEC2eventを作成します。
<img width="600" alt="QiitaPic4_ETarget.png" src="https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/3889837/af5d23b7-e559-1254-0ced-649db1eb836f.png">

### Amazon EventBridgeの設定
AWSコンソールにサインインして、EC2の起動/停止をするために、作成したイベント送信先（EC2event）をアクティブ化しイベントバスとルールを設定していきます。
1. パートナーイベントソースのページを開き、作成したパートナーイベントソースを選択する
    <img width="600" alt="QiitaPic5_EB1.png" src="https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/3889837/b6612c30-2970-05f8-f0f7-e99d2dd846ac.png">
1. イベントバスとの関連付けをする
    <img width="600" alt="QiitaPic6_EB2.png" src="https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/3889837/0357e482-b24e-1485-941d-4552c6c93a67.png">
    <img width="600" alt="QiitaPic7_EB3.png" src="https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/3889837/112aea85-04e3-0e60-2a40-75621aa91250.png">
パートナーイベントソースがイベントバスに関連付けされ、アクティブになりました。
    <img width="600" alt="フQiitaPic8_EB4.png" src="https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/3889837/869fa5d9-f2c6-e0c2-df8f-94e68cc28c48.png">
1. ルールのページを開き、［イベントバス］に関連付けたイベントバスを選択し、ルールを作成する
    <img width="600" alt="QiitaPic9_EB5.png" src="https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/3889837/46a070d0-fb72-1a1c-c663-889d33060750.png">
1. ルールを設定する
サンプルでは、EC2の起動/停止をするため、ルールを2件作成します。ルールでは以下の項目を設定します。
- イベントバス：関連付けたイベントバスを選択する
1件目（起動）の設定値：aws.partner/hitachi-solutions.co.jp/JobSaaS/customer-test.EC2event
2件目（停止）の設定値：aws.partner/hitachi-solutions.co.jp/JobSaaS/customer-test.EC2event
        <img width="600" alt="QiitaPic10_EB6.png" src="https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/3889837/bb587646-c5ac-ce4f-25d0-9e566767baf8.png">

- イベントパターンの定義："source"と"jobName"に、イベントバスとジョブ名を入力する。ジョブ名は、後ほど「ジョブ」の作成で使用する
    1件目（起動）の設定値：
    ```
        {
          "source": ["aws.partner/hitachi-solutions.co.jp/JobSaaS/customer-test.EC2event"],
          "detail-type": ["execJob"],
          "detail": {
            "jobName": ["EC2Start"]
          }
        }
    ```
    2件目（停止）の設定値：
    ```
        {	
          "source": ["aws.partner/hitachi-solutions.co.jp/JobSaaS/customer-test.EC2event"],
          "detail-type": ["execJob"],
          "detail": {
            "jobName": ["EC2Stop"]
          }
        }
    ```
    <img width="600" alt="QiitaPic11_EB7.png" src="https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/3889837/ce46383a-f9ad-ecb0-995f-64b11710122f.png">

- ターゲット：実行対象を選択する
1件目（起動）の設定値：StartEC2（Lambda関数）※
2件目（停止）の設定値：EC2 StopInstances API 呼び出し
※EC2を起動するLambda関数の作成方法については、補足を参照してください。
    <img width="600" alt="QiitaPic12_EB8.png" src="https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/3889837/f2e034c7-d8e6-78fc-27bf-4b657cc691f7.png">
ルールを2件作成したら、Amazon EventBridgeの設定は完了です。
    <img width="600" alt="QiitaPic13_EB9.png" src="https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/3889837/c2a4481a-a218-7c12-ae07-4ade5353543b.png">

### ジョブの作成とスケジューリング
クラウド型ジョブスケジューラーサービスに戻り、EC2の起動/停止を実行するため、ジョブを2件設定していきます。ジョブは[ジョブ作成]画面から作成します。
[イベント送信先]と[参照するカレンダー]に作成済みのものを設定することで、祝日や会社の休日を考慮した、ジョブのスケジューリングと実行ができます。
    <img width="600" alt="QiitaPic14_Job1.png" src="https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/3889837/571bfb30-5e1d-d980-b827-2ae2db2e2069.png">
[ジョブの実行予定の作成]でスケジューリングの設定をします。サンプルでは、毎日10時実行で設定します。
[カレンダーの休業日とジョブの実行予定が重なった場合の動作]で[休業日は予定を実行しない]を選択することで、業務カレンダーで定めた休業日は、ジョブが実行されなくなります。
    <img width="600" alt="QiitaPic15_Job2.png" src="https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/3889837/df1957b9-2f95-6985-900d-fe554895470c.png">
[作成]をクリックするとジョブが作成されます。同様に、ジョブ名と開始時刻を変更し、EC2の停止を実行するジョブを作成します。
    <img width="600" alt="QiitaPic16_Job3.png" src="https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/3889837/9c0f5eb9-a339-e354-21a6-e96aa7eb1394.png">

### 実行結果の確認
ジョブの実行結果は、ジョブ一覧画面で確認できます。
    <img width="600" alt="QiitaPic17_Result1.png" src="https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/3889837/5e1c3e78-1299-2c52-71b6-35a9928ea870.png">
ジョブが正常終了したため、実際にAWSコンソールに戻り、EC2を確認すると、起動/停止できていました。
    <img width="600" alt="QiitaPic18_Result2.png" src="https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/3889837/583d59be-03f4-e1e6-fccb-7c50196eeb83.png">
さらに、クラウド型ジョブスケジューラーサービスでジョブをクリックし[ジョブ詳細]画面を開くと、マンスリーカレンダーで結果と予定を確認できます。正常終了の場合は、黄緑色のアイコンが表示されます。
    <img width="600" alt="QiitaPic19_Result3.png" src="https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/3889837/0acd0f16-ca71-de36-b98b-a48616dafab5.png">

## まとめ
祝日や会社の休日に配慮した例外的な対応も、クラウド型ジョブスケジューラーサービスを使うと、GUIから簡単に設定できます。
本記事では、実際に休日祝日のカレンダーに応じたEC2の起動/停止をやってみました。手順をまとめると、以下のようになります。
1. 祝日や会社の休日を反映したカレンダーを作成する
1. イベント送信先を作成し、Amazon EventBridgeの設定をする
1. ジョブを作成し、業務の実行予定に合わせてスケジューリングを設定する

## おわりに
いかがでしたでしょうか？EC2の管理について自動化する機会がありましたので、記事を作成しました。みなさんのお役に立てればと思います。

## 参考リンク
- 株式会社日立ソリューションズ
\- クラウド型ジョブスケジューラーサービス　ご紹介サイト
https://www.hitachi-solutions.co.jp/jobschedulerservice/
- Amazon Web Service公式サイト
\- Amazon EventBridge のドキュメント
https://docs.aws.amazon.com/ja_jp/eventbridge/?icmpid=docs_homepage_appintegration

#### 補足
EC2を起動するLambda関数の作成方法
以下の設定でLambda関数を作成します。
1. 設定値に以下を入力し、[関数の作成]をクリックする
    - オプション: 一から作成
    - 関数名: StartEC2
    - ランタイム: python3.12
2. 作成されたLambda（StartEC2）を開く
3. [コード]タブを開き、以下を入力(regionは環境に合わせて変更)し、[Deploy]をクリックする
    ```python
    import boto3
    import os

    region = 'ap-northeast-1'
    instances = [os.environ['INSTANCE_ID']]
    ec2 = boto3.client('ec2', region_name=region)

    def lambda_handler(event, context):
        ec2.start_instances(InstanceIds=instances)
        print('started your instances: ' + str(instances))
    ```
4. [設定]タブ-[環境変数]を開き、以下を追加する
    - キー：INSTANCE_ID
    - 値：起動対象EC2のインスタンスID
5. [設定]タブ-[アクセス権限]を開き、[ロール名]に表示されているロールをクリックし、ロール画面を開く
6. [許可を追加]をクリックし、AmazonEC2FullAccessを追加する

以上で、関数の作成は完了です。
作成されたLambda（StartEC2）を開き、[テスト]タブから、以下を入力し[テスト]を実行します。正常終了したら正しく作成できています。
- イベント名：test
- EventJSON： {"Action": "Start"}