【コスト削減】AWS EC2インスタンス 夜間休日自動停止方法 (1) AWS Lambda + Amazon EventBridge

# 1. はじめに
- AWS環境のコスト削減に取り組んでいる。コスト削減の一番ベーシックな対策である、EC2インスタンスの夜間休日の自動停止方法について、いくつかやり方があるようなので、それぞれ試してみて、難易度やメリット・デメリットを比較する。
- 本記事では一番昔からある方法(Lambda + EventBridge)の動作確認を行う。

# 2. やったこと
- 自動起動・停止対象とするインスタンスを1台用意する。
- 以下のスケジュール設定により、夜間休日のインスタンス自動停止を実現する。
    - インスタンスを開始するLambda関数を作成し、EventBridgeルールで月～金の9:00に実行するように設定する。
    - インスタンスを停止するLambda関数を作成し、EventBridgeルールで月～金の21:00に実行するように設定する。

# 3. 構成図

![ins構成図1.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/189302/513f3727-a000-0770-bfeb-9529c9d922cd.png)


# 4. 手順

## 4.1 事前準備
- 自動起動・停止の対象とするEC2インスタンスを作成する。このインスタンスのインスタンスIDを指定して自動起動・停止の操作を行う。

## 4.2 IAMポリシーの作成
- EC2インスタンスのstop/start、CloudWatchログへのログ出力のみを許可するIAMポリシー(mksamba-lambda-stopstart-policy)を作成する。(ポリシーの内容は記事末の「5.参考」のところにあるAWS公式の記事から引用）

``` mksamba-lambda-stopstart-policy.json
{
  "Version": "2012-10-17",
  "Statement": [
    {
      "Effect": "Allow",
      "Action": [
        "logs:CreateLogGroup",
        "logs:CreateLogStream",
        "logs:PutLogEvents"
      ],
      "Resource": "arn:aws:logs:*:*:*"
    },
    {
      "Effect": "Allow",
      "Action": [
        "ec2:Start*",
        "ec2:Stop*"
      ],
      "Resource": "*"
    }
  ]
}
```

## 4.3 IAMロールの作成
- 後で作成するLambda関数にアタッチするIAMロールを作成する。
- ロールの作成 -> AWSのサービス/Lambdaを選択する。


![ins01.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/189302/1c4d9f57-9e6a-3c05-3d03-f27fc2689902.png)

- 手順 4.2 で作成したIAMポリシーを選択する。

![ins02.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/189302/415c7e9f-4c9f-843e-e8b2-506e0130ef6f.png)

- ロール名を「mksamba-lambda-stopstart-role」とし、信頼されたエンティティに「lambda.amazon.aws.com」が指定されていることを確認し、ロールを作成する。

![ins03.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/189302/46d2d2be-130a-9642-2f01-797a8b664909.png)

## 4.4 Lambda関数の作成

- インスタンスを停止するLambda関数を作成する。
- 名前を「mksamba-lambda-instance-stop」とし、実行ロールとして手順 4.3 で作成したIAMロールを選択する。

![ins04.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/189302/6844d520-a6a3-2e6e-6516-868b65609d7a.png)

- コードは、AWS公式(記事末の「5.参照」のところのもの)を使用する。リージョン、インスタンスIDは自分の環境の値に変更する。

``` mksamba-lambda-instance-stop.py
import boto3
region = 'us-west-1'
instances = ['i-xxxxxxxxxxxxxxxxx']
ec2 = boto3.client('ec2', region_name=region)

def lambda_handler(event, context):
    ec2.stop_instances(InstanceIds=instances)
    print('stopped your instances: ' + str(instances))
```

- 同様に、インスタンスを開始するLambda関数を作成する（画面は省略）。
- 名前を「mksamba-lambda-instance-start」とし、実行ロールとして手順 4.3 で作成したIAMロールを選択する。
- コードは、AWS公式(記事末の「5.参照」のところのもの)を使用する。リージョン、インスタンスIDは自分の環境の値に変更する。

``` mksamba-lambda-instance-start.py
import boto3
region = 'us-west-1'
instances = ['i-xxxxxxxxxxxxxxxxx']
ec2 = boto3.client('ec2', region_name=region)

def lambda_handler(event, context):
    ec2.start_instances(InstanceIds=instances)
    print('started your instances: ' + str(instances))
```

## 4.5 EventBridge ルールの作成

- インスタンス停止を行うLambda関数を呼び出すEventBridgeルールを作成する。
- Amazon EventBridge > ルール > ルールを作成にて、ルール名「mksamba-instance-stop-lambda」とし、ルールタイプは「スケジュール」を選択し、「続行してルールを作成する」に進む。

![ins05.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/189302/54687b45-97fa-ca14-695d-b81d8f4f4ede.png)

- 月～金の21:00PMに動作するよう、cron式を設定する。今回は「0 12 ? * MON-FRI *」で設定。動作スケジュールの確認はJSTで可能だが、CRON式はUTCで入力する必要がある。

![ins06.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/189302/8ece71ec-aeeb-ff50-4f43-5c33c7fa7d1c.png)

- 呼び出すターゲットとして、インスタンスを停止するLambda関数「mksamba-lambda-instance-stop」を指定する。


![ins07.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/189302/4a64be35-196c-be87-c0c1-0658b2b2d061.png)

- 同様に、インスタンス開始を行うLambda関数を呼び出すEventBridgeルール「mksamba-instance-start-lambda」を作成する（画面は省略）。開始は月～金の9:00AMとするため、CRON式は「0 0 ? * MON-FRI *」となる。

## 4.6 停止・起動の動作確認

- 検証用に、00:00AMに起動、00:05AMに停止するようにEventBridgeの時刻設定を変更する。
- Lambdaの実行ログ(CloudWatch Logs)は以下のようになる。(00:00に開始、00:05に停止)

![ins08.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/189302/4181609f-ff12-c1ee-95d6-f1dfc1b96b41.png)
![ins09.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/189302/0f250abf-27b7-9e53-36b6-1516dd2bd6bd.png)

- CloudTrailのログは以下のようになる。

![ins10.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/189302/348e57b3-7b0f-f01b-388d-5e221e69891e.png)



# 5. 参考
- [Lambda を使用して、Amazon EC2 インスタンスを一定の間隔で停止および起動するにはどうすればよいですか?](https://repost.aws/ja/knowledge-center/start-stop-lambda-eventbridge)
    - AWS公式(re:Post)による手順解説。
- [Lambdaを使って、EC2インスタンスを任意の時間で停止・起動してみる](https://cloud5.jp/saitou-lambda-ec2-stopstart/)
    - 検証環境のVPCの作成から手順がある、非常に詳細な記事。

# 6. 所感
- まずは昔からある、自動停止/起動のベーシックな方法を再確認した。シンプルな要件(特定の数台程度のインスタンスを自動停止/起動したい)レベルであれば、これで十分と感じた。引き続きその他の方法との比較を行っていきたい。