Aurora Serverless v2のスケールアップ・スケールダウンをスケジューリングする

## Aurora Serverless v2
Aurora Serverless v2は、AWSマネージドな新しいDBインスタンスです。
Aurora Serverless v2ではインスタンスタイプではなくACU（Aurora Capacity Unit）と呼ばれる値を設定し、性能を決定します。その際、ACUの最小値と最大値を設定することができ、DBの負荷に応じてこの範囲内で自動的にスケールアップ/ダウンすることが特徴です。
詳しくは[公式リファレンス](https://docs.aws.amazon.com/ja_jp/AmazonRDS/latest/AuroraUserGuide/aurora-serverless-v2.how-it-works.html?#aurora-serverless-v2.how-it-works.capacity)をご確認ください。

このようにAurora Serverless v2は負荷に応じてスケールする機能がありますが、スケールアップする速度はその時点でのACUによって決まります。したがって、スパイクが予測できる場合、あらかじめACUをあげることができれば安心です。

2022年9月時点で、Aurora Serverless v2をスケジューリングしてスケールアップするには、Lambda関数とEventBridgeを組み合わせる必要があり、その設定手順についてまとめました。

## 構成
- RDS
Aurora Serverless v2インスタンスをもつDBクラスターは既に作成済みのものとします。
- Lambda
実行環境: python 3.9
- EventBridge

## Lambda関数を作成する

まずは、Aurora Serverless v2のACUを変更するLambda関数を作成します。pythonのboto3を使用し、以下のような関数を作成します

```lambda_function.py
import boto3

def lambda_handler(event, context):
    client = boto3.client('rds')
    client.modify_db_cluster(
        DBClusterIdentifier='database-1', #クラスターのDB識別子
        ServerlessV2ScalingConfiguration= {
            'MinCapacity': 1.0, #ACUの最小値
            'MaxCapacity': 2.0  #ACUの最大値
        },
        ApplyImmediately=True, #すぐに変更を適用
    )
```

`modify_db_cluster()`で既存のDBクラスターの設定を変更します。

https://boto3.amazonaws.com/v1/documentation/api/latest/reference/services/rds.html#RDS.Client.modify_db_cluster

適宜`MinCapacity`と`MaxCapacity`は変更してください。上の関数は、1.0〜2.0ACUへ変更する例です。

### IAMロールの作成
Lambda関数にAuroraを変更する権限を与える必要があるので、Lambda関数の実行ロールに以下のインラインポリシーをアタッチします。

```js
{
    "Version": "2012-10-17",
    "Statement": [
        {
            "Sid": "VisualEditor0",
            "Effect": "Allow",
            "Action": "rds:ModifyDBCluster",
            "Resource": "arn:aws:rds:ap-northeast-1:XXXXXXXXXXX:cluster:database-1" //対象のDBクラスターのARN
        }
    ]
}
```

### レイヤーの追加
しかしながら、このまま実行することはできません。
引数`ServerlessV2ScalingConfiguration` は、boto3の1.24系から導入されており、2022年9月時点でのpython3.9実行環境のboto3がv1.20だったため、使うことができませんでした。そこで、boto3のv1.24以上をレイヤーとして追加する必要があります。

ローカルで以下のコマンドを叩きboto3の最新バージョンを取得します。pip3がローカルに入ってない場合は別途インストールする必要があります。
```sh
mkdir python #レイヤーのディレクトリ名は決まっているのでpythonにしないとうまくいかない
pip3 install -t ./python boto3
```

依存関係のあるパッケージも含めてインストールされるので、まるごとzipで圧縮します。ファイル名は実行時点でのboto3のバージョン1.24.70に合わせています。
```
zip -r boto3-1.24.70.zip python
```


レイヤーの追加については、こちらの記事が非常に参考になりました。

https://dev.classmethod.jp/articles/lambda-boto3-layer/

レイヤーの追加ボタンから、さきほど作成したzipをアップロードします。
Lambda関数にこのレイヤーを追加し、再度実行し、Aurora ServerlessのACUが1.0〜2.0ACUに変更されていれば成功です。

## トリガーを作成する

次はこのLambda関数を発火させるEventBridgeを作成していきます。
Lambda関数の画面トップにある「トリガーを追加」をクリックします。
![スクリーンショット 2022-09-18 9.59.00.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/584114/cafd6522-05a8-611c-6f67-fca6b6ce0b5e.png)

EventBridgeを選択し、新規ルールの作成を選択します。
`ルール名`はわかりやすい任意の名前をつけます。ここでは`scheduler-modify-db-cluster`としました。
![スクリーンショット 2022-09-18 10.03.00.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/584114/4e1574cb-db68-b5ec-36af-7465fc3bb449.png)

`スケジュール式`でACUを変更したい日時をcron式またはrate式で指定します。
詳しくは[公式リファレンス](https://docs.aws.amazon.com/ja_jp/AmazonCloudWatch/latest/events/ScheduledEvents.html)を参照

UTC時間を指定する点には注意しましょう。

![スクリーンショット 2022-09-18 10.05.33.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/584114/1dedabe7-eb8d-ec83-aaa4-ec25534068c7.png)

これにて作成は終了です。時間になりACUが変更されていれば完成です。

## ACUをEventBridge側から渡せるようにする

Aurora Serverless v2のスケーリングをスケジュールすることができましたが、変更後のACUをコードにベタ書きしているため、例えば時間になったらスケールアップし、数時間後に元に戻したいなどには、Lambda関数を複数作成する必要がでてしまいます。
そこでACUをEventBridge側から渡せるように改良します。
まずはLambda関数を以下のように修正します。

```lambda_function.py
import boto3

def lambda_handler(event, context):
    client = boto3.client('rds')
    client.modify_db_cluster(
        DBClusterIdentifier='database-1',
        ServerlessV2ScalingConfiguration= {
            'MinCapacity': event['minCapacity'], #修正
            'MaxCapacity': event['maxCapacity']  #修正
        },
        ApplyImmediately=True,
    )
```

次に、設定タブから先ほど作成したEventBridgeを選択します。

Amazon EventBridgeのページに遷移するので、右上の「編集」をクリックします。
`ステップ2 スケジュールを定義`で、再度発火する日時を設定します。

渡すデータを設定するのは`ステップ3 ターゲットを選択`です。
`追加設定`のトグルを開き、`ターゲット入力を設定`のドロップダウンから`定数（JSONテキスト)`を選択します。
するとテキストボックスが現れるのでこちらにJSONを記載します。
このJSONがLambda関数のevent引数に渡されます。

```json
{
  "minCapacity": 0.5,
  "maxCapacity": 32.0
}
```

![スクリーンショット 2022-09-18 10.22.05.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/584114/6adc33e1-f0b4-9c8f-c2f6-61626d5092ec.png)

時刻になったら、ACUが変更されることを確認しましょう。