前記事でserverless frameworkでのローカル環境構築方法を勉強してみたのですが、その続きみたいな記事になります。
今回はS3イベントをトリガーにしてLambdaを起動し、LambdaがS3やDynamoDBにアクセスするような構成を想定してローカルに動作確認用の環境を構築していきます。
ローカルに構築するインフラ構成
必要な物
- Nodejs
- npm
- Java
- awscli
手順
やっていきます。
プロジェクト作成
$ npx serverless create -t aws-nodejs -p local-s3-lambda-app
$ cd local-s3-lambda-app
$ npm init -y
必要なモジュール類をインストール
$ npm i serverless serverless-dynamodb-local serverless-s3-local aws-sdk
Lambdaとして動かす関数を用意
2つLambdaを作成します。
- S3にオブジェクトをPutするLambda(trigger)
- S3イベントでトリガーされるLambda(handler)
s3_trigger.js
"use strict";
const AWS = require("aws-sdk");
const fs = require("fs");
const s3Client = new AWS.S3({
s3ForcePathStyle: true,
accessKeyId: "S3RVER",
secretAccessKey: "S3RVER",
endpoint: new AWS.Endpoint("http://localhost:4569"),
});
module.exports.trigger = async (event, context, callback) => {
const uploadFile = fs.readFileSync("./upload_data/upload_data.json");
const params = {
Bucket: "local-bucket",
Key: "upload_data.json",
Body: uploadFile,
};
const response = await s3Client
.putObject(params)
.promise()
.catch((err) => {
console.log(err, err.stack);
});
console.log("OK");
callback();
};
handler.js
"use strict";
const AWS = require("aws-sdk");
const dynamodbClient = new AWS.DynamoDB({
endpoint: "http://localhost:8000",
});
module.exports.handler = async (event) => {
const params = {
TableName: "SomeTable",
};
const response = await dynamodbClient
.scan(params)
.promise()
.catch((err) => console.log(err));
console.log(JSON.stringify(response, null, 1));
};
serverless.ymlを修正
serverless.ymlにローカルで動かすS3とDynamoDBとLambdaを記述します。
serverless.yml
service: local-s3-lambda-app
configValidationMode: error
frameworkVersion: "2"
plugins:
- serverless-s3-local
- serverless-dynamodb-local
provider:
name: aws
runtime: nodejs12.x
stage: dev
region: ap-northeast-1
lambdaHashingVersion: 20201221
custom:
s3:
host: localhost
directory: ./local_s3
dynamodb:
stages:
- dev
start:
port: 8000
inMemory: true
migrate: true
seed: true
seed:
development:
sources:
- table: SomeTable
sources: [./seed/records.json]
resources:
Resources:
NewResource:
Type: AWS::S3::Bucket
Properties:
BucketName: local-bucket
Resources:
SomeTable:
Type: AWS::DynamoDB::Table
Properties:
TableName: SomeTable
AttributeDefinitions:
- AttributeName: attr1
AttributeType: S
KeySchema:
- AttributeName: attr1
KeyType: HASH
ProvisionedThroughput:
ReadCapacityUnits: 1
WriteCapacityUnits: 1
functions:
trigger:
handler: s3_trigger.trigger
handler:
handler: handler.handler
events:
- s3:
bucket: local-bucket
event: s3:Put
必要なファイルを追加
S3にPutするファイルとDynamoDBに初期投入するデータを用意します。
S3用
$ mkdir upload_data
$ touch upload_data/upload_data.json
$ echo '{}' > upload_data/upload_data.json
DynamoDB用
$ mkdir seed
$ touch seed/records.json
records.json
[
{
"attr1": "value1-1",
"attr2": "value2-1",
"attr3": "value3-1"
},
{
"attr1": "value1-2",
"attr2": "value2-2",
"attr3": "value3-2"
}
]
localDynamoDBをインストール
$ $(npm bin)/sls dynamodb install
ローカルで起動してみる
順番はこんな感じです
- S3を起動する
- DynamoDBを起動する
- Lambda(s3_trigger)をinvoke localする
S3イベントがhandlerをinvokeしてDynamoDBのレコードがコンソールに出力されていればOKです。
$ $(npm bin)/sls s3 start
$ $(npm bin)/sls dynamodb start
$ $(npm bin)/sls invoke local -f trigger
{
"Items": [
{
"attr2": {
"S": "value2-2"
},
"attr1": {
"S": "value1-2"
},
"attr3": {
"S": "value3-2"
}
},
{
"attr2": {
"S": "value2-1"
},
"attr1": {
"S": "value1-1"
},
"attr3": {
"S": "value3-1"
}
}
],
"Count": 2,
"ScannedCount": 2
}
無事出力されました!
終わりに
ローカルでS3イベントからLambda起動してDynamoDBの読み取りまでできちゃうのはすごいですね。
他にもapi-gatewayも動かせたりするので、まだまだローカルでの実行環境構築はいろんなことができそうです。
以上です。