☁
12/03 AWS Lambda with AWS SAM CLI
この記事は、Serverless Hello World Advent Calendar 2020の3日目です。
AWS SAM CLIインストール
Linux への AWS SAM CLI のインストールにしたがって導入します。
% sam --version
SAM CLI, version 1.13.1
プロジェクトの作成
sam init
でプロジェクトを作成します。
すでにOCIコンテナ対応が入っていますね。
% sam init
Which template source would you like to use?
1 - AWS Quick Start Templates
2 - Custom Template Location
Choice: 1
What package type would you like to use?
1 - Zip (artifact is a zip uploaded to S3)
2 - Image (artifact is an image uploaded to an ECR image repository)
Package type: 1
Which runtime would you like to use?
1 - nodejs12.x
2 - python3.8
3 - ruby2.7
4 - go1.x
5 - java11
6 - dotnetcore3.1
7 - nodejs10.x
8 - python3.7
9 - python3.6
10 - python2.7
11 - ruby2.5
12 - java8.al2
13 - java8
14 - dotnetcore2.1
Runtime: 1
Project name [sam-app]: adventcalendar03
Cloning app templates from https://github.com/aws/aws-sam-cli-app-templates
AWS quick start application templates:
1 - Hello World Example
2 - Step Functions Sample App (Stock Trader)
3 - Quick Start: From Scratch
4 - Quick Start: Scheduled Events
5 - Quick Start: S3
6 - Quick Start: SNS
7 - Quick Start: SQS
8 - Quick Start: Web Backend
Template selection: 1
-----------------------
Generating application:
-----------------------
Name: adventcalendar03
Runtime: nodejs12.x
Dependency Manager: npm
Application Template: hello-world
Output Directory: .
Next steps can be found in the README file at ./adventcalendar03/README.md
生成されたファイルの確認
template.yaml
では、Lambda関数とそれを公開するAPIイベントが設定されています。一見長いですが、半分近くは登録したAWSリソースの情報を出力表示するためのOutputs節です。
AWSTemplateFormatVersion: '2010-09-09'
Transform: AWS::Serverless-2016-10-31
Description: >
adventcalendar03
Sample SAM Template for adventcalendar03
# More info about Globals: https://github.com/awslabs/serverless-application-model/blob/master/docs/globals.rst
Globals:
Function:
Timeout: 3
Resources:
HelloWorldFunction:
Type: AWS::Serverless::Function # More info about Function Resource: https://github.com/awslabs/serverless-application-model/blob/master/versions/2016-10-31.md#awsserverlessfunction
Properties:
CodeUri: hello-world/
Handler: app.lambdaHandler
Runtime: nodejs12.x
Events:
HelloWorld:
Type: Api # More info about API Event Source: https://github.com/awslabs/serverless-application-model/blob/master/versions/2016-10-31.md#api
Properties:
Path: /hello
Method: get
Outputs:
# ServerlessRestApi is an implicit API created out of Events key under Serverless::Function
# Find out more about other implicit resources you can reference within SAM
# https://github.com/awslabs/serverless-application-model/blob/master/docs/internals/generated_resources.rst#api
HelloWorldApi:
Description: "API Gateway endpoint URL for Prod stage for Hello World function"
Value: !Sub "https://${ServerlessRestApi}.execute-api.${AWS::Region}.amazonaws.com/Prod/hello/"
HelloWorldFunction:
Description: "Hello World Lambda Function ARN"
Value: !GetAtt HelloWorldFunction.Arn
HelloWorldFunctionIamRole:
Description: "Implicit IAM Role created for Hello World function"
Value: !GetAtt HelloWorldFunctionRole.Arn
hello-world/app.js
が関数本体です。
// const axios = require('axios')
// const url = 'http://checkip.amazonaws.com/';
let response;
/**
*
* Event doc: https://docs.aws.amazon.com/apigateway/latest/developerguide/set-up-lambda-proxy-integrations.html#api-gateway-simple-proxy-for-lambda-input-format
* @param {Object} event - API Gateway Lambda Proxy Input Format
*
* Context doc: https://docs.aws.amazon.com/lambda/latest/dg/nodejs-prog-model-context.html
* @param {Object} context
*
* Return doc: https://docs.aws.amazon.com/apigateway/latest/developerguide/set-up-lambda-proxy-integrations.html
* @returns {Object} object - API Gateway Lambda Proxy Output Format
*
*/
exports.lambdaHandler = async (event, context) => {
try {
// const ret = await axios(url);
response = {
'statusCode': 200,
'body': JSON.stringify({
message: 'hello world',
// location: ret.data.trim()
})
}
} catch (err) {
console.log(err);
return err;
}
return response
};
hello-world/tests/unit/test-handler.js
にユニットテストが生成されているのが評価高いですね。最近多いJestではなくChaiベースです。
'use strict';
const app = require('../../app.js');
const chai = require('chai');
const expect = chai.expect;
var event, context;
describe('Tests index', function () {
it('verifies successful response', async () => {
const result = await app.lambdaHandler(event, context)
expect(result).to.be.an('object');
expect(result.statusCode).to.equal(200);
expect(result.body).to.be.an('string');
let response = JSON.parse(result.body);
expect(response).to.be.an('object');
expect(response.message).to.be.equal("hello world");
// expect(response.location).to.be.an("string");
});
});
ローカル環境での動作確認 (関数単体)
AWS SAM CLIではDockerを使って関数の実行環境をローカル環境上でエミュレーションできます。
% cd adventcalendar03
% sam local invoke "HelloWorldFunction" -e events/event.json
Invoking app.lambdaHandler (nodejs12.x)
Image was not found.
Building image...........................................................................................................................................................................................................................
Skip pulling image and use local one: amazon/aws-sam-cli-emulation-image-nodejs12.x:rapid-1.13.1.
Mounting /home/masa/work/serverless-helloworld/03/adventcalendar03/hello-world as /var/task:ro,delegated inside runtime container
START RequestId: b1371030-63c0-4a3d-a450-d1a743585468 Version: $LATEST
END RequestId: b1371030-63c0-4a3d-a450-d1a743585468
REPORT RequestId: b1371030-63c0-4a3d-a450-d1a743585468 Init Duration: 0.23 ms Duration: 150.02 ms Billed Duration: 200 ms Memory Size: 128 MB Max Memory Used: 128 MB
{"statusCode":200,"body":"{\"message\":\"hello world\"}"}%
AWS上であればCloudWatch Logsに出力されるログと、関数の実行結果が表示されました。
ローカル環境での動作確認 (API Gateway経由)
関数単体で実行するだけでなく、API Gatewayもローカルで起動してそこを経由した動作確認もできます。
% sam local start-api
Mounting HelloWorldFunction at http://127.0.0.1:3000/hello [GET]
You can now browse to the above endpoints to invoke your functions. You do not need to restart/reload SAM CLI while working on your functions, changes will be reflected instantly/automatically. You only need to restart SAM CLI if you update your AWS SAM template
2020-12-04 00:51:25 * Running on http://127.0.0.1:3000/ (Press CTRL+C to quit)
別のターミナルからリクエストを送信してみます。
% curl -v http://127.0.0.1:3000/hello
* Trying 127.0.0.1:3000...
* TCP_NODELAY set
* Connected to 127.0.0.1 (127.0.0.1) port 3000 (#0)
> GET /hello HTTP/1.1
> Host: 127.0.0.1:3000
> User-Agent: curl/7.68.0
> Accept: */*
>
* Mark bundle as not supporting multiuse
* HTTP 1.0, assume close after body
< HTTP/1.0 200 OK
< Content-Type: application/json
< Content-Length: 25
< Server: Werkzeug/1.0.1 Python/3.8.6
< Date: Thu, 03 Dec 2020 15:51:38 GMT
<
* Closing connection 0
{"message":"hello world"}%
sam local start-api
した方のターミナルにはログが表示されています。
2020-12-04 00:51:34 127.0.0.1 - - [04/Dec/2020 00:51:34] "GET /api HTTP/1.1" 403 -
Invoking app.lambdaHandler (nodejs12.x)
Skip pulling image and use local one: amazon/aws-sam-cli-emulation-image-nodejs12.x:rapid-1.13.1.
Mounting /home/masa/work/serverless-helloworld/03/adventcalendar03/hello-world as /var/task:ro,delegated inside runtime container
START RequestId: c434e64a-c280-40ef-9087-d34d9c925275 Version: $LATEST
END RequestId: c434e64a-c280-40ef-9087-d34d9c925275
REPORT RequestId: c434e64a-c280-40ef-9087-d34d9c925275 Init Duration: 0.51 ms Duration: 138.93 ms Billed Duration: 200 ms Memory Size: 128 MB Max Memory Used: 128 MB
No Content-Type given. Defaulting to 'application/json'.
2020-12-04 00:51:38 127.0.0.1 - - [04/Dec/2020 00:51:38] "GET /hello HTTP/1.1" 200 -
デプロイ
AWSにデプロイします。
初回はデプロイのために必要な情報を入力するため--guided
オプションを付けます。入力内容はsamconfig.toml
に保存されるため2度目からは不要です。
% sam deploy --guided
Configuring SAM deploy
======================
Looking for config file [samconfig.toml] : Not found
Setting default arguments for 'sam deploy'
=========================================
Stack Name [sam-app]: adventcalendar03
AWS Region [us-east-1]: ap-northeast-1
#Shows you resources changes to be deployed and require a 'Y' to initiate deploy
Confirm changes before deploy [y/N]:
#SAM needs permission to be able to create roles to connect to the resources in your template
Allow SAM CLI IAM role creation [Y/n]:
HelloWorldFunction may not have authorization defined, Is this okay? [y/N]: y
Save arguments to configuration file [Y/n]:
SAM configuration file [samconfig.toml]:
SAM configuration environment [default]:
Looking for resources needed for deployment: Found!
Managed S3 bucket: aws-sam-cli-managed-default-samclisourcebucket-3gtctbms54wr
A different default S3 bucket can be set in samconfig.toml
Saved arguments to config file
Running 'sam deploy' for future deployments will use the parameters saved above.
The above parameters can be changed by modifying samconfig.toml
Learn more about samconfig.toml syntax at
https://docs.aws.amazon.com/serverless-application-model/latest/developerguide/serverless-sam-cli-config.html
Uploading to adventcalendar03/d40748b23cc2b52639ac30cbe755a890 1510 / 1510.0 (100.00%)
Deploying with following values
===============================
Stack name : adventcalendar03
Region : ap-northeast-1
Confirm changeset : False
Deployment s3 bucket : aws-sam-cli-managed-default-samclisourcebucket-3gtctbms54wr
Capabilities : ["CAPABILITY_IAM"]
Parameter overrides : {}
Signing Profiles : {}
Initiating deployment
=====================
HelloWorldFunction may not have authorization defined.
Uploading to adventcalendar03/8938c1ff6b9bbd55bd210f5b20dde7fe.template 1116 / 1116.0 (100.00%)
Waiting for changeset to be created..
CloudFormation stack changeset
-------------------------------------------------------------------------------------------------
Operation LogicalResourceId ResourceType Replacement
-------------------------------------------------------------------------------------------------
+ Add HelloWorldFunctionHell AWS::Lambda::Permissio N/A
oWorldPermissionProd n
+ Add HelloWorldFunctionRole AWS::IAM::Role N/A
+ Add HelloWorldFunction AWS::Lambda::Function N/A
+ Add ServerlessRestApiDeplo AWS::ApiGateway::Deplo N/A
yment47fc2d5f9d yment
+ Add ServerlessRestApiProdS AWS::ApiGateway::Stage N/A
tage
+ Add ServerlessRestApi AWS::ApiGateway::RestA N/A
pi
-------------------------------------------------------------------------------------------------
Changeset created successfully. arn:aws:cloudformation:ap-northeast-1:XXXXXXXXXXXX:changeSet/samcli-deploy1607011170/c6bf5c9a-823a-423a-8171-e441ca22ad66
2020-12-04 00:59:41 - Waiting for stack create/update to complete
CloudFormation events from changeset
-------------------------------------------------------------------------------------------------
ResourceStatus ResourceType LogicalResourceId ResourceStatusReason
-------------------------------------------------------------------------------------------------
CREATE_IN_PROGRESS AWS::IAM::Role HelloWorldFunctionRole -
CREATE_IN_PROGRESS AWS::IAM::Role HelloWorldFunctionRole Resource creation
Initiated
CREATE_COMPLETE AWS::IAM::Role HelloWorldFunctionRole -
CREATE_IN_PROGRESS AWS::Lambda::Function HelloWorldFunction -
CREATE_IN_PROGRESS AWS::Lambda::Function HelloWorldFunction Resource creation
Initiated
CREATE_COMPLETE AWS::Lambda::Function HelloWorldFunction -
CREATE_IN_PROGRESS AWS::ApiGateway::RestA ServerlessRestApi -
pi
CREATE_IN_PROGRESS AWS::ApiGateway::RestA ServerlessRestApi Resource creation
pi Initiated
CREATE_COMPLETE AWS::ApiGateway::RestA ServerlessRestApi -
pi
CREATE_IN_PROGRESS AWS::ApiGateway::Deplo ServerlessRestApiDeplo -
yment yment47fc2d5f9d
CREATE_IN_PROGRESS AWS::Lambda::Permissio HelloWorldFunctionHell Resource creation
n oWorldPermissionProd Initiated
CREATE_IN_PROGRESS AWS::Lambda::Permissio HelloWorldFunctionHell -
n oWorldPermissionProd
CREATE_COMPLETE AWS::ApiGateway::Deplo ServerlessRestApiDeplo -
yment yment47fc2d5f9d
CREATE_IN_PROGRESS AWS::ApiGateway::Deplo ServerlessRestApiDeplo Resource creation
yment yment47fc2d5f9d Initiated
CREATE_IN_PROGRESS AWS::ApiGateway::Stage ServerlessRestApiProdS -
tage
CREATE_IN_PROGRESS AWS::ApiGateway::Stage ServerlessRestApiProdS Resource creation
tage Initiated
CREATE_COMPLETE AWS::ApiGateway::Stage ServerlessRestApiProdS -
tage
CREATE_COMPLETE AWS::Lambda::Permissio HelloWorldFunctionHell -
n oWorldPermissionProd
CREATE_COMPLETE AWS::CloudFormation::S adventcalendar03 -
tack
-------------------------------------------------------------------------------------------------
CloudFormation outputs from deployed stack
-------------------------------------------------------------------------------------------------
Outputs
-------------------------------------------------------------------------------------------------
Key HelloWorldFunctionIamRole
Description Implicit IAM Role created for Hello World function
Value
arn:aws:iam::XXXXXXXXXXXX:role/adventcalendar03-HelloWorldFunctionRole-1IW4M6LIINSG6
Key HelloWorldApi
Description API Gateway endpoint URL for Prod stage for Hello World function
Value https://ycl8rpimeg.execute-api.ap-northeast-1.amazonaws.com/Prod/hello/
Key HelloWorldFunction
Description Hello World Lambda Function ARN
Value arn:aws:lambda:ap-
northeast-1:XXXXXXXXXXXX:function:adventcalendar03-HelloWorldFunction-1OL861863RRDY
-------------------------------------------------------------------------------------------------
Successfully created/updated stack - adventcalendar03 in ap-northeast-1
動作確認
ではさっそく叩いてみます。
% curl -v https://ycl8rpimeg.execute-api.ap-northeast-1.amazonaws.com/Prod/hello/
...(省略)...
* Using HTTP2, server supports multi-use
* Connection state changed (HTTP/2 confirmed)
* Copying HTTP/2 data in stream buffer to connection buffer after upgrade: len=0
* Using Stream ID: 1 (easy handle 0x555b6c256db0)
> GET /Prod/hello/ HTTP/2
> Host: ycl8rpimeg.execute-api.ap-northeast-1.amazonaws.com
> user-agent: curl/7.68.0
> accept: */*
>
* Connection state changed (MAX_CONCURRENT_STREAMS == 128)!
< HTTP/2 200
< content-type: application/json
< content-length: 25
< date: Thu, 03 Dec 2020 16:06:00 GMT
< x-amzn-requestid: 3af4e0fd-6112-4a94-b2c4-5050e6977251
< x-amz-apigw-id: W-70OFFltjMFZmA=
< x-amzn-trace-id: Root=1-5fc90ce7-5cf15a065808962753bbae65;Sampled=0
< x-cache: Miss from cloudfront
< via: 1.1 d930c4e4b6bd1abceb94d9d7f03e8e5f.cloudfront.net (CloudFront)
< x-amz-cf-pop: NRT12-C3
< x-amz-cf-id: BVYMQFeXTH4mQDXsO7FWSO6TEmAdhFd2T2WG0bcBUt2uOg9wA-f0eg==
<
* Connection #0 to host ycl8rpimeg.execute-api.ap-northeast-1.amazonaws.com left intact
{"message":"hello world"}%
無事動いていることが確認できました。
Discussion