【AWS】今日から使える！StepFunctionsで環境全起動！

## 皆さんはこう考えたことはありませんか？
- 使わない間AWSのリソースを停止してる
    - １個ずつ起動するの面倒。。。
    - **ボタン一つで指定したリソース起動できたらなぁ〜**

## それ、 StepFunctions で実現できます:thumbsup:
そんなあなたに！ AWSの StepFunctions！
AWSのAPIを使ったワークフローで簡単に指定したリソースを起動することができます！

## 前提1
今回の前提として下記のリソースを起動します

|リソース種別|台数|備考|
|:---:|:---:|:---:|
|RDSインスタンス|1||
|Auroraクラスタ|1||
|EC2|5||
|EC2 AutoScaling Group|1|ASGの個数は2つ|

## 前提2
下記のポリシーをアタッチしたIAMロールを作成し、StepFunctionsステートマシンに割り当てていること。
```json
{
    "Version": "2012-10-17",
    "Statement": [
        {
            "Sid": "VisualEditor0",
            "Effect": "Allow",
            "Action": [
                "rds:DescribeDBInstances",
                "rds:DescribeDBClusters",
                "rds:StartDBCluster",
                "rds:StartDBInstance",
                "ec2:DescribeInstanceStatus",
                "ec2:DescribeInstances",
                "ec2:StartInstances",
                "autoscaling:DescribeAutoScalingGroups",
                "autoscaling:ExitStandby",
                "autoscaling:UpdateAutoScalingGroup"
            ],
            "Resource": "*"
        }
    ]
}
```

## 全体の構成
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/396559/1fc7cc11-5222-788c-8e52-66023778ba33.png)

流れとしてはこうなっています。
1. DBクラスタの状態を取得
1. 停止している場合起動
1. 起動完了したらDBインスタンスの状態を取得
1. 停止している場合起動
1. 起動完了したらEC2インスタンスの状態を取得
1. 停止している場合5台全て起動
1. 起動完了したらAutoScaling Groupのキャパシティを取得
1. 0の場合1に変更しキャパシティを増やす

上記画像のように上から下に流れる形で順序立てて起動させることができます。
では実際に細かく説明していきます

## DBクラスタの起動
最初にAuroraのクラスタを起動させていきます

### DBクラスタの状態取得
まず左のメニューから「Describe DBClusters」を検索し、配置します

![スクリーンショット 2023-12-07 18.12.10.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/396559/61339fde-a3d1-3f39-2bce-844a68a91caf.png)

配置したら右のメニューに以下を入力します。

![スクリーンショット 2023-12-07 18.15.38.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/396559/cac6d153-5b66-060a-fec6-9bd4d841e961.png)

```json
{
  "DbClusterIdentifier": "kensyo-aurora"
}
```
これでDBクラスタ名を使ってDBクラスタの状態を取得することができます（Stopped or Available)

次に状態を取得したらその情報を次のフローへ出力するように設定します。
出力タブを開き以下のように設定します。

![スクリーンショット 2023-12-07 18.19.17.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/396559/4c9aadc4-f62f-aa8f-430a-f302330e17de.png)

```json
{
  "DbClusterStatus.$": "$.DbClusters[0].Status"
}
```
### 状態による分岐
ここからはクラスタの状態によって動きを分岐させていきます。
左のメニューのフローから「Choice」を選択して配置します。

![スクリーンショット 2023-12-07 18.22.42.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/396559/17e7eeff-a96f-2c17-f194-ebedc732a2cd.png)

![スクリーンショット 2023-12-07 18.23.46.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/396559/8947e43b-44b5-85ee-3a8c-0810727c0167.png)

では、まずRule1を編集していきます。
鉛筆マークを押して、AddConditionsをクリック

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/396559/8b2261f2-690d-5418-1683-0a718fc654c9.png)


ここで、先程DescribeDBClusterから出力をした、「$.DbClusters[0].Status」の中身を使って分岐をしていきます。
以下のように設定してまずは停止だった場合の条件にします。
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/396559/90ba53c1-1172-18d5-6368-85c36d2bd6fa.png)

では次にAdd New Choice Ruleをクリックし逆に起動していた場合の条件も入力します。
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/396559/43be0a5e-9048-6185-101b-8d7a678ab58e.png)

指定する状態として実際にaws cliで確認したところ以下で返ってきたため、こんな感じで指定しています。
停止している場合: Stopped
起動完了している場合 : available

Ruleが増えたのでこの様になっているかと思います
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/396559/11cec07a-fbe9-0970-7411-83d906f15f08.png)

分岐させる場合、このように各Ruleの下に次に行いたいアクションを配置していく形になります。

### DBクラスタの起動
ではまず、DBクラスタを起動させる動きを入れていきましょう！

左メニューから「StartDBCluster」を検索して stopped の下に配置します。

