【Aurora】【RDS】停止しても7日後に勝手に起動するやつを、最小リソースで解決してみた

停止したAuroraが7日後に起動したら、自動的に止める機能をお手軽に作る

# TL;DR 

* RDSの管理操作にはEVENT IDとというものがある
* これはEventBridgeで拾えるので、そこからRDSの停止処理をするリソースにつなげる
* 停止処理はそれぞれよしなに。自分はAutomationを使いました。
* [よくわからん。。とりあえず実現だけしたい！という方はこちらへ](#よくわからんとりあえず実現だけしたいという方へ)

# 前置き

* 50や100を超えるAuroraを管理する手法を検討しています
* 1,2個しかない場合はほかの解決方法の方が楽かもしれません。

# RDSの停止は7日で起動してしまう

AWS側でのメンテナンスの実施など様々な理由がありますが、停止したつもりがいつの間にか起動し、請求が。。。

みたいなことはRDSで開発した人はみな経験があるのではないでしょうか。




# AWSの記事

AWSもわかっているので、いくつか回答を用意しています。

https://aws.amazon.com/jp/premiumsupport/knowledge-center/rds-stop-seven-days/

* Lambdaの作成がが必要
* **スケジュールでの停止しかできない**
  * 環境によって停止時間が違うので一律スケジュールはできない

こちらは2021の記事。

https://aws.amazon.com/jp/blogs/architecture/field-notes-stopping-an-automatically-started-database-instance-with-amazon-rds/ 

* 作成するリソースが多い
  * イベントサブスクリプション/SNS/Stepfunction/Lambda * 3
* AWSアカウントは複数アカウントで存在しており、すべてのアカウントでこのリソース作成と管理をしたくはない
* ここまでしてやりたいことでもない。

でもこの記事を見ると、RDSから自動起動に対してイベントが発行されていることがわかります

# EventBridgeの活用

イベントといえば、、そうEventBridgeです

イベントが出ているならEventBridgeで拾えるやろ！ということで、やってみたらできました。

https://docs.aws.amazon.com/ja_jp/AmazonRDS/latest/AuroraUserGuide/USER_Events.Messages.html#USER_Events.Messages.cluster

このページからClusterの自動起動に関しては↓のように書かれてます

```
通知

RDS-EVENT-0153	
停止中の最大許容時間を超えたため、DB クラスターがスタートされています。
```

そして実際のEventを見てみるとこんな感じ

```json
{
  "version": "0",
  "id": "XXXXXXX-XXXX-XXXX-XXXX-XXXXXXXXX",
  "detail-type": "RDS DB Cluster Event",
  "source": "aws.rds",
  "account": "XXXXXXXXXXX",
  "time": "2022-12-06T13:00:16Z",
  "region": "ap-northeast-1",
  "resources": [
    "arn:aws:rds:ap-northeast-1:XXXXXXX:cluster:XXXXXXXX"
  ],
  "detail": {
    "EventCategories": [
      "notification"
    ],
    "SourceType": "CLUSTER",
    "SourceArn": "arn:aws:rds:ap-northeast-1:XXXXXXXX:cluster:XXXXXXXXXX",
    "Date": "2022-12-06T13:00:16.580Z",
    "Message": "DB cluster is being started due to it exceeding the maximum allowed time being stopped.",
    "SourceIdentifier": "XXXXXX",
    "EventID": "RDS-EVENT-0153"
  }
}
```

なのでEventBridgeのルールとしては以下になります。


```json
{
  "source": ["aws.rds"],
  "detail-type": ["RDS DB Cluster Event"],
  "detail": {
  	"EventID": ["RDS-EVENT-0153"]
  }
}
```

Auroraを停止させるためのAPIに必要な引数はこのドキュメントを見ると

https://docs.aws.amazon.com/AmazonRDS/latest/APIReference/API_StopDBCluster.html

どうやらDBClusterIdentifierがあればできそうです。

お、、DBClusterIdentifierはイベント内のSourceIdentifierなので、イベントの情報だけで停止できそうですね


# 停止方法について

Lambda使うのが一般的かもと思いますが、コードの管理が面倒なので、他の方法を考えました。

EventBridgeから呼び出せる+コードを書かずにAWSのAPIを実行できるサービスは以下になります

* SSM Automation
* StepFunctions

どちらを選んでもOKですが、複雑な分岐や別サービスとのオーケストレーションなどは必要ないのでシンプルに実装ができそうなSSM Automationでやってみました。

注意点としては、ドキュメントでは↓のように書かれていますが、イベントが発火した時点では、Clusterが起動し始めただけなので、停止前に**まずはAuroraが起動完了するのを待つ**必要があります。

この関係でAWSが用意しているAutomation Runbookである[AWS-StartStopAuroraCluster](https://ap-northeast-1.console.aws.amazon.com/systems-manager/documents/AWS-StartStopAuroraCluster/description?region=ap-northeast-1)はうまく動かないので不採用となりました。


結果としてできたRunbookがこちらです。

* ※実行にはIAM Roleの作成が必要なので、あらかじめ作成をしておいてください
  * これはEC2周りの記事ですが、参考になると思います。
  https://qiita.com/m-oka-system/items/6ca3becfac1206b2d59a


```yml
description: Stop RDS instance
schemaVersion: '0.3'
assumeRole: '{{ AutomationAssumeRole }}'
parameters:
  ClusterName:
    type: String
    description: (Required) RDS Cluster Id 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: AssertNotStopping
    action: 'aws:assertAwsResourceProperty'
    isCritical: false
    onFailure: 'step:WaitClusterAvailable'
    nextStep: CheckStop
    inputs:
      Service: rds
      Api: DescribeDBClusters
      DBClusterIdentifier: '{{ClusterName}}'
      PropertySelector: '$.DBClusters[0].Status'
      DesiredValues:
        - stopping
  - name: WaitClusterAvailable
    action: 'aws:waitForAwsResourceProperty'
    inputs:
      Service: rds
      Api: DescribeDBClusters
      DBClusterIdentifier: '{{ClusterName}}'
      PropertySelector: '$.DBClusters[0].Status'
      DesiredValues:
        - available
  - name: WaitInstanceAvailable
    action: 'aws:waitForAwsResourceProperty'
    inputs:
      Service: rds
      Api: DescribeDBInstances
      Filters:
        - Name: db-cluster-id
          Values:
            - '{{ClusterName}}'
      PropertySelector: $.DBInstances..DBInstanceStatus
      DesiredValues:
        - available
  - name: StopCluster
    action: 'aws:executeAwsApi'
    inputs:
      Service: rds
      Api: StopDBCluster
      DBClusterIdentifier: '{{ClusterName}}'
  - name: CheckStop
    action: 'aws:waitForAwsResourceProperty'
    onFailure: Abort
    maxAttempts: 10
    timeoutSeconds: 600
    inputs:
      Service: rds
      Api: DescribeDBClusters
      DBClusterIdentifier: '{{ClusterName}}'
      PropertySelector: '$.DBClusters[0].Status'
      DesiredValues:
        - stopped

```

# EventBridgeとAutomationを紐づける

Runbookもできたので、EventBridgeから実行できるようにしましょう

ポイントはInputTransfomerを活用して、イベントのSourceIdentifierをRunbookのパラメータである、ClusterNameに渡してあげることです。

また、AutomationAssumeRoleにはAutomation作成時に用意したIAM RoleのARNをわたしてあげましょう

入力パス

```json
{
  "ClusterName": "$.detail.SourceIdentifier"
}
```


入力テンプレート

```json
{
    "ClusterName": ["<ClusterName>"],
    "AutomationAssumeRole": ["SSM実行に使用できるIAM RoleのARN"]
}
```

これによって、どのAuroraClusterであっても、自動起動した際に停止することができるようになりました。

# RDS版について

RDSの場合はEVENT-IDが`RDS-EVENT-0154`になります

https://docs.aws.amazon.com/ja_jp/AmazonRDS/latest/UserGuide/USER_Events.Messages.html

```
通知

RDS-EVENT-0154	
停止中の最大許容時間を超えたため、DB インスタンスが起動されています。
```


また、停止のAPIも変わります

https://docs.aws.amazon.com/AmazonRDS/latest/APIReference/API_StopDBInstance.html


なので、それに合わせて対応してください


# 注意点

停止中は自動バックアップなども取られません。いつの間にかバックアップがなくなったなどにならないように、あらかじめSnapshotを取得しておくなどしましょう

>Aurora はまた、クラスターが停止している間に基礎となるデータを変更できないため、自動バックアップを実行できません。Aurora は、クラスターの停止中にそのバックアップ保持期間を延長しません。

https://docs.aws.amazon.com/ja_jp/AmazonRDS/latest/AuroraUserGuide/aurora-cluster-stop-start.html#aurora-cluster-stopped



# 結論

EventBridge / SSM / IAMだけで実現することができました。

AWS記事のイベントサブスクリプション/SNS/Stepfunction/Lambda * 3に比べたら、かなりコンパクトに実装できています。

もちろん信頼性などはあちらの実装の方が高いなどはあると思います。

気軽に実装したい場合などにぜひ利用してみてください

# よくわからん。。とりあえず実現だけしたい！という方へ

Cloudformationのテンプレート作ったので、これでStack作れば1発です

https://github.com/willco21/rds-stop-from-autostart/blob/main/stop-rds-cluster-from-autostart.yml

このテンプレートはWHIのAWSアカウントにもStackSetとかで展開していこうと思っています