AWSメモ >

AWS Lambda のローカル開発手順

事前準備

aws-sdk と AWS CLI をインストールしておく。
AWSローカル開発環境の構築 を参照

SAM Local のインストール

# NPMでインストール
npm install -g aws-sam-local

# インストール(バージョン)確認
sam --version

Dockerのインストール

「SAM Local は docker-lambda というカスタマイズされた Docker イメージを自動的に提供します」という事らしい。
http://docs.aws.amazon.com/ja_jp/AmazonECS/latest/developerguide/docker-basics.html

インストールガイドに従ってインストール
https://docs.docker.com/engine/installation/

DynamoDB ローカルのインストール

参考)
http://docs.aws.amazon.com/ja_jp/amazondynamodb/latest/developerguide/DynamoDBLocal.html

https://s3.ap-south-1.amazonaws.com/dynamodb-local-mumbai/dynamodb_local_latest.zip からダウンロード、解凍する。

DymanoDBの開始

java -Djava.library.path=./DynamoDBLocal_lib -jar DynamoDBLocal.jar -sharedDb

※デフォルトでは localhost:8000 で動作する。
※AWS CLI で エンドポイント指定するか、http://localhost:8000/shell から各種操作が可能。

ローカルIPアドレスの確認

上記で起動した DynamoDB はホストOS上の 8000ポートで動作しているが、
sam local は docker上で動作する為、sam local から ローカルへの DynamoDB には
localhost:8000 という指定ではアクセスはできない。

なので、ローカルホストの IPアドレスを確認し、lo0 に 127.0.0.1 (localhost) 以外のアドレスが割り当たっていない場合は、以下の通り割り当てる。

sudo ifconfig lo0 alias 10.20.30.40/24
※10.20.30.40/24 は 割り当てる IPアドレスとサブネットマスク

SAM localの 主なCLI オペレーション

コマンド説明補足
start-apiすべての Lambda 関数をホストするローカル HTTP サーバーを作成する。
invokeローカル Lambda 関数を一度呼び出し、呼び出しの完了後に終了する。
generate-event疑似サーバーレスイベントを生成する。
validateテンプレートを検証する。
package および deployAM アプリケーションのパッケージングおよびデプロイメントを行うhttp://docs.aws.amazon.com/ja_jp/lambda/latest/dg/serverless-deploy-wt.html#serverless-deploy

SAM Local によるシンプルなアプリケーションの構築

Lambda関数の作成

TODO: handler を分けた方が良さそう

https://github.com/awslabs/serverless-application-model/tree/master/examples/2016-10-31/api_backend

book.js

'use strict';
var AWS = require('aws-sdk');

var dynamoOpt = {apiVersion: '2012-08-10'};
if (process.env.DYNAMO_REGION && process.env.DYNAMO_END_POINT) {
    dynamoOpt.region = process.env.DYNAMO_REGION;
    dynamoOpt.endpoint = process.env.DYNAMO_END_POINT;
}
var documentClient = new AWS.DynamoDB.DocumentClient(dynamoOpt);

const createResponse = (callback, statusCode, body) => {
    var res = { 
        "statusCode": statusCode,
        "body": JSON.stringify(body)
    }   
    callback(null, res);
}

exports.handler = (event, context, callback) => {
    var req = event.body || event;
    if (typeof(req) === "string" && req !== "") {
      req = JSON.parse(req);
    }   
    var id = false;
    if (event.pathParameters){
        id = event.pathParameters.id || false;
    }   
    switch(event.httpMethod){
        case "GET":
            if(id && id > 0) {
                var params = { 
                  TableName : 'Books',
                  FilterExpression : 'id = :id',
                  ExpressionAttributeValues : {':id' : id }
                };
                documentClient.scan(params, function(err, data) {
                   if (err) {
                        console.log(err);
                        createResponse(callback, 500, { "msg": "Get Error!", "err": err});
                   } else {
                        createResponse(callback, 200, data);
                        console.log(data);
                   }
                });
                return;  
            } else {
                var params = { 
                  TableName : 'Books'
                };
                documentClient.scan(params, function(err, data) {
                   if (err) {
                        console.log(err);
                        createResponse(callback, 500, { "msg": "List Error!", "err": err});
                   } else {
                        createResponse(callback, 200, data);
                        console.log(data);
                   }
                });
            }
            break;
        case "POST": 
            var params = { 
                TableName : 'Books',
                Item: {
                    "id" : req.id,
                    "isbn" : req.isbn,
                    "title" : req.title,
                    "price" : parseInt(req.price,10)
                }
            };
            documentClient.put(params, function(err, data) {
                if (err) {
                    console.log(err);
                    createResponse(callback, 500, { "msg": "Create Error!", "err": err, "req": req});
                } else {
                    createResponse(callback, 200, { "msg": "Create OK!"});
                }
            });
            break;
        case "PUT":
            var params = {
                TableName : 'Books',
                Key: { "id" : id },
                ExpressionAttributeNames: {
                    "#isbn" : "isbn",
                    "#title" : "title",
                    "#price" : "price"
                },
                ExpressionAttributeValues: {
                    ":isbn" : req.isbn,
                    ":title" : req.title,
                    ":price" : parseInt(req.price, 10)
                },
                UpdateExpression: "SET #isbn = :isbn, #title = :title, #price = :price"
            };
            documentClient.update(params, function(err, data) {
                if (err) {
                    console.log(err);
                    console.log(data);
                    createResponse(callback, 500, { "msg": "Update Error!", "err": err});
                } else {
                    createResponse(callback, 200, { "msg": "Update OK!"});
                }
            });
            break;
        case "DELETE":
            var params = {
                TableName : 'Books',
                Key: { "id" : id }
            };
            documentClient.delete(params, function(err, data) {
                if (err) {
                    console.log(err);
                    console.log(data);
                    createResponse(callback, 500, { "msg": "Delete Error!", "err": err});
                } else {
                    createResponse(callback, 200, { "msg": "Delete OK!"});
                }
            });
            break;
        default:
            console.log("Error: unsupported HTTP method (" + event.httpMethod + ")");
            createResponse(callback, 501, { "msg": "Error: unsupported HTTP method (" + event.httpMethod + ")" } );
    }
}