![スクリーンショット 2023-12-07 18.34.28.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/396559/b081aa14-4837-2fee-ca4b-bef0d4ee65b6.png)
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/396559/d573d7ca-2e28-efdb-bba3-5765b132c8b6.png)

次に、DBクラスタの起動は時間がかかるため、その間の待機をさせるためにフローからWaitを配置します
（スクリーンショットが取れなかったですが、ハイライトが出ます）

![スクリーンショット 2023-12-07 18.37.49.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/396559/48b8680c-2cff-721d-c988-e6696c5631eb.png)
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/396559/ab461e3e-0986-c49e-ba0e-e035e8370b61.png)

無事に配置ができたら StartDBCluster にクラスタ名を指定します。
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/396559/9e2e8e59-a304-db8b-715d-7bc5fee71010.png)

### ループの設定
次にWaitの設定を行います。
今回は２分ずつ待つことにします。

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/396559/d87d67c1-31c7-bd96-c39c-b7b39d510662.png)

Waitでやりたいことは
- 起動完了まで状態確認を繰り返す
- 起動中も繰り返したい

上記を実現するため細工をしていきます。
まず、Waitの次の状態を Describe DBClustersへ
次に、ChoiceのDefault ruleの次の状態をWaitにします。
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/396559/65a9a4c8-19b6-d877-3f51-181100890575.png)

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/396559/1c44a9a8-e3a4-7cab-ff03-4c3300c8e269.png)

そうするとこの状態になったと思います。
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/396559/180f7ae0-5948-7b71-3b58-a791dc2bb539.png)

ぐちゃぐちゃですが、
起動の動作が終わったあと２分待って、状態を取りに行きます。
そして、その状態が stopped でも available でもない場合、また２分待って状態を取得する
以上を繰り返して、 availableが取れたときに次の動作に移ります。

これだと時間がかかってしまいますのでフローの中のParallelを使ったほうがもっと効率よくできますが、今回は初めてだったためこの方法で実装してみました。

## DBインスタンスの起動
クラスタのときとほぼ変わらないので割愛しますが、パラメータが多少違うため記載します。
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/396559/2141ba04-7a5b-ecda-05b0-8014370ef601.png)

### 状態の取得
同じ流れで設置、設定していきます。
![スクリーンショット 2023-12-07 18.37.49.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/396559/e002f067-1429-ffbf-bce8-e34893a9e451.png)

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/396559/a7b80c26-f308-9a48-3890-6ce8795fe2a9.png)

```json
{
  "DbInstanceIdentifier": "RDS-kensyo"
}
```

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/396559/f3743571-79e5-3aba-dd74-b606b88cf241.png)

```json
{
  "DbInstanceStatus.$": "$.DbInstances[0].DbInstanceStatus"
}
```

### 分岐
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/396559/d893db7f-ebc2-edd4-57a3-f8159c1658b4.png)

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/396559/e612a4a5-5a57-3a2d-54ce-e74899144d14.png)

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/396559/61b1e4c7-26ee-fe16-5a56-b673d07909e0.png)

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/396559/8b634b6e-b650-0ea0-fbca-cb2352a2932e.png)

### DBインスタンスの起動

![スクリーンショット 2023-12-07 18.57.33.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/396559/8ec06fbe-31b3-d70f-35ac-8a5e5bdb34fb.png)

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/396559/d8615e27-12ae-2d79-3d06-218e0abcf6d2.png)

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/396559/09aefaa7-37a1-275a-ee8a-56d95c3f1b07.png)

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/396559/5dea34b5-917b-1348-f773-3fbaab8ce8b7.png)

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/396559/510dc066-86c3-1c55-b56c-0df5bfac8a98.png)

### ループの設定
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/396559/d9fd4085-360c-945d-3de1-308b9ced7840.png)

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/396559/ca6759dd-3c76-297e-6f22-002063eb8c46.png)

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/396559/2141ba04-7a5b-ecda-05b0-8014370ef601.png)

## EC2インスタンスの起動
EC2の起動も同じような形で配置していきます。
今回対象のインスタンスは5台となっています。
5台の状態を取得し、起動します。

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/396559/b648d169-c045-1934-4a24-b2769cc2259b.png)

### 状態の取得
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/396559/68e09ef6-6422-12c4-eba2-3964f4414d10.png)

```json
# APIパラメータ
{
  "Filters": [
    {
      "Name": "tag:Name",
      "Values": [
        "aaa",
        "test",
        "dev",
        "kensyo",
        "prod"
      ]
    },
    {
      "Name": "instance-state-name",
      "Values": [
        "stopped"
      ]
    }
  ]
}
```

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/396559/0b92ae7e-f85a-2efd-8f46-0442395fda07.png)

```json
{
  "StoppedInstanceCount.$": "States.ArrayLength($.Reservations)",
  "StopInstanceIds.$": "$.Reservations[*].Instances[0].InstanceId"
}
```

