[AWS Step Functions] EC2とRDS(Aurora)をグループ単位かつ指定した順番に起動/停止する


## はじめに

EC2とRDS(Aurora)を、グループ単位かつ指定した順番に起動/停止する仕組みを AWS Step FunctionsとLambda(Python 3.9)で作りました。

## もう少し詳しく

作成した StepFunctions ステートマシン の詳細を説明します。
以下のように複数のEC2,RDS(Aurora)がある場合に、タグを使いをグループ化と起動順序を設定します。
タグに必要な情報を設定し、起動したいグループと命令(起動命令 or 停止命令)を指定すると、順番に従いリソースを起動or 停止します。

具体的な設定例も含め説明します。以下図のような構成でEC2,RDS(Aurora)を作成します。

<img src="https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/274270/faa1e75b-f4c2-33dd-d61a-71d21cb59aa7.png" width=340>
※図にはリソースごとのタグ情報を記載しています

各リソースにはこのようにタグを設定します。

|リソース|Nameタグ/DB識別子|Groupタグ|BootOrderタグ|Group2タグ|BootOrder2タグ|
|----|-----|-----|------|-------|-----|
|EC2|tmp1|test1|2|ec2only|1|
|EC2|tmp2|test2|2|ec2only|2|
|RDS(Aurora)|database-a|test1|1|-|-|
|RDS(Aurora)|database-b|test2|1|test2A|1|

タグ名 `Group`,`Group2`はグループの区分け用のタグです。
タグ名 `BootOrder`,`BootOrder2`は起動順番を設定するタグです。

作成した StepFunctions ステートマシンは、実行する際にグループ分けのタグと起動順番のタグを指定することができます。これにより、1つのリソースに、グループ分けと起動順番のタグを複数することが可能にしました。

### グループ `test1` をすぐに起動する場合

グループ `test1` に所属するEC2とRDS(Aurora)を起動します。

<img src="https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/274270/609cca07-6ef4-01b3-34e4-79ea8411eb70.png" width=340>

StepFunctions実行時の `実行入力` は ↓ です。

```json
{
  "EXEC": "start",
  "DATE": "now",
  "GroupTag": "Group",
  "GroupValue": "test1",
  "BootOrderTag": "BootOrder"
}
```

※参考※ `実行入力`とは以下図のように、作成したStep Functions ステートマシンを実行するときに設定する引数のようなもので、JSON形式で記載します。
　　　<img src="https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/274270/7e5682d4-a6f3-4286-f8d7-3da876947c45.png" width="300">


`実行入力` の各要素の意味はこちら ↓

|要素|説明|
|---|---|
|EXEC|実行命令 `start` or `stop`|
|DATE|実行日時 `YYYY-MM-DDThh:mm:ss+09:00`<BR />例 `2021-10-09T21:40:00+09:00`<BR />`now` ←即時実行の場合 |
|GroupTag|グループ分けのタグ|
|GroupValue|グループ名|
|BootOrderTag|起動順番のタグ|


起動処理は、BootOrderタグの値を昇順で処理します。RDS(Aurora)から起動を開始し、すべてのDBインスタンスが起動完了した後に、EC2が起動開始します。EC2が起動を完了するとStepFunctionsの処理が完了します。


### グループ `test2` を指定した時刻に停止する場合

グループ `test2` に所属するEC2とRDS(Aurora)を停止します。

<img src="https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/274270/d4cef777-80db-fc77-a1b1-28c8b3bd9ef6.png" width=340>

StepFunctions実行時の `実行入力` は ↓ です。

```json
{
  "EXEC": "stop",
  "DATE": "2021-10-09T21:40:00+09:00",
  "GroupTag": "Group",
  "GroupValue": "test2",
  "BootOrderTag": "BootOrder"
}
```

`DATE`に指定した日時(2021年10月9日21時40分)に命令(今回は停止命令)を実行します。
停止処理は、BootOrderタグの値を降順で処理します。EC2から停止を開始し、停止が完了した後に、RDS(Aurora)が停止を開始します。RDS(Aurora)が停止を完了するとStepFunctionsの処理が完了します。

### グループ `ec2only` をすぐに起動する場合

グループ `ec2only` に所属するEC2を停止します。

<img src="https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/274270/9c84ee54-86ab-2288-0f68-65112f4a9396.png" width=340>

StepFunctions実行時の `実行入力` は ↓ です。これまでの例ではグループ分け用のタグは `Group` でしたが今回は `Group2` を使用します。

```json
{
  "EXEC": "start",
  "DATE": "now",
  "GroupTag": "Group2",
  "GroupValue": "ec2only",
  "BootOrderTag": "BootOrder2"
}
```


### グループ `test2A` をすぐに起動する場合

グループ `test2A` に所属するRDS(Aurora)を起動します。

<img src="https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/274270/dfd152a3-8c3d-91c7-5409-53d7c3c43431.png" width=340>

StepFunctions実行時の `実行入力` は ↓ です。

```json
{
  "EXEC": "start",
  "DATE": "now",
  "GroupTag": "Group2",
  "GroupValue": "test2A",
  "BootOrderTag": "BootOrder2"
}
```



以上で使い方の説明はおわりです。

---

## StepFunctions ステートマシン の紹介

### 概要

ソースはgithubに置きました。

