AWS SAM(Serverless Application Model)
は、CloudFormation
をサーバーレスアプリケーションで利用しやすくなるように変形したものです。ここでは、sam init
で生成されるサンプルアプリケーションをもとに動作確認を行います。( API Gateway
のリクエストをトリガーに、Lambda関数
が実行されます。)
AWS SAM CLIをインストール
pip(Pythonのパーケージマネージャ)
経由で AWS SAM CLI
をインストールできます。
Pyenv経由でPythonをインストール済みです。
$ python -V
Python 3.6.5
$
$ pip -V
pip 9.0.3 from /Users/xxxx/.pyenv/versions/3.6.5/lib/python3.6/site-packages (python 3.6)
$ pip install aws-sam-cli
AWS SAM CLI
をインストールできました。
$ sam --help
Usage: sam [OPTIONS] COMMAND [ARGS]...
AWS Serverless Application Model (SAM) CLI
The AWS Serverless Application Model extends AWS CloudFormation to provide
a simplified way of defining the Amazon API Gateway APIs, AWS Lambda
functions, and Amazon DynamoDB tables needed by your serverless
application. You can find more in-depth guide about the SAM specification
here: https://github.com/awslabs/serverless-application-model.
Options:
--debug Turn on debug logging to print debug message generated by SAM
CLI.
--version Show the version and exit.
--info
--help Show this message and exit.
Commands:
local Run your Serverless application locally for...
build Build your Lambda function code
deploy Deploy an AWS SAM application. This is an alias for 'aws
cloudformation deploy'.
validate Validate an AWS SAM template.
init Initialize a serverless application with a...
logs Fetch logs for a function
package Package an AWS SAM application. This is an alias for 'aws
cloudformation package'.
publish Publish a packaged AWS SAM template to the AWS Serverless
Application Repository.
アプリケーションの作成
サンプルアプリを作成
( sam init )
sam init
でサンプルアプリを作成できます。
今回はランタイムに node.js
を利用したいので以下のように実行します。
$ sam init --runtime nodejs8.10
[+] Initializing project structure...
Project generated: ./sam-app
Steps you can take next within the project folder
===================================================
[*] Invoke Function: sam local invoke HelloWorldFunction --event event.json
[*] Start API Gateway locally: sam local start-api
Read sam-app/README.md for further instructions
[*] Project initialization is now complete
以下ファイルが生成されていました。
sam-app/
├── hello-world
│ ├── tests
│ │ └── unit
│ │ └── test-handler.js // ユニットテスト
│ ├── app.js // Lambda関数のソースコード
│ └── package.json
├── README.md
├── event.json // Lambdaに送られる疑似イベント(API Gateway)
└── template.yaml // SAMテンプレート
event.json
は、ローカルでテストする際に活用できます。
app.js
( Lambda関数のソースコード )
message: 'hello world'
というレスポンスを返すLambda関数のようです。
// 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
};
template.yaml
( SAMテンプレート )
AWSTemplateFormatVersion: '2010-09-09'
Transform: AWS::Serverless-2016-10-31
Description: >
sam-app
Sample SAM Template for sam-app
# 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: nodejs8.10
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
プロパティについて
関数を追加したい場合、Resources
配下に設定を追加します。
Resources.HelloWorldFunction.Properties
配下の設定は以下のようになります。
プロパティ | 概要 |
---|---|
CodeUri | Lambda関数のソースが存在するフォルダ指定します。 |
Handler | 関数を指定します。 (今回は、 app.jsファイル の lambdaHandler を指定しています。) |
Events | 関数が起動されるイベントを設定します。 (今回は、APIで起動されるように指定しています。) |
詳しくは、下記ページで確認できます。
CloudFormationについて
SAM
は CloudFormationテンプレート
の拡張版なので、CloudFormation
の知識も必要です。CloudFormation
については下記ページで取り上げています。
サンプルテンプレートについて
サンプルテンプレートの情報も役に立ちます。
ローカルテスト
指定Lambda関数を実行
( sam local invoke )
sam local invoke
でLambda関数を指定して、ローカルテストを実行できます。
$ sam local invoke HelloWorldFunction --event event.json --region ap-northeast-1
2019-01-03 11:15:26 Invoking app.lambdaHandler (nodejs8.10)
Fetching lambci/lambda:nodejs8.10 Docker container image......................(省略)
2019-01-03 11:23:30 Mounting /xxxx/sam-app/hello-world as /var/task:ro inside runtime container
START RequestId: xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx Version: $LATEST
END RequestId: xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx
REPORT RequestId: xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx Duration: 11.64 ms Billed Duration: 100 ms Memory Size: 128 MB Max Memory Used: 31 MB
{"statusCode":200,"body":"{\"message\":\"hello world\"}"}
Dockerのコンテナイメージがダウンロードされて、指定したLambda関数が実行されました。
ローカルAPI Gatewayの起動
( sam local start-api )
sam local start-api
を実行すると、ローカル上でAPI Gatewayを起動できます。
$ sam local start-api --region ap-northeast-1 --port 6000
2019-01-03 11:45:42 Mounting HelloWorldFunction at http://127.0.0.1:6000/hello [GET]
2019-01-03 11:45:42 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
2019-01-03 11:45:42 * Running on http://127.0.0.1:6000/ (Press CTRL+C to quit)
curlでリクエストしてみます。
$ curl http://127.0.0.1:6000/hello
{"message":"hello world"}
デプロイ
認証情報
デプロイ時、AWSリソースの作成・管理を行う権限を持ったIAMユーザーが必要です。
ここでは、wakuwaku-sam-admin
というプロファイル情報を利用します。
$ cat ~/.aws/credentials
[wakuwaku-sam-admin]
aws_access_key_id = xxxxxxxxxxxxxxxxxxxxxxx
aws_secret_access_key = xxxxxxxxxxxxxxxxxxxxxxx
region = ap-northeast-1
テンプレートを検証
( sam validate )
sam validate
でテンプレートを検証できます。
$ env AWS_DEFAULT_REGION=ap-northeast-1 sam validate --profile wakuwaku-sam-admin
2019-01-03 13:37:14 Found credentials in shared credentials file: ~/.aws/credentials
/xxxx/sam-app/template.yaml is a valid SAM Template
ただ、sam validate
を実行すると、 AttributeError: 'NoneType' object has no attribute 'lower'
というエラーがでたので、下記 issueを参考に env AWS_DEFAULT_REGION=ap-northeast-1
をつけて実行しています。
https://github.com/awslabs/aws-sam-cli/issues/442
S3バケットを作成
( aws s3 mb )
AWS CLI
でS3バケットを作成します。
$ aws s3 mb s3://sample-sam-hello-world --profile wakuwaku-sam-admin
make_bucket: sample-sam-hello-world
$
$ aws s3 ls --profile wakuwaku-sam-admin
2019-01-03 13:53:02 sample-sam-hello-world
パッケージ化してS3にアップロード
( sam package )
下記コマンドを実行します。
sam package \
--output-template-file packaged.yaml \
--s3-bucket sample-sam-hello-world \
--profile wakuwaku-sam-admin
以下、実行結果です。aws cloudformationコマンド
が実行されていることがわかります。
$ sam package \
> --output-template-file packaged.yaml \
> --s3-bucket sample-sam-hello-world \
> --profile wakuwaku-sam-admin
Uploading to xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx 1508 / 1508.0 (100.00%)
Successfully packaged artifacts and wrote output template to file packaged.yaml.
Execute the following command to deploy the packaged template
aws cloudformation deploy --template-file /xxxx/sam-app/packaged.yaml --stack-name <YOUR STACK NAME>
S3にアップロードされています。
$ aws s3 ls s3://sample-sam-hello-world --profile wakuwaku-sam-admin
2019-01-03 13:58:42 1508 xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx
デプロイ
( sam deploy )
下記コマンドを実行します。
sam deploy \
--template-file packaged.yaml \
--stack-name sam-app \
--capabilities CAPABILITY_IAM \
--profile wakuwaku-sam-admin
以下、実行結果です。
$ sam deploy \
> --template-file packaged.yaml \
> --stack-name sam-app \
> --capabilities CAPABILITY_IAM \
> --profile wakuwaku-sam-admin
Waiting for changeset to be created..
Waiting for stack create/update to complete
Successfully created/updated stack - sam-app
作成されたリソースを確認
( aws cloudformation list-stack-resources )
管理画面から確認できます。
以下コマンドでも確認できます。
aws cloudformation list-stack-resources \
--stack-name sam-app \
--profile wakuwaku-sam-admin
API Gatewayのエンドポイントを確認
下記コマンドで確認できます。
aws cloudformation describe-stacks \
--stack-name sam-app \
--query 'Stacks[].Outputs[?OutputKey==`HelloWorldApi`]' \
--output table \
--profile wakuwaku-sam-admin
$ aws cloudformation describe-stacks \
> --stack-name sam-app \
> --query 'Stacks[].Outputs[?OutputKey==`HelloWorldApi`]' \
> --output table \
> --profile wakuwaku-sam-admin
------------------------------------------------------------------------------------------------------------------------------------------------------------------
| DescribeStacks |
+-------------------------------------------------------------------+----------------+---------------------------------------------------------------------------+
| Description | OutputKey | OutputValue |
+-------------------------------------------------------------------+----------------+---------------------------------------------------------------------------+
| API Gateway endpoint URL for Prod stage for Hello World function | HelloWorldApi | https://xxxx.execute-api.ap-northeast-1.amazonaws.com/Prod/hello/ |
+-------------------------------------------------------------------+----------------+---------------------------------------------------------------------------+
curlでリクエストしてみます。
$ curl https://xxxx.execute-api.ap-northeast-1.amazonaws.com/Prod/hello/
{"message":"hello world"}
削除
( aws cloudformation delete-stack )
今回作成したスタックを削除します。
aws cloudformation delete-stack \
--stack-name sam-app \
--profile wakuwaku-sam-admin