Serverless FrameworkとAWS Serverless Application Modelのコマンドをまとめてみた

この記事は公開されてから1年以上経過しています。情報が古い可能性がありますので、ご注意ください。

2018年5月12日追記
AWS SAMにも専用のCLIツールが発表されたようです。最新の情報は各種ドキュメントを参照してください。

はじめに

こんにちは、中山です。

サーバーレス環境を構築する際に何らかのフレームワークを利用されている方は多くいると思います。Serverless FrameworkApexなどさまざまなフレームワークが存在しており、私も日々これらのツールを利用しています。それぞれ特色がありますが、共通する点として基本的にコミュニティベースで開発されているという側面があります。これだけサーバーレスという技術トレンドの盛り上がりがあるにも関わらず、AWS公式のフレームワークが中々発表されなかったのですが、AWS re:Invent 2016が開催される少し前、ついにAWSから待望のAWS Serverless Application Model(以下AWS SAM)というフレームワーク(正確に言うとサーバーレス環境をAWSで構築する際のモデル)が発表されました。弊社でもすぐにエントリを発表しています。

私もAWS SAMを利用/検証しています。使い勝手としてはServerless Frameworkとかなり近いなという印象です。そのため、Serverless Frameworを利用した経験のある方なら比較的容易に導入できると思います。という訳で、今回は自分の備忘録用途として Serverless FrameworkのあのコマンドはAWS SAMではどのコマンドに対応するのか という点を調べたのでエントリにまとめたいと思います。

概要

Serverless Frameworkには専用のコマンドが用意されています。 serverless またはそのシンボリックリンクである sls / slss コマンドです(本エントリでは sls で統一します)。対してAWS SAMの方はどうでしょうか。執筆時点(2016/12/17)ではAWS SAM専用のコマンドは用意されておらず、AWS CLIを利用することが想定されています(強いて言うならAWS SAMと同時に発表された aws cloudfromation package 及び aws cloudformation deploy ぐらい)。フレームワークではなくあくまで モデル という位置づけのためか、この点は他のフレームワークと大きく異なる点です。そのため、本エントリでは sls コマンドとAWS CLIの比較という形でまとめます。

Serverless Frameworkのバージョンは現時点の最新バージョンである1.4.0ベースであることにご注意ください。このツールは開発速度が早く、新しいコマンドが導入されたり既存のコマンド結果が変更される可能性が高いです。その点ご了承ください。また、AWS CLIのバージョンは1.11.30を想定しています。

Serverless Frameworkで用意されている各種コマンド及びその概要は sls コマンド単体で実行することにより確認可能です。

config credentials ............ Configures a new provider profile for the Serverless Framework
create ........................ Create new Serverless service
install ....................... Install a Serverless service from GitHub
deploy ........................ Deploy a Serverless service
deploy function ............... Deploy a single function from the service
deploy list ................... List deployed version of your Serverless Service
invoke ........................ Invoke a deployed function
invoke local .................. Invoke function locally
info .......................... Display information about the service
logs .......................... Output the logs of a deployed function
metrics ....................... Show metrics for a specific function
remove ........................ Remove Serverless service and all resources
rollback ...................... Rollback the Serverless service to a specific deployment
slstats ....................... Enable or disable stats

説明が長くなりました。それでは、早速比較していきます。

config credentials

Serverless Frameworkで利用する各種プロバイダ用クレデンシャルを生成するコマンドです。現在時点ではAWSのみに対応しています。実行結果は以下の通りです。

$ sls config credentials \
  --provider aws \
  --key ******************** \
  --secret **************************************** \
  --profile test-profile1
Serverless: Setting up AWS...
Serverless: Saving your AWS profile in "~/.aws/credentials"...
Serverless: Success! Your AWS access keys were stored under the "test-profile1" profile.
$ cat ~/.aws/credentials
[test-profile1]
aws_access_key_id=********************
aws_secret_access_key=****************************************

AWS CLIの場合はみなさん一度は実行したことがある aws configure ですね。

$ aws configure \
  --profile test-profile2
AWS Access Key ID [None]: ********************
AWS Secret Access Key [None]: ****************************************
Default region name [None]: ap-northeast-1
Default output format [None]: json
$ cat ~/.aws/credentials
aws_access_key_id = ********************
aws_secret_access_key = ****************************************

create

このコマンドは各種テンプレートからサービス及びプラグインの雛形を生成します。実行結果は以下の通りです。

$ sls create \
  --template aws-python \
  --name test-service \
  --path test-path1
Serverless: Generating boilerplate...
Serverless: Generating boilerplate in "/Users/knakayama/tmp/20161217/create/test-path1"
 _______                             __
|   _   .-----.----.--.--.-----.----|  .-----.-----.-----.
|   |___|  -__|   _|  |  |  -__|   _|  |  -__|__ --|__ --|
|____   |_____|__|  \___/|_____|__| |__|_____|_____|_____|
|   |   |             The Serverless Application Framework
|       |                           serverless.com, v1.4.0
 -------'

Serverless: Successfully generated boilerplate for template: "aws-python"
$ tree test-path1
test-path1
├── handler.py
└── serverless.yml

0 directories, 2 files

先程はサービスの生成でしたが、プラグインの場合も同じように雛形となるコードを生成してくれます。

$ sls create \
  --template plugin \
  --path test-path2
Serverless: Generating boilerplate...
Serverless: Generating boilerplate in "/Users/knakayama/tmp/20161217/create/test-path2"
 _______                             __