#### 出力に関して
```"States.ArrayLength($.Reservations)",``` の部分では、インスタンスの台数を出力しています。
APIパラメータで指定した、
```
      "Name": "instance-state-name",
      "Values": [
        "stopped"
```
上記の部分で、stoppedのインスタンス情報が取れているため、その配列のlengthを出力しています。

```"$.Reservations[*].Instances[0].InstanceId"```の部分では、停止しているインスタンスIDを出力しています。

### 状態での分岐
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/396559/50351f56-7fcd-5dfd-80e7-b4e39810ecea.png)

#### 条件に関して
今回インスタンスが5台という条件(状態を取得するインスタンスが5台)ですので、
「5台停止していたら起動し、停止しているインスタンスが0台になったら次のフローに移る」　動きにしています。
これに関してはもっと良いやり方があると思いますが今回はこの条件で実装していきます。

### EC2インスタンスの起動
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/396559/fbc67ea0-f577-a6cb-c575-cdf18bbe6caa.png)

```json
{
  "InstanceIds.$": "$.StagingStopInstanceIds"
}
```
実は、インスタンスの状態取得時に出力したインスタンスIDの配列はChoiceを通して取得することができます。
よって、InstanceIdsにその配列をそのまま指定しています。
これで5台一気に起動することができます。

### Wait
Waitも同じように設定し、ループをさせます。

## AutoScalingGroup(ASG)のキャパシティ変更
２つのAutoScalingGroupを対象にキャパシティ変更による、インスタンスの起動を実装していきます。
初期状態は、

- 希望するキャパシティ : 0
- 最小キャパシティ : 0
- 最大キャパシティ : 1

とします。

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/396559/55161b3b-032a-790f-1aa8-d03b7623600d.png)

### 状態の取得
まずは対象のASGの状態を取得し、出力します。
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/396559/b66c32d0-061b-b4ae-68c5-c6ed9ad70546.png)

```json
{
  "AutoScalingGroupNames": [
    "kensyo",
    "kensyo2"
  ]
}
```

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/396559/c1a21231-5f89-c3ac-22b6-6f86c18b7930.png)

```json
{
  "StagingInstanceId.$": "$.AutoScalingGroups[0].Instances[0]",
  "StagingInstanceId2.$": "$.AutoScalingGroups[1].Instances[0]"
}
```
もっといい方法がありそうですが、配列の添字を入力しそれぞれ取得します。

### 状態での分岐
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/396559/6aab3fc2-1b13-bdee-681c-4c55e19dfe9c.png)

Rule1には、条件として、初期状態の希望するキャパシティと最小キャパシティが０の場合、配列が Null であるため、
Nullの条件を指定してあげる必要があります。
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/396559/6c1a7a87-2204-ccb3-3b44-032335396fdd.png)

Rule2は、```$.StagingInstanceId.LifecycleState```と```$.StagingInstanceId2.LifecycleState```の値が "InService" となったら次のフローに移ります

### AutoScalingGroupのキャパシティ変更
2つのASGを一度に変更することが難しかったため、２つのフローに分けて実装します。
最小キャパシティと希望するキャパシティを１にしてインスタンスを起動させます。

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/396559/11637684-fa0e-01ec-9d91-b22f9a0c8f5a.png)

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/396559/896e7269-e50f-12d6-06b1-a8ca0e362606.png)

```json
# 1つ目

{
  "AutoScalingGroupName": "kensyo",
  "MinSize": 1,
  "DesiredCapacity": 1
}

# 2つ目

{
  "AutoScalingGroupName": "kensyo2",
  "MinSize": 1,
  "DesiredCapacity": 1
}
```

### Wait
同じように配置し、ループさせます。

## 終わり方
今回は、ASGの更新で処理を終わらせたいため、InServiceの条件の下にフローからpassを配置して、そのままENDまで流れるようにしています。

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/396559/ec4fcd56-6e7d-a667-e864-5a4990b2026c.png)

## 実行
ここまでできたら、右上の実行を押して、実行するだけです！
実行を押すと、下記の画面が出ますが、何も入力せずそのままでOKです！

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/396559/292a923f-643b-ba75-c1ea-413ac6174424.png)

## 作ってみて
ピタゴラスイッチのような感覚で、APIアクセスを使用してAWSリソースを操作できるため、起動だけでなくその逆の停止や、情報の書き換えなど、
EventBridgeなどと組み合わせると日時指定での実行も可能なため更に幅広い操作が可能だと思いました。
GUI形式で簡単に配置できるため、わかりやすく作成することができました！
今回のような内容のときは積極的に使っていきたいですね！

## 最後に
若干ごちゃごちゃとした内容になってはしまいましたが、どなたかの参考になれば幸いです。
みなさんも良いStepFunctionsライフを:thumbsup: