LoginSignup
2
5

More than 1 year has passed since last update.

APIGatewayとStepFunctionを使い、EC2の起動から停止時間までを自在に操る

Last updated at Posted at 2021-10-19

はじめに

「EC2を起動し、特定の時間経過後、EC2を停止する」仕組みをAPIGatewayとStepFunctionを使い、実現します。

完成図

https://xxxxx.execute-api.ap-northeast-1.amazonaws.com/prod/start-limit?instance_id=i-hogehoge&time=10をリクエストすると、インスタンスIDがi-hogehogeのEC2を起動し、10秒後に停止する挙動になります。

挙動の詳細について説明しますと、
起動するインスタンスinstance_idで指定し、と起動してから停止するまでの時間をtimeで指定しています。

APIGatewayからこれらの2つの値をStepFunctionに渡し、StepFunction内で、Lambdaにinstance_id、とWaitにtimeを渡して実行する挙動になります。

作業の流れ流れ

①Lambda用のIAMポリシーを作成
②Lambdaを2つ作成
③Stepfunction作成
④APIGateway用のIAMロール作成
⑤APIGateway作成

Lambda用のIAMポリシーを作成

LambdaでEC2を起動・停止するためのぽりが必要です。
jsonで下記のコードをコピペして、ポリシーを作成しましょう。

{
  "Version": "2012-10-17",
  "Statement": [
    {
     "Sid": "VisualEditor0",
     "Effect": "Allow",
     "Action": [
         "logs:CreateLogStream",
         "ec2:DescribeInstances",
         "ec2:StopInstances",
         "ec2:StartInstances",
         "logs:CreateLogGroup",
         "logs:PutLogEvents"
     ],
     "Resource": "*"
    }
  ]
}

Lambdaを2つ作成

起動と停止するLambdaを作成します。
・関数を作成:一から作成
・関数名:適切に
・ランタイム:Python
・アクセス権限:基本的な Lambda アクセス権限で新しいロールを作成

EC2Start
import json
import boto3
def lambda_handler(event, context):
    ec2 = boto3.client('ec2', region_name='ap-northeast-1')
    ec2.start_instances(InstanceIds=[event['instance_id']])
EC2Stop
import json
import boto3
def lambda_handler(event, context):
    ec2 = boto3.client('ec2', region_name='ap-northeast-1')
    ec2.stop_instances(InstanceIds=[event['instance_id']])

作成後、設定実行ロールの編集から、先程作成したポリシーをIAMロールにアタッチしてください。

Stepfunction作成

ステートマシンを作成します。
ワークフローを視覚的に設計
タイプ標準
次へ

ワークフローを設計
StartとEndの間に以下の通りにフローを設定します。
アクションLambda Invoke
フローWait
アクションLambda Invoke

第一工程(EC2の起動)

設定
状態名startEC2
Integration TypeOptimized
Function name先程作成したEC2の起動Lambda
ペイロードUse state input as payload
追加の状態Wait

入力
InputPath で入力をフィルタリング$.InputParams
入力をInputParamsに絞ることで、Lambdaに渡す値がわかりやくすなります。
Lambdaは、InputParams.instance_idを参照します。

"InputParams": {
  "instance_id": "i-xxxxxxxxxxxx",
  "time": 10
}

出力
ResultPath を使用して元の入力を出力に追加Discard result and keep original input
元の入力からそのまま出力されます。
元の入力を変えると、Waitや次のLambdaが値を参照できなくなります。



第二工程(待機時間)

設定
状態名stopEC2
オプションWait for a fixed interval
Get seconds from state input$.InputParams.time
InputParamstimeの値を参照して待機時間の値が決定されます。

入力
チェックしません

出力
チェックしません

第三工程(EC2の停止)

設定
状態名stopEC2
Integration TypeOptimized
Function name作成したEC2の停止Lambda
ペイロードUse state input as payload

入力
InputPath で入力をフィルタリング$.InputParams

出力
デフォルト

次へ
名前EC2-Control
実行ロール新しいロールを作成

ステートマシンが作成されました。

ARNは、後で使いますのでコピーしておいてください。

StepFunctionの定義

stepfunctionの定義になります。LambdaのARN2つを貼り付けると、コピペで作成できます。