|   _   .-----.----.--.--.-----.----|  .-----.-----.-----.
|   |___|  -__|   _|  |  |  -__|   _|  |  -__|__ --|__ --|
|____   |_____|__|  \___/|_____|__| |__|_____|_____|_____|
|   |   |             The Serverless Application Framework
|       |                           serverless.com, v1.4.0
 -------'

Serverless: Successfully generated boilerplate for template: "plugin"
$ tree test-path2
test-path2
└── index.js

0 directories, 1 file

AWS CLIではAWS SAMの雛形を生成する機能は無いです。幸い、AWS SAMのGitHubリポジトリに多くのサンプル用CloudFormationテンプレートとLambda関数をまとめてくれています。もし雛形が必要であればこれをコピペすればOKです。AWS SAMには現状プラグインという概念がないのでその雛形を生成する機能もありません。

install

このコマンドはGitHubからサービスをカレントディレクトリにダウンロードすることができます。実行結果は以下の通りです。

$ sls install \
  --url https://github.com/pmuens/serverless-crud
Serverless: Downloading and installing "serverless-crud"...
Serverless: Successfully installed service "serverless-crud".
$ tree serverless-crud
serverless-crud
├── README.md
├── handler.js
├── package.json
├── serverless.yml
├── todos-create.js
├── todos-delete.js
├── todos-read-all.js
├── todos-read-one.js
└── todos-update.js

0 directories, 9 files

こちらもAWS CLI単体では提供されていない機能です。AWS SAMの各種コードをGitHubからダウンロードしたいのであれば単純に git clone で持ってくればいいでしょう。 .git が不要であれば消せばいいだけです。

deploy

Serverless Frameworkのサービスをデプロイするコマンドです。このフレームワークにより生成されたCloudFormationテンプレートはカレントディレクトリの .serverless ディレクトリ以下に作成されます。実行結果は以下の通りです。

# CloudFormationテンプレートのみ生成
$ sls deploy \
  --noDeploy \
  --stage dev \
  --region ap-northeast-1 \
  --verbose
Serverless: Packaging service...
Serverless: Did not deploy due to --noDeploy
$ tree .serverless
.serverless
├── cloudformation-template-create-stack.json
├── cloudformation-template-update-stack.json
└── test-service.zip

0 directories, 3 files
# 実際にデプロイ
$ sls deploy \
  --stage dev \
  --region ap-northeast-1 \
  --verbose
Serverless: Creating Stack...
Serverless: Checking Stack create progress...
CloudFormation - CREATE_IN_PROGRESS - AWS::CloudFormation::Stack - test-service-dev
CloudFormation - CREATE_IN_PROGRESS - AWS::S3::Bucket - ServerlessDeploymentBucket
CloudFormation - CREATE_IN_PROGRESS - AWS::S3::Bucket - ServerlessDeploymentBucket
CloudFormation - CREATE_COMPLETE - AWS::S3::Bucket - ServerlessDeploymentBucket
CloudFormation - CREATE_COMPLETE - AWS::CloudFormation::Stack - test-service-dev
Serverless: Stack create finished...
Serverless: Packaging service...
Serverless: Uploading CloudFormation file to S3...
Serverless: Uploading service .zip file to S3 (639 B)...
Serverless: Updating Stack...
Serverless: Checking Stack update progress...
CloudFormation - UPDATE_IN_PROGRESS - AWS::CloudFormation::Stack - test-service-dev
CloudFormation - CREATE_IN_PROGRESS - AWS::IAM::Role - IamRoleLambdaExecution
CloudFormation - CREATE_IN_PROGRESS - AWS::IAM::Role - IamRoleLambdaExecution
CloudFormation - CREATE_COMPLETE - AWS::IAM::Role - IamRoleLambdaExecution
CloudFormation - CREATE_IN_PROGRESS - AWS::IAM::Policy - IamPolicyLambdaExecution
CloudFormation - CREATE_IN_PROGRESS - AWS::IAM::Policy - IamPolicyLambdaExecution
CloudFormation - CREATE_COMPLETE - AWS::IAM::Policy - IamPolicyLambdaExecution
CloudFormation - CREATE_IN_PROGRESS - AWS::Lambda::Function - HelloLambdaFunction
CloudFormation - CREATE_IN_PROGRESS - AWS::Lambda::Function - HelloLambdaFunction
CloudFormation - CREATE_COMPLETE - AWS::Lambda::Function - HelloLambdaFunction
CloudFormation - CREATE_IN_PROGRESS - AWS::Lambda::Version - HelloLambdaVersion6o6Rkvlbaf5HCYTq0tDyUlMHgyTHvO8ZK6RXnh3k1Y
CloudFormation - CREATE_IN_PROGRESS - AWS::Lambda::Version - HelloLambdaVersion6o6Rkvlbaf5HCYTq0tDyUlMHgyTHvO8ZK6RXnh3k1Y
CloudFormation - CREATE_COMPLETE - AWS::Lambda::Version - HelloLambdaVersion6o6Rkvlbaf5HCYTq0tDyUlMHgyTHvO8ZK6RXnh3k1Y
CloudFormation - UPDATE_COMPLETE_CLEANUP_IN_PROGRESS - AWS::CloudFormation::Stack - test-service-dev
CloudFormation - UPDATE_COMPLETE - AWS::CloudFormation::Stack - test-service-dev
Serverless: Stack update finished...
Service Information
service: test-service
stage: dev
region: ap-northeast-1
api keys:
  None
endpoints:
  None
functions:
  test-service-dev-hello: arn:aws:lambda:ap-northeast-1:************:function:test-service-dev-hello

Stack Outputs
HelloLambdaFunctionArn: arn:aws:lambda:ap-northeast-1:************:function:test-service-dev-hello
HelloLambdaFunctionQualifiedArn: arn:aws:lambda:ap-northeast-1:************:function:test-service-dev-hello:1
ServerlessDeploymentBucketName: test-service-dev-serverlessdeploymentbucket-29pknictzyf7

テンプレートとアーティファクトの生成及びそのデプロイはAWS SAMのお家芸ですね。 aws cloudformation package でS3にLambda関数を設置してAWS SAM用CloudFormationを生成(S3上のLambda関数へのパスを追記)、 aws cloudformation deploy でデプロイという流れです。それぞれ見ていきましょう。

# AWS SAM用CloudFormationの生成
$ aws cloudformation package \
  --template-file sam.yml \
  --s3-bucket ********************** \
  --output-template-file packaged-sam.yml \
  --region ap-northeast-1
Uploading to 14f3eb35c3eeeee74943d3e3aea1efb0  4448 / 4448.0  (100.00%)
Successfully packaged artifacts and wrote output template to file packaged-sam.yml.
Execute the following command to deploy the packaged template
aws cloudformation deploy --template-file /Users/knakayama/tmp/20161217/deploy/packaged-sam.yml --stack-name <YOUR STACK NAME>
# デプロイ
$ aws cloudformation deploy \
  --template-file packaged-sam.yml \
  --stack-name test-sam \
  --capabilities CAPABILITY_IAM \
  --region ap-northeast-1
Waiting for changeset to be created..
Waiting for stack create/update to complete
Successfully created/updated stack - test-sam

Serverless Frameworkと異なるAWS SAMの特色として以下の点があります。

  • --kms-key-id
    • S3にアップロードするアーティファクトをKMSにより暗号化可能
  • --parameter-override
    • CloudFormationのパラメータをコマンドラインから変更可能
  • --no-execute-change-set
    • スタックのアップデート前にChangeSetを確認できる
    • Serverless Frameworkは現状ChangeSetに対応してないのでAWS SAMの利点の一つ

それぞれ以下のように使います。

  • KMSによる暗号化
$ aws cloudformation package \
  --template-file sam.yml \
  --s3-bucket ********************** \
  --output-template-file packaged-sam.yml \
  --kms-key-id ************************************ \
  --region ap-northeast-1
Uploading to 2e7e34d6b2265f4558363875d1200d36  490 / 490.0  (100.00%)
Successfully packaged artifacts and wrote output template to file packaged-sam.yml.
Execute the following command to deploy the packaged template
aws cloudformation deploy --template-file /Users/knakayama/tmp/20161217/deploy/packaged-sam.yml --stack-name <YOUR STACK NAME>
$ aws s3api head-object \
  --bucket ********************** \
  --key 2e7e34d6b2265f4558363875d1200d36
{
    "AcceptRanges": "bytes",
    "ContentType": "binary/octet-stream",
    "LastModified": "Sat, 17 Dec 2016 02:35:25 GMT",
    "ContentLength": 490,
    "ETag": "\"53d20f8816e72392468face701662416\"",
    "ServerSideEncryption": "aws:kms",
    "SSEKMSKeyId": "arn:aws:kms:ap-northeast-1:************:key/************************************",
    "Metadata": {}
}
  • パラメータのオーバーライド
$ cat packaged-sam.yml
AWSTemplateFormatVersion: 2010-09-09
Description: AWS SAM Test
Parameters:
  Timeout:
    Default: 3
    Description: Timeout
    Type: Number
Resources:
  TestFunction:
    Properties:
      CodeUri: s3://**********************/015926a9a59bf83ceb0d87aec7c4afbc
      Handler: handler.hello
      Runtime: python2.7
      Timeout:
        Ref: Timeout
    Type: AWS::Serverless::Function
Transform: AWS::Serverless-2016-10-31
$ aws cloudformation deploy \
  --template-file packaged-sam.yml \
  --stack-name test-sam \
  --capabilities CAPABILITY_IAM \
  --region ap-northeast-1 \
  --parameter-overrides Timeout=6
Waiting for changeset to be created..
Waiting for stack create/update to complete
Successfully created/updated stack - test-sam
$ aws lambda get-function-configuration \
  --function-name test-sam-TestFunction-1EXTP41SKWHO9 \
  --query 'Timeout'
6
  • ChangeSetの取得
$ aws cloudformation deploy \
  --template-file packaged-sam.yml \
  --stack-name test-sam \
  --capabilities CAPABILITY_IAM \
  --region ap-northeast-1 \
  --parameter-overrides Timeout=5 \
  --no-execute-changeset
Waiting for changeset to be created..
Changeset created successfully. Run the following command to review changes:
aws cloudformation describe-change-set --change-set-name arn:aws:cloudformation:ap-northeast-1:************:changeSet/awscli-cloudformation-package-deploy-1481944875/54effcac-125c-4987-b56d-877b5d960b55
$ aws cloudformation describe-change-set \
  --change-set-name arn:aws:cloudformation:ap-northeast-1:************:changeSet/awscli-cloudformation-package-deploy-1481944875/54effcac-125c-4987-b56d-877b5d960b55
{
    "StackId": "arn:aws:cloudformation:ap-northeast-1:************:stack/test-sam/235ef660-c407-11e6-bc1f-50a686699882",
    "Status": "CREATE_COMPLETE",
    "ChangeSetName": "awscli-cloudformation-package-deploy-1481944875",
    "Description": "Created by AWS CLI at 2016-12-17T03:21:15.992064 UTC",
    "Parameters": [
        {
            "ParameterValue": "5",
            "ParameterKey": "Timeout"
        }
    ],
    "Changes": [
        {
            "ResourceChange": {
                "ResourceType": "AWS::Lambda::Function",
                "PhysicalResourceId": "test-sam-TestFunction-1EXTP41SKWHO9",
                "Details": [
                    {
                        "CausingEntity": "Timeout",
                        "ChangeSource": "ParameterReference",
                        "Evaluation": "Static",
                        "Target": {
                            "Attribute": "Properties",
                            "Name": "Timeout",
                            "RequiresRecreation": "Never"
                        }
                    },
                    {
                        "ChangeSource": "DirectModification",
                        "Evaluation": "Dynamic",
                        "Target": {
                            "Attribute": "Properties",
                            "Name": "Timeout",
                            "RequiresRecreation": "Never"
                        }
                    }
                ],
                "Action": "Modify",
                "Scope": [
                    "Properties"
                ],
                "LogicalResourceId": "TestFunction",
                "Replacement": "False"
            },
            "Type": "Resource"
        }
    ],
    "CreationTime": "2016-12-17T03:21:17.075Z",
    "Capabilities": [
        "CAPABILITY_IAM"
    ],
    "StackName": "test-sam",
    "NotificationARNs": [],
    "ExecutionStatus": "AVAILABLE",
    "ChangeSetId": "arn:aws:cloudformation:ap-northeast-1:************:changeSet/awscli-cloudformation-package-deploy-1481944875/54effcac-125c-4987-b56d-877b5d960b55"
}

deploy function

サービスに関連付けられているLambda関数の中から特定のLambda関数をデプロイするコマンドです。一見 sls deploy と似た動作をしそうですが、ドキュメントによると異なる動作をするようです。以下に引用します。

The sls deploy function command deploys an individual function without AWS CloudFormation. This command simply swaps out the zip file that your CloudFormation stack is pointing toward. This is a much faster way of deploying changes in code.

CloudFormationが参照するZipを変更するという処理になるので sls deploy より高速に動作するようですね。実行結果は以下の通りです。

# 現在のLambda関数のSHA256を確認
$ aws lambda get-function-configuration \
  --function-name test-service-dev-hello \
  --query 'CodeSha256'
"yjdQs4sCLKZcCpJ/1f37+6R90gQviLOpDe9hbVtFPdw="
# 特定Lambda関数のみデプロイ
$ sls deploy function \
  --function hello \
  --stage dev \
  --region ap-northeast-1 \
  --verbose
Serverless: Deploying function: hello...
Serverless: Packaging function: hello...
Serverless: Uploading function: hello (2.47 KB)...
Serverless: Successfully deployed function: hello
# Lambda関数のSHA256が変更されていることを確認
$ aws lambda get-function-configuration \
  --function-name test-service-dev-hello \
  --query 'CodeSha256'
"+hkvpr4P+dNG2pmSx5+xA69vIeoQbmMhSM3w4MMNV4k="

AWS SAMでは aws lambda update-function-code を利用することによりLambda関数の参照するコードを差し替えることが可能です。

# 現在のLambda関数のSHA256を確認
$ aws lambda get-function-configuration \
  --function-name test-sam-TestFunction-OINPPMS3LCOA \
  --query 'CodeSha256'
"i3PhQqa9VaKs6ilDgUGrdr0k3upZp5D+0siGE/I6OLk="
# Lambda関数のコードを差し替える
$ aws lambda update-function-code \
  --function-name test-sam-TestFunction-OINPPMS3LCOA \
  --s3-bucket ********************** \
  --s3-key cde3868bbec9ab495a18c09299d66865
{
    "CodeSha256": "6RR+7MnkwfjwD5it8cv1wG/hhKA0bvIFho0Fb9UMpd8=",
    "FunctionName": "test-sam-TestFunction-OINPPMS3LCOA",
    "CodeSize": 1041,
    "MemorySize": 128,
    "FunctionArn": "arn:aws:lambda:ap-northeast-1:************:function:test-sam-TestFunction-OINPPMS3LCOA",
    "Version": "$LATEST",
    "Role": "arn:aws:iam::************:role/test-sam-TestFunctionRole-1T5ZT9L4RQWBG",
    "Timeout": 3,
    "LastModified": "2016-12-17T11:21:57.081+0000",
    "Handler": "handler.hello",
    "Runtime": "python2.7",
    "Description": ""
}

deploy list

デプロイ済みアーティファクトとその情報を表示するコマンドです。実行結果は以下の通りです。

$ sls deploy list \
  --stage dev \
  --region ap-northeast-1 \
  --verbose
Serverless: Listing deployments:
Serverless: -------------
Serverless: Timestamp: 1481937983844
Serverless: Datetime: 2016-12-17T01:26:23.844Z
Serverless: Files:
Serverless: - compiled-cloudformation-template.json
Serverless: - test-service.zip

出力は多少異なりますが、AWS SAMの場合はS3バケットをそのまま参照すればほぼ同等の情報は表示できます。

$ aws s3 ls s3://**********************
2016-12-17 12:12:19        996 015926a9a59bf83ceb0d87aec7c4afbc
2016-12-17 12:10:38       1045 0bbe9db183a711f0eedd7083229dd677
2016-12-17 12:07:36        490 2e7e34d6b2265f4558363875d1200d36
2016-12-17 19:27:00        994 317c4060ca5af0f09a4b7dc3bb680162
2016-12-17 19:57:05       1105 4c23686ee9a6bfb95c03c9eb7190d868
2016-12-17 19:56:16       1026 710ed11f0ffbf2c47a14af5d4887b3f3
2016-12-17 19:59:58       1110 c233d40079702ff5ff8d9015284c5a5c
2016-12-17 19:48:03        950 c30589961aed945eff97109809912f92
2016-12-17 12:09:51       1041 cde3868bbec9ab495a18c09299d66865
2016-12-17 20:17:53       1030 f4d11a1161bf72a0e59aff9c93497788

invoke

デプロイ済みのLambda関数を実行するコマンドです。 -t または --type でLambda関数の実行方法を指定可能です。デフォルトは RequestResponse で、その他 Event または DryRun を指定できます。実行結果は以下の通りです。

$ sls invoke \
  --function hello \
  --stage dev \
  --region ap-northeast-1 \
  --data '{"Message": "Test Message"}' \
  --log
{
    "body": "{\"input\": {\"Message\": \"Test Message\"}, \"message\": \"Go Serverless v1.0! Your function executed successfully!\"}",
    "statusCode": 200
}
--------------------------------------------------------------------
START RequestId: a4a4673a-c40f-11e6-97f0-473036194eb9 Version: $LATEST
END RequestId: a4a4673a-c40f-11e6-97f0-473036194eb9
REPORT RequestId: a4a4673a-c40f-11e6-97f0-473036194eb9  Duration: 0.25 ms       Billed Duration: 100 ms         Memory Size: 1024 MB    Max Memory Used: 16 MB

AWS SAMの場合は aws lambda invoke でほぼ同等のことが可能です。ただし注意点が2つあります。一つはLambda関数の実行ログがbase64エンコードで出力されるという点、二つ目はLambda関数の実行結果がファイルに出力することを想定されている、つまりデフォルトで標準出力に表示する訳ではないという点です。

$ aws lambda invoke \
  --function-name test-service-dev-hello \
  --log-type Tail \
  --payload '{"Message": "Test Message"}' \
  --region ap-northeast-1 \
  outfile
{
    "LogResult": "U1RBUlQgUmVxdWVzdElkOiBkYjIxMjgxYy1jNDExLTExZTYtYjA2My00MWNiYTUwZTM5ZDMgVmVyc2lvbjogJExBVEVTVApFTkQgUmVxdWVzdElkOiBkYjIxMjgxYy1jNDExLTExZTYtYjA2My00MWNiYTUwZTM5ZDMKUkVQT1JUIFJlcXVlc3RJZDogZGIyMTI4MWMtYzQxMS0xMWU2LWIwNjMtNDFjYmE1MGUzOWQzCUR1cmF0aW9uOiAwLjM4IG1zCUJpbGxlZCBEdXJhdGlvbjogMTAwIG1zIAlNZW1vcnkgU2l6ZTogMTAyNCBNQglNYXggTWVtb3J5IFVzZWQ6IDE2IE1CCQo=",
    "StatusCode": 200
}
$ cat outfile
{"body": "{\"input\": {\"Message\": \"Test Message\"}, \"message\": \"Go Serverless v1.0! Your function executed successfully!\"}", "statusCode": 200}%

いちいちファイルを指定するのも面倒ですし、ログがbase64エンコードされているのは見づらいです。そういった場合は以下のように修正すればOKです。

$ aws lambda invoke \
  --function-name test-service-dev-hello \
  --log-type Tail \
  --payload '{"Message": "Test Message"}' \
  --region ap-northeast-1 \
  --query 'LogResult' \
  /dev/stdin \
  | perl -MMIME::Base64 -ne 'print decode_base64($_)'
{"body": "{\"input\": {\"Message\": \"Test Message\"}, \"message\": \"Go Serverless v1.0! Your function executed successfully!\"}", "statusCode": 200}START RequestId: ef886eb5-c412-11e6-a344-c51c45ded01c Version: $LATEST
END RequestId: ef886eb5-c412-11e6-a344-c51c45ded01c
REPORT RequestId: ef886eb5-c412-11e6-a344-c51c45ded01c  Duration: 0.33 ms       Billed Duration: 100 ms         Memory Size: 1024 MB    Max Memory Used: 16 MB

invoke local

Lambda関数をローカル環境でエミュレーションして実行できるコマンドです。現状Node.jsのみ対応しています。ドキュメントを引用します。

This runs your code locally by emulating the AWS Lambda environment. Please keep in mind, it's not a 100% perfect emulation, there may be some differences, but it works for the vast majority of users. We mock the context with simple mock data.

完全に同じ環境という訳ではないようですが、ローカルでLambda関数を実行できるのはかなり便利な機能だと思います。実行結果は以下の通りです。

$ sls invoke local \
  --function hello \
  --stage dev \
  --region ap-northeast-1 \
  --data '{"Message": "Test Invoke on local"}' \
  --log
{ awsRequestId: 'id',
  invokeid: 'id',
  logGroupName: '/aws/lambda/test-service-dev-hello',
  logStreamName: '2015/09/22/[HEAD]13370a84ca4ed8b77c427af260',
  functionVersion: 'HEAD',
  isDefaultFunctionVersion: true,
  functionName: 'test-service-dev-hello',
  memoryLimitInMB: '1024',
  succeed: [Function: succeed],
  fail: [Function: fail],
  done: [Function: done],
  getRemainingTimeInMillis: [Function: getRemainingTimeInMillis] }
{
    "statusCode": 200,
    "body": "{\"message\":\"Go Serverless v1.0! Your function executed successfully!\",\"input\":{\"Message\":\"Test Invoke on local\"}}"
}

AWS SAM単体ではこういった機能は提供されていません。ashiina/lambda-localなどの外部ツールを利用すれば同等のことは可能です。

info

サービスでデプロイされたLambda関数を表示します。 -v または --verbose オプションを指定することによりLambda関数以外のAWSリソースも表示可能です。出力結果は以下の通りです。

$ sls info \
  --stage dev \
  --region ap-northeast-1 \
  --verbose
Service Information
service: test-service
stage: dev
region: ap-northeast-1
api keys:
  None
endpoints:
  None
functions:
  test-service-dev-hello: arn:aws:lambda:ap-northeast-1:************:function:test-service-dev-hello

Stack Outputs
HelloLambdaFunctionArn: arn:aws:lambda:ap-northeast-1:************:function:test-service-dev-hello
HelloLambdaFunctionQualifiedArn: arn:aws:lambda:ap-northeast-1:************:function:test-service-dev-hello:8
ServerlessDeploymentBucketName: test-service-dev-serverlessdeploymentbucket-17ru2k5afzf0j

AWS SAMであれば以下のコマンドで確認可能です。

# スタックで作成されたリソースを全て表示
$ aws cloudformation describe-stack-resources \
  --stack-name test-service-dev \
  --region ap-northeast-1
{
    "StackResources": [
        {
            "StackId": "arn:aws:cloudformation:ap-northeast-1:************:stack/test-service-dev/178981e0-c40f-11e6-9798-50a6866998ae",
            "ResourceStatus": "CREATE_COMPLETE",
            "ResourceType": "AWS::Lambda::Function",
            "Timestamp": "2016-12-17T04:13:59.215Z",
            "StackName": "test-service-dev",
            "PhysicalResourceId": "test-service-dev-hello",
            "LogicalResourceId": "HelloLambdaFunction"
        },
        {
            "StackId": "arn:aws:cloudformation:ap-northeast-1:************:stack/test-service-dev/178981e0-c40f-11e6-9798-50a6866998ae",
            "ResourceStatus": "CREATE_COMPLETE",
            "ResourceType": "AWS::Lambda::Version",
            "Timestamp": "2016-12-17T04:14:04.764Z",
            "StackName": "test-service-dev",
            "PhysicalResourceId": "arn:aws:lambda:ap-northeast-1:************:function:test-service-dev-hello:8",
            "LogicalResourceId": "HelloLambdaVersionfiJylhhWqgsYsPlPvp6YHrfw4m1A56Vq4s2u2I4g4c0"
        },
        {
            "StackId": "arn:aws:cloudformation:ap-northeast-1:************:stack/test-service-dev/178981e0-c40f-11e6-9798-50a6866998ae",
            "ResourceStatus": "CREATE_COMPLETE",
            "ResourceType": "AWS::IAM::Policy",
            "Timestamp": "2016-12-17T04:13:53.734Z",
            "StackName": "test-service-dev",
            "PhysicalResourceId": "test-IamP-RYMM19CZ8FLL",
            "LogicalResourceId": "IamPolicyLambdaExecution"
        },
        {
            "StackId": "arn:aws:cloudformation:ap-northeast-1:************:stack/test-service-dev/178981e0-c40f-11e6-9798-50a6866998ae",
            "ResourceStatus": "CREATE_COMPLETE",
            "ResourceType": "AWS::IAM::Role",
            "Timestamp": "2016-12-17T04:13:49.275Z",
            "StackName": "test-service-dev",
            "PhysicalResourceId": "test-service-dev-ap-northeast-1-lambdaRole",
            "LogicalResourceId": "IamRoleLambdaExecution"
        },
        {
            "StackId": "arn:aws:cloudformation:ap-northeast-1:************:stack/test-service-dev/178981e0-c40f-11e6-9798-50a6866998ae",
            "ResourceStatus": "CREATE_COMPLETE",
            "ResourceType": "AWS::S3::Bucket",
            "Timestamp": "2016-12-17T04:13:25.136Z",
            "StackName": "test-service-dev",
            "PhysicalResourceId": "test-service-dev-serverlessdeploymentbucket-17ru2k5afzf0j",
            "LogicalResourceId": "ServerlessDeploymentBucket"
        }
    ]
}
# 特定のリソースのみ表示
$ aws cloudformation describe-stack-resource \
  --stack-name test-service-dev \
  --logical-resource-id HelloLambdaFunction \
  --region ap-northeast-1
{
    "StackResourceDetail": {
        "StackId": "arn:aws:cloudformation:ap-northeast-1:************:stack/test-service-dev/178981e0-c40f-11e6-9798-50a6866998ae",
        "ResourceStatus": "CREATE_COMPLETE",
        "ResourceType": "AWS::Lambda::Function",
        "LastUpdatedTimestamp": "2016-12-17T04:13:59.215Z",
        "StackName": "test-service-dev",
        "PhysicalResourceId": "test-service-dev-hello",
        "Metadata": "{}\n",
        "LogicalResourceId": "HelloLambdaFunction"
    }
}

logs

特定Lambda関数のCloudWatch Logsに出力された実行ログを標準出力に表示します。 -t または --tail でログを出力し続けられるという点が扱いやすいと思います。実行結果は以下の通りです。

