読者です 読者をやめる 読者になる 読者になる

まちいろエンジニアブログ

南池袋のWebサービス開発会社、株式会社まちいろのエンジニアブログです。

AWS Lambda で EC2 インスタンスを自動起動・停止してみる (セットアップ編)

AWS Lambda Node.js

こんにちは、まちいろの工藤です。

先日の AWS Summit レポートでも

今回の AWS Summit では「サーバーレス」という単語がよく聞こえてきました。

Lambda をうまく利用することで、開発・運用コストの最小化でき、 かつアプリケーションからビジネスロジック以外のコードを切り出すことができる、というのはかなりキャッチーですね。

事例で紹介されていた、EC2 インスタンスを日中だけ起動しておくよう Lambda で制御する、というのは面白いなと思いました。

と触れましたが、今回は事例として紹介されていた「EC2 インスタンス自動起動・停止」に挑戦してみたいと思います。

まずはコンソール画面から触ってみる

Lambda がどんなものか、まずはコンソールから Lambda Function を登録してみたいと思います。
ヘッダメニューのサービスから、[コンピューティング]-[Lambda] にアクセスします。

f:id:mkudo-machiiro:20160615113649p:plain:w400

Lambda Function を追加する

「Step 1: Select blueprint」は【Skip】ボタンを押してスキップします。
次に、「Step 2: Configure function」にて以下の設定を行います。

項目 設定
Name lambda-test
Runtime Node.js 4.3
Code entry type Edit code inline
Handler index.handler
Role Create new role - * Basic execution role

ソースコードには、サンプルとして以下のコードを貼り付けます。
他にも ZIP ファイルをアップロードしたり、S3 に配置した ZIP ファイルを読ませる方法があるようです。

exports.handler = (event, context) => {
  console.log('lambda test');
};

Role のプルダウンを変更すると、IAM ロールの登録画面が別ウィンドウで表示され、Lambda を実行するために必要なポリシーが予め設定された状態となります。
このロールは後ほど使用したいので、名称に EC2_OPERATING_SCHEDULE_MANAGER と付けて保存しておきます。
登録が完了すると、Lambda Function の設定画面側で追加した IAM ロールが選択された状態となります。

以上の設定で Lambda Function を追加します。

動作確認

Lamda Function の詳細画面の【Test】ボタンからテストを実行します。
ここで Function に渡すパラメータを定義可能ですが、今回はサンプル Hello World そのままで実行します。

f:id:mkudo-machiiro:20160615120755p:plain:w400

実行すると、画面下部に実行結果が表示されます。
先ほど貼り付けたコードに記述した console.log の実行結果がログに出力されていれば成功です。

f:id:mkudo-machiiro:20160615121028p:plain:w400

ローカル開発環境の構築

コンソールを触ってみた印象としては、コードの修正・デプロイの流れが面倒そうに感じました。
そこで、ローカルのソースコードを ZIP 化 -> デプロイまでの流れを作ってみたいと思います。

今回はこの要件にぴったりな npm モジュール node-aws-lambda を使用したいと思います。

github.com

gulp セットアップ

まずは node-aws-lambda を使ったデプロイに必要な各種モジュールをインストールします。

$ npm install gulp gulp-install gulp-zip del node-aws-lambda require-dir run-sequence --save-dev

次に gulpfile.js を作成します。
require-dir モジュールを使って、タスクファイルの分割を行っています。

var dir = require('require-dir');
dir('./gulp/tasks', {recurse: true});

node-aws-lambda の README を参考に、デプロイ用のタスクファイル gulp/tasks/deploy.js を作成します。

const gulp = require('gulp');
const zip = require('gulp-zip');
const del = require('del');
const install = require('gulp-install');
const runSequence = require('run-sequence');
const awsLambda = require("node-aws-lambda");

gulp.task('clean', function() {
  return del(['./dist', './dist.zip']);
});

gulp.task('js', function() {
  return gulp.src(['index.js'])
    .pipe(gulp.dest('dist/'));
});

gulp.task('node-mods', function() {
  return gulp.src('./package.json')
    .pipe(gulp.dest('dist/'))
    .pipe(install({production: true}));
});

gulp.task('zip', function() {
  return gulp.src(['dist/**/*', '!dist/package.json'])
    .pipe(zip('dist.zip'))
    .pipe(gulp.dest('./'));
});

gulp.task('upload', function(callback) {
  awsLambda.deploy('./dist.zip', require("./lambda-config.js"), callback);
});

gulp.task('deploy', function(callback) {
  return runSequence(
    ['clean'],
    ['js', 'node-mods'],
    ['zip'],
    ['upload'],
    callback
  );
});

node-aws-lambda 用の設定ファイル gulp/tasks/lambda-config.js を作成します。
role には先ほど作成した IAM ロール EC2_OPERATING_SCHEDULE_MANAGER の arn を指定します。
注意点として、指定した profile に Lambda Function の登録・更新権限を付与しておく必要があります。

module.exports = {
  profile: 'machiiro',
  region: 'ap-northeast-1',
  handler: 'index.handler',
  role: 'arn:aws:iam::xxxxxxxx:role/EC2_OPERATING_SCHEDULE_MANAGER',
  functionName: 'lambda-test',
  timeout: 5,
  memorySize: 128,
  publish: false,
  runtime: 'nodejs4.3'
}

最後に、package.jsonscript に gulp 実行用の設定を追加しておきます。

  "scripts": {
    "gulp": "gulp"
  },

デプロイ

コンソール画面で貼り付けたソースコードindex.js として作成します。
正常にデプロイされたことがわかるよう、ログに出力するメッセージをちょっといじっておきます。

exports.handler = (event, context) => {
  console.log('lambda test2');
};

最終的なファイル構成は以下のようになります。

gulp/
    tasks/
        deploy.js
        lambda-config.js
node_modules/
gulpfile.js
index.js
package.json

デプロイを実行してみます。

$ npm run gulp deploy
> gulp "deploy"

[12:47:12] Using gulpfile path-to-path/gulpfile.js
[12:47:12] Starting 'deploy'...
[12:47:12] Starting 'clean'...
[12:47:12] Finished 'clean' after 8.02 ms
[12:47:12] Starting 'js'...
[12:47:12] Starting 'node-mods'...
[12:47:12] Finished 'js' after 19 ms
npm WARN package.json lambda-test@1.0.0 No description
npm WARN package.json lambda-test@1.0.0 No README data
[12:47:13] Finished 'node-mods' after 716 ms
[12:47:13] Starting 'zip'...
[12:47:13] Finished 'zip' after 28 ms
[12:47:13] Starting 'upload'...
[12:47:14] Finished 'upload' after 597 ms
[12:47:14] Finished 'deploy' after 1.36 s

Lambda の画面から再度テストを実行してみましょう。
ログに出力されるメッセージが変更したものになっていれば、デプロイは正常に動作しています。

まとめ

今回は Lambda を一から触りつつ、gulp をつかってソースコードをデプロイする流れを構築してみました。
次回は、実際に EC2 インスタンスの起動・停止させる部分を実装していきたいと思います。