{
  "Comment": "This is your state machine",
  "StartAt": "startEC2",
  "States": {
    "startEC2": {
      "Type": "Task",
      "Resource": "arn:aws:states:::lambda:invoke",
      "Parameters": {
        "Payload.$": "$",
        "FunctionName": "arn:aws:lambda:ap-northeast-1:xxxxxxxxxx:function:test-steppfunction:$LATEST"
      },
      "Retry": [
        {
          "ErrorEquals": [
            "Lambda.ServiceException",
            "Lambda.AWSLambdaException",
            "Lambda.SdkClientException"
          ],
          "IntervalSeconds": 2,
          "MaxAttempts": 6,
          "BackoffRate": 2
        }
      ],
      "Next": "Wait",
      "ResultPath": null,
      "InputPath": "$.InputParams"
    },
    "Wait": {
      "Type": "Wait",
      "Next": "stopEC2",
      "SecondsPath": "$.InputParams.time"
    },
    "stopEC2": {
      "Type": "Task",
      "Resource": "arn:aws:states:::lambda:invoke",
      "OutputPath": "$.Payload",
      "Parameters": {
        "Payload.$": "$",
        "FunctionName": "arn:aws:lambda:ap-northeast-1:xxxxxxx:function:stop-stepfunction:$LATEST"
      },
      "Retry": [
        {
          "ErrorEquals": [
            "Lambda.ServiceException",
            "Lambda.AWSLambdaException",
            "Lambda.SdkClientException"
          ],
          "IntervalSeconds": 2,
          "MaxAttempts": 6,
          "BackoffRate": 2
        }
      ],
      "End": true,
      "InputPath": "$.InputParams"
    }
  }
}

APIGateway用のIAMロール作成

StepFunctionsの実行権限を持ったロールが必要なため、API Gateway用のIAMロールを作成します

ロールの作成
AWSサービス
APIGateway
次のステップ

ポリシーの選択
AmazonAPIGatewayPushToCloudWatchLogsが選択済み
追加せずそのまま、次のステップをクリック

下記の通り、ロールを作成する

作成したロールにAWSStepFunctionsFullAccessをアタッチします。

ロールのARNをコピーしておきます。

APIGateway作成

REST API構築を選択します。

プロトコルREST
新しいAPI
API名EC2-Start-StepFunction

リソースの作成
リソース名start-limit

メソッドの作成
メソッドGET
結合タイプAWS サービス
AWS リージョン適切な値
AWS サービスStep Functions
HTTP メソッドPOST
アクションの種類アクション名の使用
アクションStartExecution
(LambdaをキックするAPIにはStartExecution)
実行ロール先程作成したAPIGateway用のロールのARN

統合リクエストをクリックします。

下側にあるマッピングテンプレートをクリックし、application/json名で、下記のコードを入力し、保存します。
先程コピーしたStepFunctionのARNが必要です。

application/json
#set( $body = $util.escapeJavaScript($input.json('$')) )
{
  "input": "{\"input\":$body,\"InputParams\":{\"instance_id\":\"$input.params('instance_id')\",\"time\":$input.params('time')}}",
  "stateMachineArn": "StepFunctionのARNを入力!"
} 

起動するインスタンスinstance_idと起動してから停止するまでの時間timeをAPIGatewayからStepFunctionに渡します。

StepFunction側は、以下のように受け取ります。

stepfuctionで受け取る
{
  "input": {},
  "InputParams": {
    "instance_id": "i-xxxxxxx",
    "time": 10
  }
}

APIをデプロイすると、URLが発行されます。
デプロイのステージ名をprodとすると、
URLはhttps://xxxxx.execute-api.ap-northeast-1.amazonaws.com/prodになります。

https://xxxxx.execute-api.ap-northeast-1.amazonaws.com/prod/start-limit?instance_id=i-xxxxxxx&time=100
とすると、インスタンスが起動し、100秒後にインスタンスが停止します。
URLをコピペして、エンターキーをおしてみましょう。

参考

Step Functionsを使い倒す
API Gateway を使用したStep Functions API の作成
ParametersやらResultPath
StepFunctionsの入力方法サンプルメモ集
API GatewayでStepFunctionsと統合する時のTips

2
5
0

Register as a new user and use Qiita more conveniently

  1. You get articles that match your needs
  2. You can efficiently read back useful information
  3. You can use dark theme
What you can do with signing up
2
5