$ sls logs \
  --function hello \
  --stage dev \
  --region ap-northeast-1 \
  --startTime 1m \
  --tail
START RequestId: 200810b6-c417-11e6-b063-41cba50e39d3 Version: $LATEST
{'body': '{"input": {"Message": "Invoke 1"}, "message": "Go Serverless v1.0! Your function executed successfully!"}', 'statusCode': 200}
END RequestId: 200810b6-c417-11e6-b063-41cba50e39d3
REPORT RequestId: 200810b6-c417-11e6-b063-41cba50e39d3  Duration: 0.23 ms       Billed Duration: 100 ms         Memory Size: 1024 MB    Max Memory Used: 15 MB

START RequestId: 2dd53c59-c417-11e6-8614-fff3243690ae Version: $LATEST
{'body': '{"input": {"Message": "Invoke 2"}, "message": "Go Serverless v1.0! Your function executed successfully!"}', 'statusCode': 200}
END RequestId: 2dd53c59-c417-11e6-8614-fff3243690ae
REPORT RequestId: 2dd53c59-c417-11e6-8614-fff3243690ae  Duration: 0.39 ms       Billed Duration: 100 ms         Memory Size: 1024 MB    Max Memory Used: 15 MB

AWS SAMで同等のことをやる場合は aws logs get-log-events でOKです。ただし -t オプションのようなものはデフォルトで用意されていません。そのまま実行すると一時点のログをダンプするだけです。

