前提条件
Lambdaへの権限
- Lambdaに対してフル権限があること。
- S3に対してフル権限があること。
CloudWatchへの権限 (任意)
CloudWatchに対してRead権限があること。
AWS CLI
以下のバージョンで動作確認済
- AWS CLI 1.9.15
コマンド
aws --version
aws-cli/1.9.15 Python/2.7.5 Darwin/13.4.0 botocore/1.3.15
IAM Role
''ロールが存在すること。
変数の設定
IAM_ROLE_NAME='lambdaExecution'
コマンド
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": "AROAXXXXXXXXXXXX",
"CreateDate": "2016-01-04T06:05:53Z",
"RoleName": "lambdaExecution",
"Path": "/",
"Arn": "arn:aws:iam::XXXXXXXXXXXX:role/lambdaExecution"
}
}
存在しない場合は、以下の手順で作成します。
- 準備
=======
0.1. 変数の確認
プロファイルが想定のものになっていることを確認します。
変数の確認
aws configure list
結果(例)
Name Value Type Location
---- ----- ---- --------
profile administrator-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
プロファイルが想定のものになっていることを確認します。
- 事前作業
===========
1.1. バケットの作成 (S3)
変数の設定
ORG_NAME=<組織名>
変数の設定
S3_BUCKET_NAME="${ORG_NAME}-$(date +%Y%m%d)-mybucket" \
&& echo ${S3_BUCKET_NAME}
同名のバケットが存在しないことを確認します。(存在する場合は、別の名前に変更してください。)
コマンド
aws s3 ls ${S3_BUCKET_NAME}
結果(例)
A client error (NoSuchBucket) occurred when calling the ListObjects operation: The specified bucket does not exist
コマンド
aws s3 mb s3://${S3_BUCKET_NAME}
結果(例)
make_bucket: s3://example-mybucket-20160104/
1.2. 画像のアップロード (S3)
コマンド
curl https://dzpp79ucibp5a.cloudfront.net/groups_logos/3485_normal_1405560765_jawsug-cli-logo.png > HappyFace.jpg
コマンド
aws s3 cp HappyFace.jpg s3://${S3_BUCKET_NAME}/
結果(例)
upload: ./jawsug-cli-logo.png to s3://example-mybucket-20160104/HappyFace.jpg
コマンド
aws s3 ls s3://${S3_BUCKET_NAME}/
結果(例)
2016-01-04 19:35:49 35720 HappyFace.jpg
2. Lambda関数デプロイパッケージを作成する
2.1. フォルダ作成
- フォルダ(examplefolder)を作成します。
コマンド
mkdir -p ~/tmp/examplefolder \
&& cd ~/tmp/examplefolder
2.2. コード
変数の設定
LAMBDA_FUNC_NAME='s3_get_object'
テキストエディターを開き、次のコードをコピーします。
s3_get_object.js
console.log('Loading function');
var aws = require('aws-sdk');
var s3 = new aws.S3({ apiVersion: '2006-03-01' });
exports.handler = function(event, context) {
//console.log('Received event:', JSON.stringify(event, null, 2));
// Get the object from the event and show its content type
var bucket = event.Records[0].s3.bucket.name;
var key = decodeURIComponent(event.Records[0].s3.object.key.replace(/\+/g, ' '));
var params = {
Bucket: bucket,
Key: key
};
s3.getObject(params, function(err, data) {
if (err) {
console.log(err);
var message = "Error getting object " + key + " from bucket " + bucket +
". Make sure they exist and your bucket is in the same region as this function.";
console.log(message);
context.fail(message);
} else {
console.log('CONTENT TYPE:', data.ContentType);
context.succeed(data.ContentType);
}
});
};
2.3. 圧縮
フォルダーそのものではなく、フォルダーの内容を zip 圧縮します。
これが Lambda 関数デプロイパッケージです。
コマンド
zip ${LAMBDA_FUNC_NAME}.zip ${LAMBDA_FUNC_NAME}.js
結果(例)
adding: s3_get_object.js (deflated 50%)
3. デプロイパッケージをアップロードしてテストする
3.1. Lambda関数を作成する
変数の設定
IAM_ROLE_NAME='lambdaExecution'
コマンド
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-01-04T06:05:53Z",
"RoleName": "lambdaExecution",
"Path": "/",
"Arn": "arn:aws:iam::XXXXXXXXXXXX:role/lambdaExecution"
}
}
変数の設定
IAM_ROLE_ARN=$( \
aws iam get-role \
--role-name ${IAM_ROLE_NAME} \
--query 'Role.Arn' \
--output text \
) \
&& echo ${IAM_ROLE_ARN}
コマンド
cd ~/tmp/examplefolder/ \
&& ls s3_get_object.zip
変数の確認
cat << ETX
IAM_ROLE_ARN: ${IAM_ROLE_ARN}
LAMBDA_FUNC_NAME ${LAMBDA_FUNC_NAME}
ETX
コマンド
aws lambda create-function \
--function-name ${LAMBDA_FUNC_NAME} \
--zip-file fileb://${LAMBDA_FUNC_NAME}.zip \
--role ${IAM_ROLE_ARN} \
--handler ${LAMBDA_FUNC_NAME}.handler \
--timeout 30 \
--runtime nodejs \
--memory-size 1024
結果(例)
{
"CodeSha256": "mIeNn3X046rKDb412oBVpLbm+sFIQU8CvQTyJ9Kr79s=",
"FunctionName": "s3_get_object",
"CodeSize": 1480,
"MemorySize": 1024,
"FunctionArn": "arn:aws:lambda:us-west-2:019764038158:function:s3_get_object",
"Version": "$LATEST",
"Role": "arn:aws:iam::019764038158:role/lambdaExecution",
"Timeout": 10,
"LastModified": "2016-01-04T01:34:25.994+0000",
"Handler": "s3_get_object.handler",
"Runtime": "nodejs",
"Description": ""
}
3.2. Lambda関数をテストする(手動で呼び出す)
変数の設定
FILE_DATA_LAMBDA="${LAMBDA_FUNC_NAME}-data.json" \
&& echo ${FILE_DATA_LAMBDA}
変数の確認
cat << ETX
FILE_DATA_LAMBDA: ${FILE_DATA_LAMBDA}
S3_BUCKET_NAME: ${S3_BUCKET_NAME}
ETX
コマンド
cat << EOF > ${FILE_DATA_LAMBDA}
{
"Records": [
{
"eventVersion": "2.0",
"eventTime": "1970-01-01T00:00:00.000Z",
"requestParameters": {
"sourceIPAddress": "127.0.0.1"
},
"s3": {
"configurationId": "testConfigRule",
"object": {
"eTag": "0123456789abcdef0123456789abcdef",
"sequencer": "0A1B2C3D4E5F678901",
"key": "HappyFace.jpg",
"size": 35720
},
"bucket": {
"arn": "arn:aws:s3:::${S3_BUCKET_NAME}",
"name": "${S3_BUCKET_NAME}",
"ownerIdentity": {
"principalId": "EXAMPLE"
}
},
"s3SchemaVersion": "1.0"
},
"responseElements": {
"x-amz-id-2": "EXAMPLE123/5678abcdefghijklambdaisawesome/mnopqrstuvwxyzABCDEFGH",
"x-amz-request-id": "EXAMPLE123456789"
},
"awsRegion": "us-west-2",
"eventName": "ObjectCreated:Put",
"userIdentity": {
"principalId": "EXAMPLE"
},
"eventSource": "aws:s3"
}
]
}
EOF
cat ${FILE_DATA_LAMBDA}
jsonlint -q ${FILE_DATA_LAMBDA}
- 次のLambda CLI invokeコマンドを実行して関数を呼び出します。
コマンド
aws lambda invoke \
--invocation-type Event \
--function-name ${LAMBDA_FUNC_NAME} \
--payload file://${FILE_DATA_LAMBDA} \
--log-type Tail \
outputfile.txt
変数の設定
LOG_GROUP_NAME=$( \
aws logs describe-log-groups \
--query 'logGroups[*].[logGroupName]' \
--output text
)
LOG_STREAM_NAMES=$( \
aws logs describe-log-streams \
--log-group-name "${LOG_GROUP_NAME}" \
--query 'logStreams[*].logStreamName' \
--output text
)
コマンド
echo LOG_STREAM_NAMES="'${LOG_STREAM_NAMES}'"
for i in ${LOG_STREAM_NAMES}; do
aws logs get-log-events \
--log-group-name "${LOG_GROUP_NAME}" \
--log-stream-name "$i" \
--query 'events[*].message' \
--output text
done | less
4. Lambda関数アクセスポリシーにアクセス権限追加
変数の設定
AWS_ID=$( \
aws iam get-role \
--role-name ${IAM_ROLE_NAME} \
--query 'Role.Arn' \
--output text | \
sed 's/^.*:://' | \
sed 's/:.*$//' \
) \
&& echo ${AWS_ID}
変数の確認
cat << EOF
LAMBDA_FUNC_NAME: ${LAMBDA_FUNC_NAME}
S3_BUCKET_NAME: ${S3_BUCKET_NAME}
AWS_ID: ${AWS_ID}
EOF
コマンド
aws lambda add-permission \
--function-name ${LAMBDA_FUNC_NAME} \
--statement-id some-unique-id \
--action "lambda:InvokeFunction" \
--principal s3.amazonaws.com \
--source-arn arn:aws:s3:::${S3_BUCKET_NAME} \
--source-account ${AWS_ID}
結果(例)
{
"Statement": "{\"Condition\":{\"StringEquals\":{\"AWS:SourceAccount\":\"XXXXXXXXXXXX\"},\"ArnLike\":{\"AWS:SourceArn\":\"arn:aws:s3:::opelabprj22-20160104-mybucket\"}},\"Action\":[\"lambda:InvokeFunction\"],\"Resource\":\"arn:aws:lambda:us-west-2:XXXXXXXXXXXX:function:CreateThumbnail\",\"Effect\":\"Allow\",\"Principal\":{\"Service\":\"s3.amazonaws.com\"},\"Sid\":\"some-unique-id\"}"
}
コマンド
aws lambda get-policy \
--function-name ${LAMBDA_FUNC_NAME}
結果(例)
{
"Policy": "{\"Version\":\"2012-10-17\",\"Statement\":[{\"Condition\":{\"StringEquals\":{\"AWS:SourceAccount\":\"XXXXXXXXXXXX\"},\"ArnLike\":{\"AWS:SourceArn\":\"arn:aws:s3:::opelabprj22-20160104-mybucket\"}},\"Action\":\"lambda:InvokeFunction\",\"Resource\":\"arn:aws:lambda:us-west-2:XXXXXXXXXXXX:function:CreateThumbnail\",\"Effect\":\"Allow\",\"Principal\":{\"Service\":\"s3.amazonaws.com\"},\"Sid\":\"some-unique-id\"}],\"Id\":\"default\"}"
}
5. S3バケットの設定
5.1. 通知の設定
通知設定をS3バケットに追加するときは、以下のセクションでこれが必要になります。
コマンド
LAMBDA_FUNC_ARN=$( \
aws lambda get-function-configuration \
--function-name ${LAMBDA_FUNC_NAME} \
--query 'FunctionArn' \
--output text \
) \
&& echo ${LAMBDA_FUNC_ARN}
結果
arn:aws:lambda:ap-northeast-1:XXXXXXXXXXXX:function:CreateThumbnail
変数の設定
FILE_S3_NOTIF="${S3_BUCKET_NAME}-notif.json"
コマンド
cat << EOF > ${FILE_S3_NOTIF}
{
"LambdaFunctionConfigurations": [
{
"LambdaFunctionArn": "${LAMBDA_FUNC_ARN}",
"Events": [
"s3:ObjectCreated:*"
]
}
]
}
EOF
jsonlint -q ${FILE_S3_NOTIF}
コマンド
aws s3api put-bucket-notification-configuration \
--bucket ${S3_BUCKET_NAME} \
--notification-configuration file://${FILE_S3_NOTIF}
コマンド
aws s3api get-bucket-notification-configuration \
--bucket ${S3_BUCKET_NAME}
結果
{
"LambdaFunctionConfigurations": [
{
"LambdaFunctionArn": "arn:aws:lambda:us-west-2:019764038158:function:s3getobj",
"Id": "s3getobj",
"Events": [
"s3:ObjectCreated:*"
]
}
]
}
5.2. 画像のアップロード (S3)
コマンド
curl https://dzpp79ucibp5a.cloudfront.net/groups_logos/3485_normal_1405560765_jawsug-cli-logo.png > jawsug-cli-logo.png
コマンド
aws s3 cp jawsug-cli-logo.png s3://${S3_BUCKET_NAME}/
結果(例)
upload: ./jawsug-cli-logo.png to s3://example-mybucket-20160104/jawsug-cli-logo.png
コマンド
aws s3 ls s3://${S3_BUCKET_NAME}/
結果(例)
2016-01-04 19:35:49 35720 jawsug-cli-logo.png
5.3. ログ確認
変数の設定
LOG_GROUP_NAME=$( \
aws logs describe-log-groups \
--query 'logGroups[*].[logGroupName]' \
--output text
)
LOG_STREAM_NAMES=$( \
aws logs describe-log-streams \
--log-group-name "${LOG_GROUP_NAME}" \
--query 'logStreams[*].logStreamName' \
--output text
)
コマンド
echo LOG_STREAM_NAMES="'${LOG_STREAM_NAMES}'"
for i in ${LOG_STREAM_NAMES}; do
aws logs get-log-events \
--log-group-name "${LOG_GROUP_NAME}" \
--log-stream-name "$i" \
--query 'events[*].message' \
--output text
done | less