AWS Lambda&cloudwatchのルールでインスタンスを自動停止させる

最近AWSを勉強するために、個人でアカウントを作り色々いじって遊んでいます。
インスタンスを停止し忘れることがしょっちゅうあるので、自動で停止するようにしようと思い、調べました。

インスタンスのcronにawscliのコマンドを登録してもよかったのですが、せっかくなのでAWSの機能を色々使うことにしました。

以下の記事と公式のドキュメントを参考にして作業を進めました。

https://geeknavi.net/aws/ec2インスタンスをスケジュールで自動起動・自動
https://aimless.jp/blog/archives/2681/

# 前提
EC2インスタンスが既に存在しており、起動した状態であること。

# Lambdaの登録
AWSにログインをしたらLambdaの画面を開き、新規関数を作成します。

## 設計図の選択
設計図は `Blank Function` をクリックします。

![スクリーンショット 2017-06-11 14.05.12.png](https://qiita-image-store.s3.amazonaws.com/0/71146/6fdb9f23-a9ee-432a-416b-5cf6c649b1fb.png)

## トリガーの設定

何もせずに次へをクリックします。


![スクリーンショット 2017-06-11 14.06.51.png](https://qiita-image-store.s3.amazonaws.com/0/71146/69fc12cc-49b5-8754-7d42-17d695385a88.png)

## 関数の設定
### 画面上部
![スクリーンショット 2017-06-11 14.08.14.png](https://qiita-image-store.s3.amazonaws.com/0/71146/b0bd703e-7ba2-c198-86ea-9cc1beea1577.png)

名前、説明はお好きなように。
とりあえず

- 名前
 `stop_ec2_instance`

- 説明
`インスタンスを停止する関数`

としておきます。

- ランタイム

Node.jsのままにします。

- コード

参考記事に記載されている以下の内容にします。
SDKについてはドキュメントがありますので、詳細を知りたい場合は目を通しておくとよいと思います。
以下はJavascript用です。
http://docs.aws.amazon.com/AWSJavaScriptSDK/latest/index.html

`YOUR_INSTANCE_ID` , `YOUR_REGION` は自身の環境に合わせて書き換えてください。
idはArrayで渡すので、複数指定が可能なようです。
(ドキュメントを見ると `Array<String>` となっています)

```
const INSTANCE_ID = 'YOUR_INSTANCE_ID';
 
var AWS = require('aws-sdk'); 
AWS.config.region = 'YOUR_REGION';
 
function ec2Stop(cb){
    var ec2 = new AWS.EC2();
    var params = {
        InstanceIds: [
            INSTANCE_ID
        ]
    };
  
    ec2.stopInstances(params, function(err, data) {
        if (!!err) {
            console.log(err, err.stack);
        } else {
            console.log(data);
            cb();
        }
    });
}
exports.handler = function(event, context) {
    console.log('start');
    ec2Stop(function() {
        context.done(null, 'Stoped Instance');
    });
};
```

### 画面下部
![スクリーンショット 2017-06-11 14.20.35.png](https://qiita-image-store.s3.amazonaws.com/0/71146/a280b8b4-ed6b-84f4-2e9d-50c408a98c5e.png)

- 環境変数

特に設定しないので空欄のままにします。

- ハンドラ

そのままにします。

- ロール

カスタムロールの作成を選びます。
そうすると別タブにIAM ロール作成画面が開くので作成します。

### IAM ロール
![スクリーンショット 2017-06-11 14.25.59.png](https://qiita-image-store.s3.amazonaws.com/0/71146/365bd834-94ce-a4f5-53b4-8ec24c4b4c30.png)

- IAM ロール

そのままにします。

- ロール名

お好きなように。
とりあえず `stop_instance_lambda` とします。 

- ポリシードキュメント

クリックするとテキストエリアが開くので、以下の内容に書き換えます。
ポリシードキュメントについては[こちらの公式ドキュメント](http://docs.aws.amazon.com/ja_jp/IAM/latest/UserGuide/access_policies.html)を読むとよいと思います。

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

入力し終わったら右下に `許可` ボタンがあるのでクリックします。
作成が完了するとlambdaの画面に戻ります。

既存のロールで先ほど作成したロールが選べるようになっているので選択します。

- タグ
- 詳細設定

こちらはデフォルトのままにするので何もせず。
画面右下の次へをクリックします。

確認画面に遷移するので、タイポなどがないか確認し、問題なければ `関数の作成` ボタンをクリックします。

## 関数確認
![スクリーンショット 2017-06-11 14.35.19.png](https://qiita-image-store.s3.amazonaws.com/0/71146/8fd68b32-c332-563d-ea83-93f6200a1183.png)

作成が完了するとこちらの画面に遷移します。
作った関数が動くか確認するためテストをクリックします。

- テスト

![スクリーンショット 2017-06-11 14.37.17.png](https://qiita-image-store.s3.amazonaws.com/0/71146/d35827bb-aa5a-ec67-118c-bc6a7695d5db.png)

このような画面が開くので、そのまま何もせず `保存してテスト`　をクリックします。
そうすると関数が実行されます。

実行した結果が画面の下部に表示されるので、ログにエラーがないことを確認してください。
そして指定したインスタンスが動作を停止しているかどうか確認し、停止していればOKです。

# Lambdaのスケジュール実行
毎日0時にlambdaを実行するために、cloudwatchの設定をします。
cloudwatchの画面を開き、左メニューの `イベント` をクリックして画面を開き、ルールの作成をクリックしてください。

## イベントソース
![スクリーンショット 2017-06-11 14.48.26.png](https://qiita-image-store.s3.amazonaws.com/0/71146/9c79374c-e8bc-d9ad-4dc3-c4e16e3454ad.png)


- イベントパターン or スケジュール

`スケジュール` のラジオボタンを選択してください。

- CloudWatch イベントスケジュール

好みの問題になりそうなのですが、 `cron式` を選択して以下の内容に書き換えてください。
イベントスケジュールの詳細は[こちら](http://docs.aws.amazon.com/ja_jp/AmazonCloudWatch/latest/events/ScheduledEvents.html)に目を通しておくとよいです。

```
0 15 * * ? *
```

注意事項としては、時間は `GMT グリニッジ標準時` で実行されるそうなので、9時間マイナスして考える必要があります。
(上記の場合、日本時間のAM0:00に実行させます)

## ターゲット
ターゲットの追加をクリックし、先ほど作成したLambdaを選びましょう。

- バージョン/エイリアスの設定
- 入力の設定


はデフォルトのままにします。
最終的に以下のようになると思います。

![スクリーンショット 2017-06-11 15.00.52.png](https://qiita-image-store.s3.amazonaws.com/0/71146/40e4574a-2c04-f394-b37a-acaf71ec706b.png)

右下の設定の詳細をクリックします。

## ルールの詳細の設定
![スクリーンショット 2017-06-11 15.01.52.png](https://qiita-image-store.s3.amazonaws.com/0/71146/55aa63c6-4036-621a-7a56-2a2331b246cd.png)

- 名前
- 説明

こちらはお好きなように。
入力が完了したら右下のルールの作成をクリックして完了します。

# さいごに
インスタンスを起動させたままにして0時を迎えましょう。
lambdaが起動するはずなので、

- cloudwatchのログ
- インスタンスの状態

を確認し、lambdaが実行されていることと、インスタンスが停止していればOKです。