テンプレートの作成

template-local.yml

AWSTemplateFormatVersion : '2010-09-09'
Transform: AWS::Serverless-2016-10-31
Description: Test serverless application.

Resources:

  BookFunction:
    Type: AWS::Serverless::Function
    Properties:
      Handler: book.handler
      Runtime: nodejs6.10
      Environment:
        Variables:
          DYNAMO_END_POINT: http://10.20.30.40:8000         #上記で確認/設定したローカルのIPアドレス
          DYNAMO_REGION: localhost
      Events:
        List:
          Type: Api
          Properties:
            Path: /book
            Method: get
        Create:
          Type: Api
          Properties:
            Path: /book
            Method: post
        Update:
          Type: Api
          Properties:
            Path: /book/{id}
            Method: put
        Delete:
          Type: Api
          Properties:
            Path: /book/{id}
            Method: delete

APIの動作確認

APIサーバー開始

sam local start-api --template template-local.yml

動作確認

一覧

curl -v http://localhost:3000/book

登録

curl -v -XPOST --data '{ "id" : "A01", "isbn" : "ABC001", "title" : "テスト001", "price": 1008 }' http://localhost:3000/book

キー指定検索

curl -v http://localhost:3000/book/A01

更新(キー指定)

curl -v -XPUT --data '{ "id" : "A01", "isbn" : "ABC001", "title" : "テスト001", "price": 2016 }' http://localhost:3000/book/A01

削除(キー指定)

curl -v -XDELETE http://localhost:3000/book/A01

Lambda単体の動作確認

イベントデータを生成

sam local generate-event apigateway aws-proxy > sample_request.json

※生成したJSONを処理に合わせて書き換える。

実行

sam local invoke BookFunction -e sample_request.json

サンプル/参考URL

aws-sdk から DynamoDB を利用するサンプル

http://docs.aws.amazon.com/ja_jp/sdk-for-javascript/v2/developer-guide/dynamodb-examples.html

aws-sdk から Lambda を利用するサンプル

http://docs.aws.amazon.com/ja_jp/sdk-for-javascript/v2/developer-guide/lambda-examples.html

AWS SAM Local(ベータ版) – サーバーレスアプリケーションをローカルに構築してテストする

https://aws.amazon.com/jp/blogs/news/new-aws-sam-local-beta-build-and-test-serverless-applications-locally/

SAM ローカルを使用してサーバーレスアプリケーションをローカルでテストする

http://docs.aws.amazon.com/ja_jp/lambda/latest/dg/test-sam-local.html
http://docs.aws.amazon.com/ja_jp/lambda/latest/dg/test-sam-local.html#sam-cli-simple-app

Lambda ベースのアプリケーションをデプロイする

http://docs.aws.amazon.com/ja_jp/lambda/latest/dg/deploying-lambda-apps.html

独自のサーバーレスアプリケーションを作成する(パッケージ化とデプロイ)

http://docs.aws.amazon.com/ja_jp/lambda/latest/dg/serverless-deploy-wt.html

Lambda ベースのアプリケーションのデプロイメントを自動化する

http://docs.aws.amazon.com/ja_jp/lambda/latest/dg/automating-deployment.html


トップ   差分 バックアップ リロード   一覧 単語検索 最終更新   ヘルプ   最終更新のRSS
Last-modified: 2017-12-09 (土) 22:18:20 (2552d)