https://github.com/zgw426/AWS-StepFunctions_MultipleResourcesStart-StopControl

StepFunctionsのフローです。

![StepFunctions_ステートマシン](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/274270/60ae6442-c866-1b47-be3b-f20b759fd13e.png)

3種類のLambda(Python 3.9)スクリプトを使用します。

- Lambda (GetTargetResources)
    - 対象のリソース(EC2,RDS)の情報を取得し、起動(or停止)の順番に並べる
    - 起動の場合：起動順場を示すタグ(BootOrderタグ)昇順に並べ替えます
    - 停止の場合：起動順場を示すタグ(BootOrderタグ)降順に並べ替えます
- Lambda (ExecResource)
    - 実行命令(start or stop)を実行する
    - 実行結果をJSON要素 Response に登録する
- Lambda (StatusCheck)
    - 対象のリソースの状態(起動中,停止中,初期化中など)を取得する
    - 取得した状態をJSON要素 NextAction に登録する

### EC2のステータス別の判定

EC2のステータス判定は、`インスタンスの状態(InstanceStatuses)`(図赤枠)と`ステータスチェック(InstanceStatus,SystemStatus)`(図青枠)で判定します。

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/274270/ce4771c4-5822-392a-7551-1040fa76cb97.png)



#### EC2の状態判定について

EC2の状態判定について、`running`以外はインスタンスの状態(InstanceStatuses)で判定することにしました。

|InstanceStatuses|判定|
|--------|----------------|----|
|NONE|起動命令(start)→WAIT<BR />停止命令(stop)→NEXT|
|pending|WAIT|
|terminated|SKIP|
|stopping|WAIT|
|stopped|起動命令→WAIT<BR />停止命令→NEXT|
|shutting-down|WAIT|
|running|`InstanceStatus`, `SystemStatus`で判定|

インスタンスの状態(InstanceStatuses)が`running`の場合は、`ステータスチェック(InstanceStatus,SystemStatus)`で判定します。

|`InstanceStatus`--`SystemStatus`--命令|判定|備考|
|-----|------|---|
|`ok--ok--stop` の場合|WAIT|起動かつ停止命令(stop)|
|`ok--ok--start` の場合|NEXT|停止かつ起動命令(start)|
|`NONE--NONE--stop`| NEXT|停止かつ停止命令|
|`NONE--NONE--start`| WAIT|停止かつ起動命令|
|`impaired`含む|ERROR|障害発生|
|`insufficient-data`含む|WAIT|データ不足|
|`not-applicable`含む|WAIT|未適用|
|`initializing`含む|WAIT|初期化中|
|その他|WAIT||


### RDS(Aurora)の状態判定について

RDS(Aurora)には、DBクラスターとDBインスタンスがあります。DBクラスターを起動すると、DBクラスター配下のDBインスタンスも起動を開始します。指定したRDS(Aurora)の起動が完了したかの判定は、そのDBクラスター配下の全DBインスタンスの状態で判定します。

1つのDBクラスターに複数のDBインスタンスが存在する場合があるので、状態判定はそれら全てのDBインスタンスが起動した場合に起動完了と判定するようにします。

DBインスタンスごとに状態の判定は以下表のようにしました。

|DB instance status|判定|
|--------|----------|
|available|停止命令(stop)→WAIT<BR />起動命令(start)→NEXT|
|backing-up|NEXT|
|configuring-enhanced-monitoring|WAIT|
|configuring-iam-database-auth|WAIT|
|configuring-log-exports|WAIT|
|converting-to-vpc|WAIT|
|creating|WAIT|
|deleting|WAIT|
|failed|ERROR|
|inaccessible-encryption-credentials|ERROR|
|incompatible-network|ERROR|
|incompatible-option-group|ERROR|
|incompatible-parameters|ERROR|
|incompatible-restore|ERROR|
|insufficient-capacity|ERROR|
|maintenance|WAIT|
|modifying|WAIT|
|moving-to-vpc|WAIT|
|rebooting|WAIT|
|resetting-master-credentials|WAIT|
|renaming|WAIT|
|restore-error|ERROR|
|starting|WAIT|
|stopped|停止命令→NEXT<BR />起動命令→WAIT|
|stopping|WAIT|
|storage-full|ERROR|
|storage-optimization|WAIT|
|upgrading|WAIT|

全DBインスタンスの状態を1つの変数(`allRtnVal`)に連結して格納し、以下表の判定条件で状態を判定します。

|変数`allRtnVal`|判定|
|--------|----------|
|ERROR 含む|ERROR|
|WAIT 含む|WAIT|
|その他|NEXT|

## 参考

- DBインスタンスのステータス
    - [Viewing DB instance status](https://docs.aws.amazon.com/AmazonRDS/latest/UserGuide/accessing-monitoring.html#Overview.DBInstance.Status) 
- SDK(boto3) EC2
    - https://boto3.amazonaws.com/v1/documentation/api/latest/reference/services/ec2.html
- SDK(boto3) RDS
    - https://boto3.amazonaws.com/v1/documentation/api/latest/reference/services/rds.html




## さいごに

モタモタしてたらStep Functionがアップデートしてました。新機能を使って、今回作ったステートマシンをアップデートできたらまたQiitaで紹介しようと思います。

https://aws.amazon.com/jp/about-aws/whats-new/2021/09/aws-step-functions-200-aws-sdk-integration/