前提条件
Lambdaへの権限
Lambdaに対してフル権限があること。
DynamoDBへの権限
DynamoDBに対して読み取り権限があること。
AWS CLI
以下のバージョンで動作確認済
- AWS CLI 1.10.47
コマンド
aws --version
結果(例):
aws-cli/1.11.34 Python/2.7.10 Darwin/15.6.0 botocore/1.4.91
バージョンが古い場合は最新版に更新しましょう。
コマンド
sudo -H pip install -U awscli
IAM Role
LambdaMicroserviceHttpEndpointRoleロールが存在すること。
- 準備
=======
0.1. リージョンの決定
変数の設定
export AWS_DEFAULT_REGION='ap-northeast-1'
0.2. プロファイルの確認
プロファイルが想定のものになっていることを確認します。
変数の確認
aws configure list
結果(例):
Name Value Type Location
---- ----- ---- --------
profile lambdaFull-prjz-mbp13 env AWS_DEFAULT_PROFILE
access_key ****************XXXX shared-credentials-file
secret_key ****************XXXX shared-credentials-file
region ap-northeast-1 env AWS_DEFAULT_REGION
0.3. DynamoDBテーブル名の指定
コマンド
DYNAMO_TABLE_NAME='microservice-http'
- 事前作業
===========
1.1. Lambda関数名の決定
変数の設定
LAMBDA_FUNC_NAME="microservice_http_endpoint-$( date '+%Y%m%d' )" \
&& echo ${LAMBDA_FUNC_NAME}
同名のLambda関数の不存在確認
コマンド
aws lambda get-function \
--function-name ${LAMBDA_FUNC_NAME}
結果(例):
A client error (ResourceNotFoundException) occurred when calling the GetFunction operation: Function not found: arn:aws:lambda:ap-northeast-1:XXXXXXXXXXXX:function:microservice_http_endpoint-20170101
1.2. IAM Roleの指定
変数の設定
IAM_ROLE_NAME='LambdaMicroserviceHttpEndpointRole'
コマンド
aws iam get-role \
--role-name ${IAM_ROLE_NAME}
結果(例):
{
"Role": {
"AssumeRolePolicyDocument": {
"Version": "2012-10-17",
"Statement": [
{
"Action": "sts:AssumeRole",
"Principal": {
"Service": "lambda.amazonaws.com"
},
"Effect": "Allow",
"Sid": ""
}
]
},
"RoleId": "AROAXXXXXXXXXXXXXXXXX",
"CreateDate": "2016-12-31T01:23:45Z",
"RoleName": "LambdaMicroserviceHttpEndpointRole",
"Path": "/",
"Arn": "arn:aws:iam::XXXXXXXXXXXX:role/LambdaMicroserviceHttpEndpointRole"
}
}
コマンド
IAM_ROLE_ARN=$( \
aws iam get-role \
--role-name ${IAM_ROLE_NAME} \
--query 'Role.Arn' \
--output text \
) \
&& echo ${IAM_ROLE_ARN}
結果(例):
arn:aws:iam::XXXXXXXXXXXX:role/LambdaMicroserviceHttpEndpointRole
1.3. Lambda関数
変数の設定
FILE_LAMBDA_FUNC="${LAMBDA_FUNC_NAME}.py"
PY_FUNC_NAME='lambda_handler'
変数の確認
cat << ETX
FILE_LAMBDA_FUNC: ${FILE_LAMBDA_FUNC}
PY_FUNC_NAME: ${PY_FUNC_NAME}
ETX
コマンド
cat << EOF > ${FILE_LAMBDA_FUNC}
from __future__ import print_function
import boto3
import json
print('Loading function')
def respond(err, res=None):
return {
'statusCode': '400' if err else '200',
'body': err.message if err else json.dumps(res),
'headers': {
'Content-Type': 'application/json',
},
}
def ${PY_FUNC_NAME}(event, context):
#print("Received event: " + json.dumps(event, indent=2))
operations = {
'DELETE': lambda dynamo, x: dynamo.delete_item(**x),
'GET': lambda dynamo, x: dynamo.scan(**x),
'POST': lambda dynamo, x: dynamo.put_item(**x),
'PUT': lambda dynamo, x: dynamo.update_item(**x),
}
operation = event['httpMethod']
if operation in operations:
payload = event['queryStringParameters'] if operation == 'GET' else json.loads(event['body'])
dynamo = boto3.resource('dynamodb').Table(payload['TableName'])
return respond(None, operations[operation](dynamo, payload))
else:
return respond(ValueError('Unsupported method "{}"'.format(operation)))
EOF
cat ${FILE_LAMBDA_FUNC}
コマンド
zip ${LAMBDA_FUNC_NAME}.zip ${FILE_LAMBDA_FUNC}
結果(例):
adding: microservice_http_endpoint-20170101.py (deflated 43%)
- Lambda関数の作成
===================
変数の設定
LAMBDA_FUNC_DESC='Microservice HTTP Endpoint 20170101'
LAMBDA_RUNTIME='python2.7'
LAMBDA_HANDLER="${LAMBDA_FUNC_NAME}.${PY_FUNC_NAME}"
FILE_LAMBDA_ZIP="${LAMBDA_FUNC_NAME}.zip"
変数の確認
cat << ETX
LAMBDA_FUNC_NAME: ${LAMBDA_FUNC_NAME}
LAMBDA_FUNC_DESC: "${LAMBDA_FUNC_DESC}"
LAMBDA_RUNTIME: ${LAMBDA_RUNTIME}
FILE_LAMBDA_ZIP ${FILE_LAMBDA_ZIP}
IAM_ROLE_ARN: ${IAM_ROLE_ARN}
LAMBDA_HANDLER: ${LAMBDA_HANDLER}
ETX
コマンド
aws lambda create-function \
--function-name ${LAMBDA_FUNC_NAME} \
--description "${LAMBDA_FUNC_DESC}" \
--zip-file fileb://${FILE_LAMBDA_ZIP} \
--runtime ${LAMBDA_RUNTIME} \
--role ${IAM_ROLE_ARN} \
--handler ${LAMBDA_HANDLER}
結果(例):
{
"CodeSha256": "+edf74XvKEs4oYFOflSRJydF5n5F0SEL34ujm7+kAPk=",
"FunctionName": "microservice_http_endpoint-20170101",
"CodeSize": 726,
"MemorySize": 128,
"FunctionArn": "arn:aws:lambda:ap-northeast-1:XXXXXXXXXXXX:function:microservice_http_endpoint-20170101",
"Version": "$LATEST",
"Role": "arn:aws:iam::XXXXXXXXXXXX:role/LambdaMicroserviceHttpEndpointRole",
"Timeout": 3,
"LastModified": "2016-12-31T01:23:45.678+0000",
"Handler": "microservice_http_endpoint-20170101.lambda_handler",
"Runtime": "python2.7",
"Description": "Microservice HTTP Endpoint 20170101"
}
コマンド
aws lambda get-function \
--function-name ${LAMBDA_FUNC_NAME}
結果(例):
{
"Code": {
"RepositoryType": "S3",
"Location": "https://awslambda-ap-ne-1-tasks.s3-ap-northeast-1.amazonaws.com/snapshots/XXXXXXXXXXXX/microservice_http_endpoint-20170101-xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx"
},
"Configuration": {
"Version": "$LATEST",
"CodeSha256": "+edf74XvKEs4oYFOflSRJydF5n5F0SEL34ujm7+kAPk=",
"FunctionName": "microservice_http_endpoint-20170101",
"MemorySize": 128,
"CodeSize": 350,
"FunctionArn": "arn:aws:lambda:ap-northeast-1:XXXXXXXXXXXX:function:microservice_http_endpoint-20170101",
"Handler": "microservice_http_endpoint-20170101.lambda_handler",
"Role": "arn:aws:iam::XXXXXXXXXXXX:role/LambdaMicroserviceHttpEndpointRole",
"Timeout": 3,
"LastModified": "2016-12-31T01:23:45.678+0000",
"Runtime": "python2.7",
"Description": "Microservice HTTP Endpoint 20170101"
}
}
- Lambda関数の動作確認
=======================
3.1. GET
変数の設定
FILE_INPUT="${LAMBDA_FUNC_NAME}-get.json" \
&& echo ${FILE_INPUT}
コマンド
cat << EOF > ${FILE_INPUT}
{
"httpMethod": "GET",
"queryStringParameters": {
"TableName": "microservice-http"
}
}
EOF
cat ${FILE_INPUT}
JSONファイルを作成したら、フォーマットが壊れてないか必ず確認します。
コマンド
jsonlint -q ${FILE_INPUT}
エラーが出力されなければOKです。
変数の設定
FILE_OUTPUT_LAMBDA="${LAMBDA_FUNC_NAME}-out.txt"
FILE_LOG_LAMBDA="${LAMBDA_FUNC_NAME}-$(date +%Y%m%d%H%M%S).log"
変数の確認
cat << ETX
LAMBDA_FUNC_NAME: ${LAMBDA_FUNC_NAME}
FILE_INPUT: ${FILE_INPUT}
FILE_OUTPUT_LAMBDA: ${FILE_OUTPUT_LAMBDA}
FILE_LOG_LAMBDA: ${FILE_LOG_LAMBDA}
ETX
コマンド
aws lambda invoke \
--function-name ${LAMBDA_FUNC_NAME} \
--log-type Tail \
--payload file://${FILE_INPUT} \
${FILE_OUTPUT_LAMBDA} \
> ${FILE_LOG_LAMBDA}
コマンド
cat ${FILE_LOG_LAMBDA} \
| jp.py 'StatusCode'
結果(例):
200
コマンド
cat ${FILE_OUTPUT_LAMBDA}
結果(例):
{"body": "{\"Count\": 1, \"Items\": [{\"Description\": \"sample\", \"Name\": \"taro\"}], \"ScannedCount\": 1, \"ResponseMetadata\": {\"RetryAttempts\": 0, \"HTTPStatusCode\": 200, \"RequestId\": \"GJTSB9TE10U7O0SS9JC9050FD7VV4KQNSO5AEMVJF66Q9ASUAAJG\", \"HTTPHeaders\": {\"x-amzn-requestid\": \"GJTSB9TE10U7O0SS9JC9050FD7VV4KQNSO5AEMVJF66Q9ASUAAJG\", \"content-length\": \"89\", \"server\": \"Server\", \"connection\": \"keep-alive\", \"x-amz-crc32\": \"2586798783\", \"date\": \"Sat, 31 Dec 2016 13:22:26 GMT\", \"content-type\": \"application/x-amz-json-1.0\"}}}", "headers": {"Content-Type": "application/json"}, "statusCode": "200"}
コマンド
aws dynamodb scan \
--table-name ${DYNAMO_TABLE_NAME}
結果(例):
{
"Count": 1,
"Items": [
{
"Description": {
"S": "sample"
},
"Name": {
"S": "taro"
}
}
],
"ScannedCount": 1,
"ConsumedCapacity": null
}
3.2. POST
変数の設定
FILE_INPUT="${LAMBDA_FUNC_NAME}-post.json" \
&& echo ${FILE_INPUT}
コマンド
cat << EOF > ${FILE_INPUT}
{
"httpMethod": "POST",
"body": "{\"TableName\":\"microservice-http\",\"Item\":{\"Name\":\"jiro\",\"Description\":\"sample2\"}}"
}
EOF
cat ${FILE_INPUT}
JSONファイルを作成したら、フォーマットが壊れてないか必ず確認します。
コマンド
jsonlint -q ${FILE_INPUT}
エラーが出力されなければOKです。
変数の設定
FILE_OUTPUT_LAMBDA="${LAMBDA_FUNC_NAME}-out.txt"
FILE_LOG_LAMBDA="${LAMBDA_FUNC_NAME}-$(date +%Y%m%d%H%M%S).log"
変数の確認
cat << ETX
LAMBDA_FUNC_NAME: ${LAMBDA_FUNC_NAME}
FILE_INPUT: ${FILE_INPUT}
FILE_OUTPUT_LAMBDA: ${FILE_OUTPUT_LAMBDA}
FILE_LOG_LAMBDA: ${FILE_LOG_LAMBDA}
ETX
コマンド
aws lambda invoke \
--function-name ${LAMBDA_FUNC_NAME} \
--log-type Tail \
--payload file://${FILE_INPUT} \
${FILE_OUTPUT_LAMBDA} \
> ${FILE_LOG_LAMBDA}
コマンド
cat ${FILE_LOG_LAMBDA} \
| jp.py 'StatusCode'
結果(例):
200
コマンド
cat ${FILE_OUTPUT_LAMBDA}
結果(例):
{"body": "{\"ResponseMetadata\": {\"RetryAttempts\": 0, \"HTTPStatusCode\": 200, \"RequestId\": \"C96O73JS0QB4NRH3U5D30JE9GRVV4KQNSO5AEMVJF66Q9ASUAAJG\", \"HTTPHeaders\": {\"x-amzn-requestid\": \"C96O73JS0QB4NRH3U5D30JE9GRVV4KQNSO5AEMVJF66Q9ASUAAJG\", \"content-length\": \"2\", \"server\": \"Server\", \"connection\": \"keep-alive\", \"x-amz-crc32\": \"2745614147\", \"date\": \"Sat, 31 Dec 2016 13:57:18 GMT\", \"content-type\": \"application/x-amz-json-1.0\"}}}", "headers": {"Content-Type": "application/json"}, "statusCode": "200"}
コマンド
aws dynamodb scan \
--table-name ${DYNAMO_TABLE_NAME}
結果(例):
{
"Count": 2,
"Items": [
{
"Description": {
"S": "sample2"
},
"Name": {
"S": "jiro"
}
},
{
"Description": {
"S": "sample"
},
"Name": {
"S": "taro"
}
}
],
"ScannedCount": 2,
"ConsumedCapacity": null
}
3.3. DELETE
変数の設定
FILE_INPUT="${LAMBDA_FUNC_NAME}-delete.json" \
&& echo ${FILE_INPUT}
コマンド
cat << EOF > ${FILE_INPUT}
{
"httpMethod": "DELETE",
"body": "{\"TableName\":\"microservice-http\",\"Key\":{\"Name\":\"jiro\"}}"
}
EOF
cat ${FILE_INPUT}
JSONファイルを作成したら、フォーマットが壊れてないか必ず確認します。
コマンド
jsonlint -q ${FILE_INPUT}
エラーが出力されなければOKです。
変数の設定
FILE_OUTPUT_LAMBDA="${LAMBDA_FUNC_NAME}-out.txt"
FILE_LOG_LAMBDA="${LAMBDA_FUNC_NAME}-$(date +%Y%m%d%H%M%S).log"
変数の確認
cat << ETX
LAMBDA_FUNC_NAME: ${LAMBDA_FUNC_NAME}
FILE_INPUT: ${FILE_INPUT}
FILE_OUTPUT_LAMBDA: ${FILE_OUTPUT_LAMBDA}
FILE_LOG_LAMBDA: ${FILE_LOG_LAMBDA}
ETX
コマンド
aws lambda invoke \
--function-name ${LAMBDA_FUNC_NAME} \
--log-type Tail \
--payload file://${FILE_INPUT} \
${FILE_OUTPUT_LAMBDA} \
> ${FILE_LOG_LAMBDA}
コマンド
cat ${FILE_LOG_LAMBDA} \
| jp.py 'StatusCode'
結果(例):
200
コマンド
cat ${FILE_OUTPUT_LAMBDA}
結果(例):
{"body": "{\"ResponseMetadata\": {\"RetryAttempts\": 0, \"HTTPStatusCode\": 200, \"RequestId\": \"R43F60O4UNN5B1FR3UKFR25R43VV4KQNSO5AEMVJF66Q9ASUAAJG\", \"HTTPHeaders\": {\"x-amzn-requestid\": \"R43F60O4UNN5B1FR3UKFR25R43VV4KQNSO5AEMVJF66Q9ASUAAJG\", \"content-length\": \"2\", \"server\": \"Server\", \"connection\": \"keep-alive\", \"x-amz-crc32\": \"2745614147\", \"date\": \"Sat, 31 Dec 2016 13:58:51 GMT\", \"content-type\": \"application/x-amz-json-1.0\"}}}", "headers": {"Content-Type": "application/json"}, "statusCode": "200"}
コマンド
aws dynamodb scan \
--table-name ${DYNAMO_TABLE_NAME}
結果(例):
{
"Count": 1,
"Items": [
{
"Description": {
"S": "sample"
},
"Name": {
"S": "taro"
}
}
],
"ScannedCount": 1,
"ConsumedCapacity": null
}