LocalStack上にAPI Gateway、Lambda、DynamoDB環境を構築してみる
はじめに
LocalStack上にAPI Gateway、Lambda、DynamoDBを環境を構築する。
CurlでApiを叩き。LambdaでDynamoDBからデータを取得しレスポンスを返す処理を実装する。
動作確認環境
「WSL2上のUbuntu 20.04でLocalStackを使ってみる」で構築した環境を使い作成する。
準備
作業フォルダー作成
各種ファイルを置く作業フォルダーを作成する
hoge@AA:~$ mkdir aws-console
hoge@AA:~$ cd aws-console
docker-compose.yml
docker-compose.ymlファイルを作成する。
必要なSERVICESを指定する。
version: "3.8"
services:
localstack:
container_name: "${LOCALSTACK_DOCKER_NAME-localstack_main}"
image: localstack/localstack:0.13.1
network_mode: bridge
ports:
- "4566:4566"
- "4571:4571"
environment:
- SERVICES=apigateway,lambda,dynamodb
- DEBUG=${DEBUG- }
- DATA_DIR=${DATA_DIR- }
- LAMBDA_EXECUTOR=${LAMBDA_EXECUTOR- }
- LOCALSTACK_API_KEY=${LOCALSTACK_API_KEY- } # only required for Pro
- HOST_TMP_FOLDER=${TMPDIR:-/tmp/}localstack
- DOCKER_HOST=unix:///var/run/docker.sock
- LAMBDA_EXECUTOR=docker-reuse
volumes:
- "${TMPDIR:-/tmp}/localstack:/tmp/localstack"
- "/var/run/docker.sock:/var/run/docker.sock"
DynamoDB
テーブル作成する。
hoge@AA:~/aws-console$ awslocal dynamodb create-table --table-name myUserTable \
--attribute-definitions \
AttributeName=Name,AttributeType=S \
AttributeName=Index,AttributeType=N \
--key-schema \
AttributeName=Name,KeyType=HASH \
AttributeName=Index,KeyType=RANGE \
--provisioned-throughput \
ReadCapacityUnits=10,WriteCapacityUnits=5 \
--profile=localstack
テーブル追加を確認する。
hoge@AA:~/aws-console$ awslocal dynamodb list-tables \
--profile=localstack
{
"TableNames": [
"myUserTable",
]
}
[ex] テーブル削除する。
hoge@AA:~/aws-console$ awslocal dynamodb delete-table \
--table-name myUserTable --profile=localstack
アイテム追加する
hoge@AA:~/aws-console$ awslocal dynamodb put-item --table-name myUserTable \
--item '{"Name":{"S": "Ishida Mio"}, "Index":{"N": "1000"}, "Gender":{"S": "Female"}, "Tel":{"S": "0769625106"}, "Mail":{"S": "mio1094@ccfrevk.ll"}, "Birthday":{"S": "1982/02/26"}}' \
--profile=localstack
hoge@AA:~/aws-console$ awslocal dynamodb put-item --table-name myUserTable \
--item '{"Name":{"S": "Shimura Kokoro"}, "Index":{"N": "1001"}, "Gender":{"S": "Female"}, "Tel":{"S": "0829490871"}, "Mail":{"S": "kokoro414@bevhlk.xju"}, "Birthday":{"S": "1990/02/17"}}' \
--profile=localstack
hoge@AA:~/aws-console$ awslocal dynamodb put-item --table-name myUserTable \
--item '{"Name":{"S": "Ishimura Masaki"}, "Index":{"N": "1002"}, "Gender":{"S": "Male"}, "Tel":{"S": "0848254480"}, "Mail":{"S": "masaki_ishimura@kokn.qgj"}, "Birthday":{"S": "1992/06/20"}}' \
--profile=localstack
hoge@AA:~/aws-console$ awslocal dynamodb put-item --table-name myUserTable \
--item '{"Name":{"S": "Shirai Tomoko"}, "Index":{"N": "1003"}, "Gender":{"S": "Female"}, "Tel":{"S": "0742216492"}, "Mail":{"S": "tomoko225@vlyqs.pxt"}, "Birthday":{"S": "1982/09/29"}}' \
--profile=localstack
hoge@AA:~/aws-console$ awslocal dynamodb put-item --table-name myUserTable \
--item '{"Name":{"S": "Yasui Tomoyuki"}, "Index":{"N": "1004"}, "Gender":{"S": "Male"}, "Tel":{"S": "095953680"}, "Mail":{"S": "tomoyuki772@jheauwpl.lyo"}, "Birthday":{"S": "1996/04/23"}}' \
--profile=localstack
アイテム追加されているかを確認する。
hoge@AA:~/aws-console$ awslocal dynamodb scan --table-name myUserTable \
--profile=localstack
{
"Items": [
{
"Index": {
"N": "1000"
},
"Tel": {
"S": "0769625106"
},
"Birthday": {
"S": "1982/02/26"
},
"Gender": {
"S": "Female"
},
"Mail": {
"S": "mio1094@ccfrevk.ll"
},
"Name": {
"S": "Ishida Mio"
}
},
〜略〜
[ex] アイテムを個別で取得する。
hoge@AA:~/aws-console$ awslocal dynamodb get-item --consistent-read \
--table-name myUserTable \
--key '{ "Name": {"S": "Ishida Mio"}, "Index": {"N": "1000"}}' \
--profile=localstack
Lambda
Functionを作成する。[1]
import os
import boto3
from boto3.session import Session
from datetime import datetime
session = Session(
aws_access_key_id='dummy',
aws_secret_access_key='dummy',
region_name='us-east-1'
)
if os.getenv('LOCALSTACK_HOSTNAME') is None:
endpoint = 'http://localhost:4566'
else:
endpoint=f"http://{os.environ['LOCALSTACK_HOSTNAME']}:4566"
dynamodb = session.resource(
service_name='dynamodb',
endpoint_url=endpoint
)
def getUsers(event, context):
table = dynamodb.Table('myUserTable')
data = []
response = table.scan()
while True:
data.extend(response["Items"])
if "LastEvaluatedKey" not in response:
break
response = table.scan(ExclusiveStartKey=response["LastEvaluatedKey"])
return {
'statusCode': 200,
'body':{
'users':data
}
}
zip形式で圧縮をする。
hoge@AA:~/aws-console$ zip lambda.zip Users.py
Functionを登録する。
hoge@AA:~/aws-console$ awslocal lambda create-function \
--runtime python3.8 \
--function-name users \
--handler Users.getUsers \
--zip-file fileb://lambda.zip \
--role r1 \
--profile=localstack
Functionを実行する。[2]
hoge@AA:~/aws-console$ awslocal lambda invoke \
--cli-binary-format raw-in-base64-out \
--function-name users \
--profile=localstack result.log
hoge@AA:~/aws-console$ cat result.log | jq
[ex] Functionを再登録する。
hoge@AA:~/aws-console$ awslocal lambda update-function-code --function-name users --zip-file fileb://lambda.zip --profile=localstack
[ex] Functionを削除する。(再登録で更新されない場合)
hoge@AA:~/aws-console$ awslocal lambda delete-function --function-name users --profile=localstack
API Gateway
作成する。
hoge@AA:~/aws-console$ awslocal apigateway create-rest-api --name 'UserApi' --profile=localstack
{
"id": "XXXXXXXX",
"name": "UserApi",
"createdDate": "2020-10-02T22:03:27+09:00",
"version": "V1",
"binaryMediaTypes": [],
"apiKeySource": "HEADER",
"endpointConfiguration": {
"types": [
"EDGE"
]
},
"tags": {},
"disableExecuteApiEndpoint": false
}
create-rest-apiのレスポンスにある、idの値(XXXXXXXXの部分)をメモしておく。
ルートリソースを確認する。(XXXXXXXXはメモしたidと置き換える)
hoge@AA:~/aws-console$ awslocal apigateway get-resources --rest-api-id XXXXXXXX --profile=localstack
{
"items": [
{
"id": "YYYYYYYY",
"path": "/"
}
]
}
get-resourcesのレスポンスにある、idの値(YYYYYYYYの部分)をメモしておく。
ルートリソースを親として、新しくリソースを作成する。(XXXXXXXX、YYYYYYYYはメモしたidと置き換える)
hoge@AA:~/aws-console$ awslocal apigateway create-resource \
--rest-api-id XXXXXXXX \
--parent-id YYYYYYYY \
--path-part {proxy+} \
--profile=localstack
{
"id": "ZZZZZZZZ",
"parentId": "YYYYYYYY",
"pathPart": "{proxy+}",
"path": "/{proxy+}"
}
create-resourceのレスポンスにある、idの値(ZZZZZZZZの部分)をメモしておく。
作成したリソースに対してメソッドを追加する。(XXXXXXXX、ZZZZZZZZはメモしたidと置き換える)
hoge@AA:~/aws-console$ awslocal apigateway put-method \
--rest-api-id XXXXXXXX \
--resource-id ZZZZZZZZ \
--http-method ANY \
--authorization-type "NONE" \
--profile=localstack
{
"httpMethod": "ANY",
"authorizationType": "NONE",
"apiKeyRequired": false
}
インテグレーションの設定に必要な、AWS Lambda関数のARNを取得する。
hoge@AA:~/aws-console$ awslocal lambda get-function --function-name users \
--query 'Configuration.FunctionArn' \
--profile=localstack
"arn:aws:lambda:us-east-1:000000000000:function:users"
get-functionで取得したARN「arn:aws:lambda:us-east-1:000000000000:function:users」をメモしておく。
インテグレーションの設定をする。[3]
(XXXXXXXX、ZZZZZZZZはメモしたidと置き換える、[ANR]はメモしたARNに置き換える。)
hoge@AA:~/aws-console$ awslocal apigateway put-integration \
--rest-api-id XXXXXXXX \
--resource-id ZZZZZZZZ \
--http-method ANY \
--type AWS_PROXY \
--integration-http-method POST \
--uri arn:aws:apigateway:us-east-1:lambda:path/2015-03-31/functions/[ANR]/invocations \
--credentials arn:aws:iam::000000000000:role/apigAwsProxyRole
{
"type": "AWS_PROXY",
"httpMethod": "POST",
"uri": "arn:aws:apigateway:us-east-1:lambda:path/2015-03-31/functions/arn:aws:lambda:us-east-1:000000000000:function:users/invocations",
"requestParameters": {},
"passthroughBehavior": "WHEN_NO_MATCH",
"cacheNamespace": "ad27c65a",
"cacheKeyParameters": []
}
デプロイする。
hoge@AA:~/aws-console$ awslocal apigateway create-deployment \
--rest-api-id XXXXXXXX \
--stage-name test \
--profile=localstack
{
"id": "AAAAAAAA",
"description": "",
"createdDate": "2020-10-02T22:23:27+09:00"
}
動作確認
API呼び出し方法
API Gateway(LocalStack)のローカルのアクセスは下記のようになる。
http://localhost:4566/restapis/<apiId>/<stageId>/_user_request_/<path>
- <apiId>はデプロイ設定のrest-api-id「XXXXXXXX」
- <stageId>はデプロイ設定のstage-name「test」
- <path>はなんでも通す設定になっている
実行例
hoge@AA:~/aws-console$ curl -X GET -s http://localhost:4566/restapis/XXXXXXXX/test/_user_request_/users | jq
{
"users": [
{
"Index": 1000,
"Tel": "0769625106",
"Birthday": "1982/02/26",
"Gender": "Female",
"Mail": "mio1094@ccfrevk.ll",
"Name": "Ishida Mio"
},
{
"Index": 1002,
"Tel": "0848254480",
"Birthday": "1992/06/20",
"Gender": "Male",
"Mail": "masaki_ishimura@kokn.qgj",
"Name": "Ishimura Masaki"
},
〜略〜
参考にしたサイト
- LocalStackでAmazon API Gateway+AWS Lambdaを動かしてみる - CLOVER🍀
- 【入門】私を苦しめたDynamoDB | フューチャー技術ブログ
- LocalStackでAWSのモックコンテナを利用する | It works for me
- ステップ 1: テーブルを作成する - Amazon DynamoDB
- 疑似個人情報生成 - 生成結果
- DynamoDBのテーブル設計時に気を付けること | It works for me
- DynamoDB の Scan でテーブルのデータを漏れなく取得する為のメモ - ようへいの日々精進XP
- DynamoDB を Python で操作する (boto3)|まくろぐ
- API Gateway で Lambda プロキシ統合を設定する - Amazon API Gateway
Discussion