$ aws logs get-log-events \
  --log-group-name /aws/lambda/test-service-dev-hello \
  --log-stream-name '2016/12/17/[$LATEST]fa7c9fbf72134771bdf38bb8eab4e17e'
{
    "nextForwardToken": "f/33048960342271083447829681146392450088141425484896075778",
    "events": [
        {
            "ingestionTime": 1481966471040,
            "timestamp": 1481966455994,
            "message": "START RequestId: 1d2bdde5-c43a-11e6-ae32-8f74f28d8d59 Version: $LATEST\n"
        },
        {
            "ingestionTime": 1481966471040,
            "timestamp": 1481966455994,
            "message": "{'body': '{\"input\": {\"Message\": \"Invoke 1\"}, \"message\": \"Go Serverless v1.0! Your function executed successfully!\"}', 'statusCode': 200}\n"
        },
        {
            "ingestionTime": 1481966471040,
            "timestamp": 1481966455994,
            "message": "END RequestId: 1d2bdde5-c43a-11e6-ae32-8f74f28d8d59\n"
        },
<snip>

もし継続してログを表示し続けたい場合は nextForwardToken をゴニョゴニョする必要がありそうです。シェルスクリプトにしないとちょっとシンドいですね。。。

metrics

サービスまたは特定のLambda関数メトリクスを表示するコマンドです。実行結果は以下の通りです。

# サービス全体のメトリクスを表示
$ sls metrics \
  --stage dev \
  --region ap-northeast-1
Service wide metrics
December 16, 2016 6:37 PM - December 17, 2016 6:37 PM

Invocations: 81
Throttles: 0
Errors: 0
Duration (avg.): 0.83ms
# 特定のLambda関数メトリクスを表示
$ sls metrics \
  --function hello2 \
  --stage dev \
  --region ap-northeast-1
test-service-dev-hello2
December 16, 2016 6:37 PM - December 17, 2016 6:37 PM

Invocations: 1
Throttles: 0
Errors: 0
Duration (avg.): 0.19ms

AWS SAMでは aws cloudwatch get-metric-statistics で同等の内容を取得可能です。ただし、 --metric-name オプションは引数を一つしか指定できないため、同時に複数のメトリクスを表示することはできません。また、出力はデータポイント毎に表示されるため合計値を取得したい場合は --query でパースしてゴニョゴニョする必要があります。

$ aws cloudwatch get-metric-statistics \
  --namespace AWS/Lambda \
  --metric-name Invocations \
  --start-time "$(date -v1d '+%FT%T%z')" \
  --end-time "$(date '+%FT%T%z')" \
  --period 3600 \
  --statistics Sum \
  --dimensions Name=FunctionName,Value=test-service-dev-hello2
{
    "Datapoints": [
        {
            "Timestamp": "2016-12-17T09:10:00Z",
            "Sum": 1.0,
            "Unit": "Count"
        }
    ],
    "Label": "Invocations"
}

--dimensions オプションは同時に複数指定可能なので、がんばればAWS SAMでデプロイしたLambda関数全て(Serverless Frameworkのようにサービスワイドに)メトリクスを表示することは「一応」可能です。

remove

デプロイしたサービスを削除するためのコマンドです。実行結果は以下の通りです。

$ sls remove \
  --stage dev \
  --region ap-northeast-1 \
  --verbose
Serverless: Getting all objects in S3 bucket...
Serverless: Removing objects in S3 bucket...
Serverless: Removing Stack...
Serverless: Checking Stack removal progress...
CloudFormation - DELETE_IN_PROGRESS - AWS::CloudFormation::Stack - test-service-dev
CloudFormation - DELETE_SKIPPED - AWS::Lambda::Version - Hello2LambdaVersionXL8T4q21BMVArjUZnPZ8H8gWpEJGeVoqJjakvY9nZ0
CloudFormation - DELETE_SKIPPED - AWS::Lambda::Version - HelloLambdaVersionXL8T4q21BMVArjUZnPZ8H8gWpEJGeVoqJjakvY9nZ0
CloudFormation - DELETE_IN_PROGRESS - AWS::Lambda::Function - Hello2LambdaFunction
CloudFormation - DELETE_IN_PROGRESS - AWS::Lambda::Function - HelloLambdaFunction
CloudFormation - DELETE_COMPLETE - AWS::Lambda::Function - Hello2LambdaFunction
CloudFormation - DELETE_COMPLETE - AWS::Lambda::Function - HelloLambdaFunction
CloudFormation - DELETE_IN_PROGRESS - AWS::S3::Bucket - ServerlessDeploymentBucket
CloudFormation - DELETE_IN_PROGRESS - AWS::IAM::Policy - IamPolicyLambdaExecution
CloudFormation - DELETE_COMPLETE - AWS::IAM::Policy - IamPolicyLambdaExecution
CloudFormation - DELETE_IN_PROGRESS - AWS::IAM::Role - IamRoleLambdaExecution
CloudFormation - DELETE_COMPLETE - AWS::IAM::Role - IamRoleLambdaExecution
Serverless: Stack removal finished...

AWS SAMの場合は単純にスタックを削除すればOKですね。何も出力してくれないのがちょっと物足りないですが。。。

$ aws cloudformation delete-stack \
  --stack-name test-sam \
  --region ap-northeast-1

注意点として、AWS SAMでデプロイしたスタックにはアーティファクトを設置するS3バケットが含まれないため、アーティファクト自体は残り続けます。不要な場合は別途 aws s3 rm などで削除する必要があります。

rollback

デプロイしたサービスを特定のバージョンにロールバックするためのコマンドです。ロールバック可能なバージョンは sls deploy list で確認できます。コマンド実行後、 sls info などでバージョンが変更されたことを確認可能です。実行結果は以下の通りです。

# ロールバック可能なバージョンを確認
$ sls deploy list \
  --stage dev \
  --region ap-northeast-1
Serverless: Listing deployments:
Serverless: -------------
Serverless: Timestamp: 1481970768486
Serverless: Datetime: 2016-12-17T10:32:48.486Z
Serverless: Files:
Serverless: - compiled-cloudformation-template.json
Serverless: - test-service.zip
Serverless: -------------
Serverless: Timestamp: 1481970854329
Serverless: Datetime: 2016-12-17T10:34:14.329Z
Serverless: Files:
Serverless: - compiled-cloudformation-template.json
Serverless: - test-service.zip
# 一つ前のバージョンにロールバック
$ sls rollback \
  --timestamp 1481970768486 \
  --stage dev \
  --region ap-northeast-1 \
  --verbose
Serverless: Updating Stack...
Serverless: Checking Stack update progress...
CloudFormation - UPDATE_IN_PROGRESS - AWS::CloudFormation::Stack - test-service-dev
CloudFormation - UPDATE_IN_PROGRESS - AWS::Lambda::Function - HelloLambdaFunction
CloudFormation - UPDATE_COMPLETE - AWS::Lambda::Function - HelloLambdaFunction
CloudFormation - CREATE_IN_PROGRESS - AWS::Lambda::Version - HelloLambdaVersiondlrDajrtLvznrNAJq89sA9kEeYEObNrIRqlkCSMDPOM
CloudFormation - CREATE_IN_PROGRESS - AWS::Lambda::Version - HelloLambdaVersiondlrDajrtLvznrNAJq89sA9kEeYEObNrIRqlkCSMDPOM
CloudFormation - CREATE_COMPLETE - AWS::Lambda::Version - HelloLambdaVersiondlrDajrtLvznrNAJq89sA9kEeYEObNrIRqlkCSMDPOM
CloudFormation - UPDATE_COMPLETE_CLEANUP_IN_PROGRESS - AWS::CloudFormation::Stack - test-service-dev
CloudFormation - DELETE_COMPLETE - AWS::Lambda::Version - HelloLambdaVersionT3pb90H1XG0nldLH7QHVZEW0uh3ma4m8oVIidMnGyYA
CloudFormation - UPDATE_COMPLETE - AWS::CloudFormation::Stack - test-service-dev
Serverless: Stack update finished...

AWS SAMの場合、Serverless Frameworkのように1つの機能として特定のバージョンにスタックをロールバックさせるという機能は現状提供されていません。似たようなことをしたいのであれば、 aws cloudformation package で生成されたCloudFormationテンプレートを保存しておき、特定のテンプレートでスタックをアップデートさせるという方法で擬似的にロールバックは可能です。

slstats

Serverless Frameworkの利用状況などを送信するかどうかをスイッチさせるコマンドです。設定ファイルは ~/.serverless ディレクトリ以下に置かれます。実行結果は以下の通りです。

$ sls slstats \
  --enable
Serverless: Stats successfully enabled
$ sls slstats \
  --disable
Serverless: Stats successfully disabled

これはServerless Framework特有のものなので、当然ですがAWS SAMにはありません。

まとめ

いかがだったでしょうか。

Serverless FrameworkとAWS SAM(正確にはAWS CLI)のコマンドをまとめてみました。専用のコマンドが用意されている分、やはり扱いやすさと出力の見やすさという点ではServerless Frameworkに分があるという印象が個人的には強いです。AWS SAMが今後発展していくためにはこの部分の整備が必須だなと考えています。例えば、専用のコマンドを用意するのもいいと思いますし、あくまでAWS CLIを利用するのであれば aws sam ... といった形でネームスペースを分けて専用のサブコマンドを用意して欲しいです。きっとAWSさんならやってくれる!と信じて今後もAWS SAMの動向に注目していきたいと思います!

本エントリがみなさんの参考になったら幸いに思います。