Lambdaを使ってAWSの複数EC2インスタンスを時間指定して起動、停止してみる


# 目標
AWSのEC2インスタンスに関して
- 起動・停止を自動化したい
- 起動・停止の時間帯の指定をしたい
- 設定したデフォルトの時間帯にすべてのインスタンスを起動・停止したい
- それぞれのインスタンスごとに時間帯を設定したい

# 設定手順
1. AWSにログイン
2. Lambdaの設定ページへ移動
3. Create a Lambda functionをクリック
4. 以下のコードをコピーしてFunctionを作成
5. 設定項目は以下を参照
6. Functionに対するEventの設定
7. Cron(A, B, C, D, E, F)の設定
8. インスタンスの設定ページに移動する
9. タグのキーと値の設定
10. 起動、停止の動作確認（必要に応じて）


## 起動コード
```
var AWS = require('aws-sdk');
var ec2 = new AWS.EC2({
    apiVersion: '2015-10-10',
    accessKeyId: '',
    secretAccessKey: '',
    region: ''
});

exports.handler = function(event, context) {
    ec2.describeInstances({
        Filters: [{
            Name: 'instance-state-name',
            Values: ['stopped']
        }]
    }, function(err, data) {
        if (err) {
            console.log(err, err.stack);
            context.done('error', err.stack);
            return;
        }

        const DEFAULT_BOOT_AT_UTC = '1'; //VST8
        var current                      = new Date();
        var current_hour                 = current.getHours();

        var is_target = function(tags) {
            for (var n in tags) {
                if (tags[n].Key == 'BootAtUTC') {
                    if (tags[n].Value == current_hour) {
                        return true;
                    }
                    return false;
                }
                if (DEFAULT_BOOT_AT_UTC == current_hour){
                    return true;
                }
            }
            return false;
        };

        var get_target = function(ids, instances) {
            for (var i = 0; i < instances.length; i++) {
                var ins = instances[i];
                if (is_target(ins.Tags)) {
                    console.log("starting (instanceId: " + ins.InstanceId + ")");
                    ids.push(ins.InstanceId);
                }
            }
        };
        var ids = [];
        for (var i = 0; i < data.Reservations.length; i++) {
            get_target(ids, data.Reservations[i].Instances);
        }
        ec2.startInstances({InstanceIds: ids}, function(err, data) {
            if (err) {
                console.log(err, err.stack);
                context.done('error', err.stack);
                return;
            }
            console.log(data);
            context.done(null, '');
        });
    });
};
```

## 停止コード
```
var AWS = require('aws-sdk');
var ec2 = new AWS.EC2({
    apiVersion: '2015-10-10',
    accessKeyId: '',
    secretAccessKey: '',
    region: ''
});
exports.handler = function(event, context) {
    ec2.describeInstances({
        Filters: [{
            Name: 'instance-state-name',
            Values: ['running']
        }]
    }, function(err, data) {
        if (err) {
            console.log(err, err.stack);
            context.done('error', err.stack);
            return;
        }

        const DEFAULT_SHUTDOWN_AT_UTC = '13'; //VST20
        var current                      = new Date();
        var current_hour                 = current.getHours();

        var is_target = function(tags) {
            for (var n in tags) {
                if (tags[n].Key == 'ShutdownAtUTC') {
                    if (tags[n].Value == current_hour) {
                        return true;
                    }
                    return false;
                }

                if (DEFAULT_SHUTDOWN_AT_UTC == current_hour){
                    return true;
                }
            }
            return false;
        };

        var get_target = function(ids, instances) {
            for (var i = 0; i < instances.length; i++) {
                var ins = instances[i];
                if (is_target(ins.Tags)) {
                    console.log("stopping (instanceId: " + ins.InstanceId + ")");
                    ids.push(ins.InstanceId);
                }
            }
        };
        var ids = [];
        for (var i = 0; i < data.Reservations.length; i++) {
            get_target(ids, data.Reservations[i].Instances);
        }
        ec2.stopInstances({InstanceIds: ids}, function(err, data) {
            if (err) {
                console.log(err, err.stack);
                context.done('error', err.stack);
                return;
            }
            console.log(data);
            context.done(null, '');
        });
    });
};
```

## 設定項目
- accessKeyId
- secretAccessKey
- region
- DEFAULT_BOOT_AT_UTC
- DEFAULT_SHUTDOWN_AT_UTC
- tags[n].Key
- tags[n].Value

### DEFAULT_BOOT_AT_UTC
- すべてのインスタンスに適用されるデフォルトの起動時間
- 希望する起動時間をUTC（タイムゾーン）で指定する
- 例えば、ベトナムの8時に起動したい場合
- VST = UTC + 7
 - UTC = VST -7
 - UTC = 8 - 7 = 1

### DEFAULT_SHUTDOWN_AT_UTC
- すべてのインスタンスに適用されるデフォルトの停止時間
- 希望する停止時間をUTC（タイムゾーン）で指定する

### tags[n].Key
- インスタンス設定ページのタグ設定で指定したキーが格納される

### tags[n].Value
- インスタンス設定ページのタグ設定で指定した値が格納される

## タグのキーと値の設定

### 個別に起動時間を設定する場合
- キー : BootAtUTC
- 値   : 希望するUTC時間

### 個別に停止時間を設定する場合
- キー : ShutdownAtUTC
- 値   : 希望するUTC時間

# 参照
- [lambdaとは](https://docs.aws.amazon.com/ja_jp/lambda/latest/dg/welcome.html)

- [regionの設定] (http://docs.aws.amazon.com/ja_jp/AWSEC2/latest/UserGuide/using-regions-availability-zones.html)

- [accessKeyId, secretAccessKeyの設定](https://docs.aws.amazon.com/ja_jp/AWSSimpleQueueService/latest/SQSGettingStartedGuide/AWSCredentials.html)

- [timezoneの一覧](https://publib.boulder.ibm.com/tividd/td/TWS/SC32-1274-02/en_US/HTML/SRF_mst273.htm)

- [AWS LambdaのScheduled EventでEC2インスタンスの定期停止、起動してみた](http://wata.hateblo.jp/entry/aws_lambda_scheduled_functions)