Lambdaで自動でEC2の起動・停止

Lambdaについて学習をしたので自身の理解・復習また文章力の向上のためアウトプットさせていただきます。

# 事前にやっておくこと
・EC2インスタンス作成しておく

# IAMロールの作成
検索で「IAM」に入り「ポリシー」>「ポリシーを作成」をクリックし上部の「JSON」を選択し以下の権限が記述されたコードを記載しました。

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

```
ポリシーの名前は任意の名前を設定し作成(1)
ポリシーが作成できたら「ロール」>「ロールを作成」をクリックし以下の設定をします。

信頼されたエンティティの種類を選択：`AWSサービス`
ユースケースの選択：`Lambda`


「Attach アクセス権限ポリシー」で(1)で作成したポリシー名を検索し選択後ロール名に任意の名前を設定し作成(2)
その後作成したロール(2)の詳細に入り「許可ポリシー」に「作成したポリシー(1)」がアタッチされていることを確認します。
＊作成した段階でアタッチされておりました。


# Lambda関数を作成
検索で「Lambda」を検索し入ります。
「関数」>「関数の作成」をクリックして以下を設定しました。


オプション：`「一から作成」`
関数名：`任意の名前(3)`
ランタイム：`「python3.8」`
アクセス権限：`「既存のロールを使用する」 ＞ 作成したロール(2)`


「関数の作成」>「作成した関数の詳細」に入り「コードタブ」でコードを記述していき「Lambda関数」を作成

「pyファイル」に以下を記述しました。

```
import boto3
import os
region = 'ap-northeast-1'
instances = [os.environ['INSTANCE_ID']]

def lambda_handler(event, context):
    ec2 = boto3.client('ec2', region_name=region)
    action = event["Action"]
    response = ec2.describe_instances(InstanceIds=instances)
    ec2_status = response['Reservations'][0]['Instances'][0]['State']['Name']
    print(instances[0] + ' instance is ' + ec2_status + ' now.')

    if action == "Start":
        ec2.start_instances(InstanceIds=instances)
        print('started your instance: ' + str(instances[0]))
    elif action == "Stop":
        ec2.stop_instances(InstanceIds=instances)
        print('stopped your instance: ' + str(instances[0]))
    else:
        print('Lamdba function could not be executed.')

```
「Deploy」をクリックし保存

# 環境変数を設定

そのままタブ箇所にある「設定」>「環境変数」>「編集」で以下を設定

キー：`「INSTANCE_ID」`
値：`「対象のインスタンスのID」`

「保存」し、Lambda関数の設定は完了しました。


# Lambda関数で起動・停止させる「ルール」を作成
ここからは作成した「Lambda関数」をいつ起動・停止するかなどを設定

検索で「Amazon EventBridge」に入り「ルール」>「ルールを作成」をクリック

#### まずは「Lambda関数を起動」ルールを作成します。
 
「cron式」については<a href="https://docs.aws.amazon.com/ja_jp/AmazonCloudWatch/latest/events/ScheduledEvents.html#CronExpressions" target="_blank">こちら</a>を参考にしてください。
＊「UTC」で設定する際は時差も計算して設定しなければなりません。
 
### ルールの詳細
 
名前：`任意の名前`
説明：`「何時に起動」かなどの分かりやすいものを記載`
イベントパターン：`スケジュール`

### スケジュールパターン
 
cron式：`起動したい時間を設定`

### ターゲットを選択
 
ターゲットタイプ：`「AWS のサービス」`
ターゲットを選択：`「Lambda関数」`
機能：`「作成したLambda関数(3)」`
入力の設定：`定数 (JSON テキスト) を選択`
「追加設定」 > 「ターゲット入力を設定」 > 「定数 (JSON テキスト)」：`「{"Action": "Start"}」`

上記を設定後に作成

 
# Lambda関数で停止させる「ルール」を作成

### ルールの詳細
 
名前：`任意の名前`
説明：`「何時に停止」かなどの分かりやすいものを記載`
イベントパターン：`スケジュール`

### スケジュールパターン
 
cron式：`停止したい時間を設定`

### ターゲットを選択
 
ターゲットタイプ：`「AWS のサービス」`
ターゲットを選択：`「Lambda関数」`
機能：`「作成したLambda関数(3)」`
入力の設定：`定数 (JSON テキスト) を選択`
「追加設定」>「ターゲット入力を設定」>「定数 (JSON テキスト)」：`「{"Action": "Stop"}」`
 
こちらで指定の時間にインスタンスの起動・停止の設定が完了です。

# 学習中につまったこと

### 指定した時間になってもインスタンスが起動しない
インスタンス起動の時間を設定したのですが、指定の時間になってもインスタンスが起動しませんでした。
 
### 起動エラーの原因特定
 
「CloudWatch」で「作成したLambda関数(3)」のログを確認
以下を表示されておりました。
 
```
[ERROR] KeyError: 'Action' Traceback (most recent call last):   File "/var/task/lambda_function.py", in lambda_handler action - event ["Action"]
```

こちらの`[ERROR] KeyError: 'Action'`を検索しました。

```
if action == "Start":
        ec2.start_instances(InstanceIds=instances)
        print('started your instance: ' + str(instances[0]))
    elif action == "Stop":
        ec2.stop_instances(InstanceIds=instances)
        print('stopped your instance: ' + str(instances[0]))
    else:
        print('Lamdba function could not be executed.')
```
「Lambda関数」の「pyファイル」に記述した上記の「action」に「{"Action": "Start"}」が渡っていなかったみたいです。
         
渡っていない原因を探してみると
Lambda関数で起動「ルール」を作成時の「追加設定」>「ターゲット入力を設定」>「定数 (JSON テキスト)」に「{"Action": "Start"}」を記載しておらずLambda関数に渡ってなかったみたいです。
         
停止の設定の方にも「{"Action": "Stop"}」を記載にエラーは解決しました。
         
# さいごに

「自動でEC2の起動・停止」ができると提供しているサービスによってはアクセス数が少ない深夜などにインスタンスを停止し、アクセスが増えてくる時間帯に起動などの調整ができ、不要な時間帯でインスタンスが起動していることによる運用コストを削減できるなど、とても便利な機能だと感じました。

「Lambda」はコードの実行されたときに起動するものなので、継続で起動している料金とは異なり「使用した分の料金が発生」ですのでコスト的にも良いと思いました。
学習していると他にも色々な便利な事が出来るのでこれからも学習をし活用したいと思います。
Lambdaの料金については<a href="https://aws.amazon.com/jp/lambda/pricing/" target="_blank">こちら</a>を参考にしてください。

###### このように自動化をすることにより起動や停止のし忘れなどのヒューマンエラーがなくなると思いますので活用する方が良いと感じました。

またエラーが発生してしまいましたが「CloudWatch」のログを確認してすぐに解決したので改めてエラーが出た際に「CloudWatch」を確認する癖付けの重要さも感じました。

最後まで読んでいただいた方、ありがとうございました。