AWS EC2上で自作のアプリケーションを回しているのですが、実行、停止を頻繁に繰り返すことがあり、EC2に入っていちいち操作させるのが結構めんどくさかったりします。
そこで、LineからEC2を操作して、プログラムの実行停止をできるようにしてみます。
全体像
以下のフローでLineからEC2を操作します。
- Line Messaging APIからAPI GatewayへPOSTリクエストを送信
- API Gatewayをトリガにして、Lambda関数が実行
- Lambda関数からEC2インスタンスが起動or停止される
- 起動時には設定したスクリプトが自動実行される
   
作成手順
- EC2インスタンスの作成
- IAMポリシーの作成
- Lambda関数の設定
- API Gatewayの設定
- Line Messaging APIの設定
- EC2起動時実行スクリプトの設定
1. EC2インスタンスの作成
プログラムを実行するためのEC2インスタンスを作成しておきます。(作成手順は省略)
後述のLambda関数で利用するため、作成したEC2のインスタンスIDをメモしておきます。
2. Lambda用IAMロールの作成
今回はLambdaの関数からEC2を操作するため、LambdaにEC2インスタンスの起動停止を行うための、IAMロールを付与してあげます。
こちらのAWS公式マニュアルに従います。
【IAMポリシーの作成】
IAM -> ポリシー -> ポリシーの作成 -> JSON
でエディタに下記のJSONを記載します。
ポリシー名はec2StartStopPolicyとします。
ポリシードキュメント
{
  "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": "*"
    }
  ]
}
 
【IAMロールの作成】
ロール -> ロールの作成 を選択し、エンティティの種類にAWSサービス、ユースケースにLambdaを選択します。
アクセス権限ポリシーで、上で作成したポリシーを選択し、ロール名をec2StartStopRoleとして、ロールを作成します。
 
3. Lambda関数の作成
EC2を起動、停止するためのLambda関数を作成します。
【関数の作成】
Lineから「起動」「停止」というメッセージを受け取って、対応するアクションを行う仕様とします。
Lambda -> 関数の作成 -> 一から作成 -> ランタイムにPython3.8を選択 -> 関数の作成

配置されたLambda関数の関数コード内、lambda_function.pyに下記のコードを記載します。
コード内のregionとinstancesには対象のEC2インスタンスの内容に置き換えてください。
Lambda関数
import json
import urllib.request, urllib.parse
import boto3
import os
region = '**リージョン**'
instances = ['**インスタンスID**']
ec2 = boto3.client('ec2', region_name=region)
def start_ec2():
    ec2.start_instances(InstanceIds=instances)
def stop_ec2():
    ec2.stop_instances(InstanceIds=instances)
    
def lambda_handler(event, context):
    # TODO implement
    text = event['events'][0]['message']['text']
    if text == '起動':
        start_ec2()
    elif text == '停止':
        stop_ec2()
    else:
        pass
        
    print("Line Message is {}".format(text))
    return {
        'statusCode': 200,
        'body': json.dumps('Hello from Lambda!')
    }
 
【IAMロールを付与】
作成したIAMロールをLambda関数に付与します。
Lambdaのアクセス権限タブで実行ロールの編集をクリックし、先ほど作成したIAMロールを選択して保存します。

4. API Gatewayの設定
作成したLambdaのデザイナー上から、トリガーを追加を選択し、API Gatewayをトリガーとして追加します。

作成したAPI GatewayのAPIエンドポイントをメモしておきます。

今回は、LineからのPOSTリクエストに応答して、Lambda関数をトリガするようにします。
API Gateway画面から、アクション -> メソッドを追加 -> POSTを選択 -> 作成したLambda関数を指定して、POSTリクエスト用のメソッドを作成します。

最後に、アクション->APIのデプロイ を選択し、デプロイします。

4. Line Messaging APIの設定
API GatewayにPOSTリクエストを送るためのLine Messaging APIを作成します。
Line Developers出ない方は新規登録をしましょう。
【チャネルの作成】
Line Developersにログインし、新規Providerを作成します。
Channelsに「Create a MEssaging API channel」を選択し、Channel nameなど適当に埋めて、Channelを作成します。
 
【Webhook URLの設定】
Messaging APIの設定で、Webhook URL選択し、作成したAPI GatewayのAPIエンドポイントを記載します。
【動作確認】
Messaging API設定画面で表示されるQRコードを読み取り、Lineで友達追加します。
このチャネルで、「起動」または「停止」を送って、実際にEC2インスタンスが起動、停止することを確かめます。
起動、停止を送ると、、、

5. 起動時設定
最後に、EC2が起動したときに特定のスクリプトを実行できるようにします。
今回は起動・停止時にメッセージを出力するだけの、mytestというスクリプトを登録します。
# !/bin/sh
# chkconfig: 2345 99 10
# description: test shell
case "$1" in
 start)
       echo "start!" > /tmp/start.txt
       ;;
 stop)
       echo "stop!" > /tmp/stop.txt
       ;;
  *) break ;;
esac
下記のコマンドでchkconfigに登録すると、スクリプトが実行されるようになります。
$ chkconfig --add mytest
$ chkconfig mytest on
まとめ
以上で、好きなタイミングでLineからEC2を起動させプログラムを自動起動できるようになりました!外出中でも気軽にEC2を操作できるのが嬉しいですね。
