AWS LambdaからEC2を起動、終了してみた
はじめに
t.hondaです。タイトル通り、LambdaからEC2を起動し、EC2での処理を完了後、EC2自体を終了させてみました。LambdaはAWS上のイベントにて処理を開始しますが、タイムアウト時間(現在は最大60秒)があります。またLambdaにてプログラムを書けるとはいえ、EC2内で実行した方がいい処理もあるかと思われます(ローカルストレージを使用したいなど)。
前書きが長くなりましたが、今回行ってみたLambdaからのEC2の起動は以下のようなケースを想定しています。
- AWS上のイベントの発生により開始したいバッチ処理などで、時間が掛かるケース
- AWS上のイベントの発生により開始したいが、EC2の方が処理を実行し易いケース
- EC2をメインの処理中のみ動かすことで、インスタンスのコストを圧縮したいケース
実装について
処理の流れ
処理の流れとしては、以下のようになります。
- ユーザがS3のバケットにファイルを配置することで、Lambda Functionが起動する
- LambdaからEC2を起動する
- EC2にて時間が掛かる処理を実行する(今回は単純なsleep処理)
- 処理完了後、S3のバケットに処理終了を表すファイルを出力する
- 最初とは別のLambda Functionが起動し、EC2を終了する
処理の実装
以下、上述した処理の流れに沿って実装について書いていきます。
1.ユーザがS3のバケットにファイルを配置することで、Lambdaが起動する
S3にバケットを用意します。今回は「t-honda-lambda-ec2-start」という名前としました。またS3にアップロード時に、次に書くLambda Functionを起動するよう設定します。設定方法についてはAWS Lambdaを始めてみる(2).Amazon S3イベントを扱うを参考にしてください。タイムアウトは、30秒としました。
2.LambdaからEC2を起動する
上記1.より呼び出されるLambda Functionです。 AWS SDK for JavaScriptを使用し、EC2を起動しています。
const INSTANCE_ID = 'your instance id'; const ACCESS_KEY = 'your access key'; const SECRET_KEY = 'your secret key'; var AWS = require('aws-sdk'); AWS.config.update({accessKeyId: ACCESS_KEY, secretAccessKey: SECRET_KEY}); AWS.config.region = 'us-west-2'; function ec2Start(){ var ec2 = new AWS.EC2(); var params = { InstanceIds: [ INSTANCE_ID ] }; ec2.startInstances(params, function(err, data) { if (err) console.log(err, err.stack); else console.log(data); }); } exports.handler = function(event, context) { console.log('start'); ec2Start(); };
3.EC2にて時間が掛かる処理を実行する(今回は単純なsleep処理)
4.処理完了後、S3のバケットに処理終了を表すファイルを出力する
上記2.にて起動するEC2に、以下のRubyを配置します。
require 'aws-sdk-v1' ACCESS_KEY = 'your access key' SECRET_KEY = 'your secret key' # ここで実際は何らかの処理を行う。 sleep(10) s3 = AWS::S3.new( :access_key_id => ACCESS_KEY, :secret_access_key => SECRET_KEY, :region => 'us-west-2' ) bucket = s3.buckets['t-honda-lambda-ec2-stop'] obj = bucket.objects[Time.now.to_s + '.txt'] result = obj.write('') puts result
このRubyを、Cronにてインスタンス起動時に実行されるよう設定します。処理内容としては、10秒のsleepを行った後、後述するS3 バケット(「t-honda-lambda-ec2-stop」というバケット名)に処理終了を表すファイルを出力します。
5.最初とは別のLambda Functionが起動し、EC2を終了する
最初とは別のバケットを用意します。今回は「t-honda-lambda-ec2-stop」という名前としました。このバケットにファイルが配置されたタイミングで、以下のLambda Functionを呼び出すように設定します。
const INSTANCE_ID = 'your instance id'; const ACCESS_KEY = 'your access key'; const SECRET_KEY = 'your secret key'; var AWS = require('aws-sdk'); AWS.config.update({accessKeyId: ACCESS_KEY, secretAccessKey: SECRET_KEY}); AWS.config.region = 'us-west-2'; function ec2Stop(){ 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); }); } exports.handler = function(event, context) { console.log('start'); ec2Stop(); };
実行してみる
実際に処理を実行し、キャプチャを取ってみました。時系列に並べただけですが、処理の流れが分かるかと思います。
1.ファイルをS3にアップロードする
2.LambdaからEC2を起動する
3.EC2の起動が始まる
4.EC2が起動した
5.EC2内のRubyから、S3にファイルを出力する
6.LambdaからEC2を終了する
7.EC2が終了し始まる
8.EC2が終了した
まとめ
Lambda FunctionからAWS SDKを呼ぶことができるので、AWS上のイベントからLambdaを起動し(現時点ではS3、Dynamodbなど限られますが)、別のサービスを呼び出すなど色々な使い方を想像できますね。
尚、今回の処理はLambdaの重複起動などは考慮しておりません。実際にはDynamoDBも使い、EC2の起動中・処理中も考慮すると、より良い構成になるかと思われます。
参考サイト
Configuring the SDK in Node.js
Class: AWS.EC2
AWS Lambdaを始めてみる(2).Amazon S3イベントを扱う