RDSを自動で起動・停止させてコスト削減するCDKテンプレートを作成してみた

## はじめに
AWS料金を節約するために、日中しか使用しないリソースは、夜間停止してランニングコストを減らしたい、と考える人は、多いのではないかと思います。
 
ただ、業務開始した時に起動、業務終了時に停止を手動で行っていると、たまに切り忘れます。

そこで本記事では、EventBridge Scheduler+IAMロールを使用して、RDSを使用する時間帯だけ、自動で起動・停止を行うことができるCDKテンプレートを紹介します。


 ## EventBridge Scheduler+IAMロールを用いたRDSのスケジュール起動・停止
 今回テンプレート化した構成は、EventBridge Scheduler+IAMロール（構成図の赤枠）になります。 本記事で作成したテンプレートでは、毎週月曜～金曜の7:00にRDSインスタンスを起動し、19:00に停止します。
![rds-eventbridge-scdule.drawio.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/3671603/fd387c66-6bb4-ace0-dd22-41d74086045e.png)



##テンプレート化したCDKコードの紹介

cdkソース
```Eventbridge.ts
import * as cdk from 'aws-cdk-lib';
import { Construct } from 'constructs';
import { CfnSchedule, type CfnScheduleGroup } from 'aws-cdk-lib/aws-scheduler';
import {
  Effect,
  Policy,
  PolicyStatement,
  Role,
  ServicePrincipal,
} from 'aws-cdk-lib/aws-iam';
import { type DatabaseCluster } from 'aws-cdk-lib/aws-rds';

//[PARAMETER] RDS ARN
let RDS_ARN = `arn:aws:rds:${REGION}:${ACCOUNT_ID}:cluster:${rdsCluster.clusterResourceIdentifier}`;

//[PARAMETER] RDS NAME
let RDS_NAME = 'RDS Name';

//[PARAMETER] RDS 開始時間
let RDS_START_SCHEDULE = 'cron(00 07 ? * MON-FRI *)';

//[PARAMETER] RDS 停止時間
let RDS_STOP_SCHEDULE = 'cron(00 19 ? * MON-FRI *)';


export class ScheduleTestStack extends cdk.Stack {
  constructor(scope: Construct, id: string, props?: cdk.StackProps) {
    super(scope, id, props);

    const RdsSchedulerRole= new Role(this, 'role-rds-scheduler', {
      assumedBy: new ServicePrincipal('scheduler.amazonaws.com'),
      description: 'start and stop RDS',
    });
    new Policy(this, 'policy-SchedulerPolicyForRDS', {
      policyName: 'policy-rds-star-and-stop',
      roles: [RdsSchedulerRole],
      statements: [
        new PolicyStatement({
          effect: Effect.ALLOW,
          actions: ['rds:StartDBCluster', 'rds:StopDBCluster'],
            RDS_ARN
          ],
        }),
      ],
    });

    const StartRdsScheduler = new CfnSchedule(this, 'Start-Rds-Scheduler ', {
      name: 'Start-Rds-Scheduler',
      description: 'Start RDS Instance',
      flexibleTimeWindow: {
        mode: 'OFF',
      },
      scheduleExpressionTimezone: 'Asia/Tokyo',
      scheduleExpression: RDS_START_SCHEDULE,
      target: {
        arn: 'arn:aws:scheduler:::aws-sdk:rds:startDBInstance',
        roleArn: RdsSchedulerRole.roleArn,
        input: JSON.stringify({ "DbInstanceIdentifier": RDS_NAME }),//クラスタ―名を記入する
      },
    });

    const StopRdsScheduler = new CfnSchedule(this, 'Stop-Rds-Scheduler ', {
      name: 'Stop-Rds-Scheduler',//スケジュール名を記入
      description: 'Stop RDS Instance',//説明を記入
      flexibleTimeWindow: {
        mode: 'OFF',
      },
      scheduleExpressionTimezone: 'Asia/Tokyo',
      scheduleExpression: RDS_STOP_SCHEDULE,//タイミングをcronで定義する
      target: {
        arn: 'arn:aws:scheduler:::aws-sdk:rds:stopDBInstance',//クラスターをインスタンスに変えるときは変更する
        roleArn: RdsSchedulerRole.roleArn,
        input: JSON.stringify({ "DbInstanceIdentifier": RDS_NAME }),//クラスタ―名を記入する
      },
    });
  }
}


```

## パラメータ変更箇所の紹介
変更頻度が高いパラメータを、コード内で定義化し、パラメータ内容を表にまとめました。
本記事のコードを自身の環境に合わせて使用する際に、参考にしていただけると幸いです。

|変数名|値 |パラメータ解説  |
|---|---|---|
|RDS_ARN |\`arn:aws:rds:REGION:ACCOUNT_ID:cluster:rdsCluster.clusterResourceIdentifier` |RDSのリソースARN |
|RDS_NAME|'RDS Name' |対象のRDSインスタンス名 |
|RDS_START_SCHEDUL  |'cron(00 19 ? * MON-FRI *)' |（停止タイミングのcron。毎週月曜～金曜の19：00 ）|
|RDS_STOP_SCHEDULE|'cron(00 07 ? * MON-FRI *)' |起動タイミングのcron。（毎週月曜～金曜の07：00） |

## 節約の効果

平日のAM7:00～PM7:00までを稼働させた場合の稼働時間は以下の通りになります。

12時間 x 22日 = 264時間（平日の日数は22日で計算）

30日間無停止の場合は 24時間 x 30日 = 720時間 なので、
稼働時間を約37%にする（63%削減）ことができる計算です。

## まとめ
平日の日中以外の時間でRDSインスタンスを停止するだけで、無停止と比較して6割もコストが削減できるのは、正直無視できないと思いました。
1円でもコスト削減して利益を上げるなら、テストや動作検証を行うクラウド環境（例えば検証環境、開発環境）は、夜間や休日など不使用の時間帯は停止できるか、自分の身の回りにあるクラウド環境を定期的に点検したほうがよいと感じました。