AWS SAM CLI 再入門 2021.08

この記事は [**AWS Advent Calendar 2019**](https://qiita.com/advent-calendar/2019/aws) 16日目の記事でした。
2020/7/21 に AWS SAM CLI が General Available となっため、v1.0.0 時点の情報に更新しました。
2021/8/24 に v1.29.0 時点の情報に更新しました。

## はじめに
2018年の5月に[aws-sam-local 改め aws-sam-cli の新機能 sam init を試す](https://qiita.com/hayao_k/items/841026f9675d163b58d5)という記事を投稿しました。

https://qiita.com/hayao_k/items/841026f9675d163b58d5

AWS SAM CLI は GitHub 上で開発が行われていますが、リリースのペースが早く日々機能追加や改善が行われています。結果として上記の記事の内容は一部古いものとなっています。本記事では2021年8月22日時点の最新バージョンである v1.29.0 までのリリースを踏まえた使い方をご紹介します。

## AWS SAM と AWS SAM CLI
Serverless Application Model（SAM）は Lambda や API Gateway, DynamoDB のようなサービスを活用したサーバーレスアプリケーションのデプロイに特化した、AWS CloudFormation の拡張機能です。通常の CloudFormation テンプレートと同様に YAML/JSON でテンプレートを定義しますが、素のテンプレートより簡潔に記載できるのが特徴です。

AWS SAM CLI は SAM を使用したサーバーレスアプリケーションの作成と管理を簡単に行うことができるコマンドラインツールです。

## SAM CLI で利用される Docker イメージについて
後述の sam local invoke 等のコマンドでは AWS Lmabda の実行環境をエミュレートするためのコンテナイメージが使用され、起動するコンテナ内で Lambda 関数がローカル実行されます。(あくまでエミュレートなので、完全な再現環境ではありません。)

GA 以前は [lambci/docker-lambda](https://github.com/lambci/docker-lambda) で公開されているコンテナイメージが利用されていましたが、v1.0.0 のリリースを機に AWS からオフィシャルにイメージも提供されるようになりました。

https://hub.docker.com/search?q=amazon%2Faws-sam-cli-&type=image

https://github.com/awslabs/aws-sam-cli/tree/master/build-image-src

## AWS SAM CLI のインストール
AWS SAM CLI のすべての機能を活用するには、前提として AWS CLI と Git, Docker のインストールが必要ですが、本記事ではこれらのインストール手順は割愛します。

### macOS
Homebrew を使用して AWS SAM CLI をインストールすることができます。

```shell-session
$ brew tap aws/tap
$ brew install aws-sam-cli
$ sam --version
SAM CLI, version 1.29.0
```

### Linux 
以下の URL からインストーラーをダウンロードできます。

```shell-session
https://github.com/aws/aws-sam-cli/releases/latest/download/aws-sam-cli-linux-x86_64.zip

$ unzip aws-sam-cli-linux-x86_64.zip -d sam-installation
$ sudo ./sam-installation/install
$ sam --version
SAM CLI, version 1.29.0
```

### Windows
以下の URL からインストーラーをダウンロードできます。

```shell-session
https://github.com/awslabs/aws-sam-cli/releases/latest/download/AWS_SAM_CLI_64_PY3.msi

> sam --version
SAM CLI, version 1.29.0
```

### その他の環境など
公式ドキュメントでは案内されていませんが、pip でもインストールできます。

```shell-session
$ pip install -U aws-sam-cli
$ sam --version
SAM CLI, version 1.29.0
```

## ローカルでの開発とテスト
### sam init
sam init コマンドを使用すると、アプリケーションのプロジェクトを初期化できます。v0.30.0 以降では対話型にサンプルアプリケーションをセットアップしたり、GitHubやローカル上のテンプレートを読み込んで初期化することもできるようになっています。

以下は対話型で `node.js14.x` のランタイムを指定したサンプルアプリケーションを作成している例です。

```shell-session
$ 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 - nodejs14.x
        2 - python3.9
        3 - ruby2.7
        4 - go1.x
        5 - java11
        6 - dotnetcore3.1
        7 - nodejs12.x
        8 - nodejs10.x
        9 - python3.8
        10 - python3.7
        11 - python3.6
        12 - python2.7
        13 - ruby2.5
        14 - java8.al2
        15 - java8
        16 - dotnetcore2.1
Runtime: 1

Project name [sam-app]:

Cloning 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: sam-app
    Runtime: nodejs14.x
    Dependency Manager: npm
    Application Template: hello-world
    Output Directory: .

```

v1.13.1 以降は AWS Lambda のコンテナイメージによるデプロイをサポートしています。こちらについては別記事を書いているので参照いただければと思います。

https://qiita.com/hayao_k/items/be0b9f984dd9ebf31696

その他のバリエーション

```shell-session
# すべてのパラメータを指定
$ sam init --runtime nodejs14.x --dependency-manager npm --app-template hello-world --name sam-app

# GitHub 上のプロジェクトを指定
$ sam init --location gh:aws-samples/cookiecutter-aws-sam-python

# ZIP ファイルやローカルのテンプレートフォルダを指定
$ sam init --location /path/to/template.zip
$ sam init --location https://example.com/path/to/template.zip
$ sam init --location /path/to/template/folder
```

nodejs14.x でのサンプルアプリケーションの場合以下のようなファイル構成となります。

```shell
sam-app
│  .gitignore
│  README.md
│  template.yaml  # SAM テンプレート
│
├─events
│   event.json  # イベントソース (API Gateway) が Lambda 関数に送信するサンプルペイロード
│
└─hello-world  # Lambda関数本体
    │  .npmignore
    │  app.js
    │  package.json
    │
    └─tests # ユニットテストファイル
        └─unit
            test-handler.js 
```

### sam build
Lambda 関数のソースコードをビルドし、デプロイ用のアーティファクトを作成することができます。

```shell-session
$ sam build
Building resource 'HelloWorldFunction'
Running NodejsNpmBuilder:NpmPack
Running NodejsNpmBuilder:CopyNpmrc
Running NodejsNpmBuilder:CopySource
Running NodejsNpmBuilder:NpmInstall
Running NodejsNpmBuilder:CleanUpNpmrc

Build Succeeded

Built Artifacts  : .aws-sam\build
Built Template   : .aws-sam\build\template.yaml

Commands you can use next
=========================
[*] Invoke Function: sam local invoke
[*] Deploy: sam deploy --guided
```

`--use-container` オプションで、実際の AWS Lambda 環境をエミュレートした Docker コンテナ内でビルドを実行することが可能です。ネイティブバイナリや複数のランタイムバージョンを扱っている場合に重宝します。

```shell-session
$ sam build --use-container

Starting Build inside a \container
Building codeuri: /home/ec2-user/sam-app/hello-world runtime: nodejs14.x metadata: {} functions: ['HelloWorldFunction']

Fetching public.ecr.aws/sam/build-nodejs14.x:latest Docker container image......
Mounting /home/ec2-user/sam-app/hello-world as /tmp/samcli/source:ro,delegated inside runtime container

Build Succeeded

Built Artifacts  : .aws-sam/build
Built Template   : .aws-sam/build/template.yaml

Commands you can use next
=========================
[*] Invoke Function: sam local invoke
[*] Deploy: sam deploy --guided

Running NodejsNpmBuilder:NpmPack
Running NodejsNpmBuilder:CopyNpmrc
Running NodejsNpmBuilder:CopySource
Running NodejsNpmBuilder:NpmInstall
Running NodejsNpmBuilder:CleanUpNpmrc
```

sam build で Lambda Layers を作成することも可能です。
こちらについても以前に別の記事を書いたので参照いただければと思います。

https://qiita.com/hayao_k/items/f8c7ad5e35e29d590957

### sam local invoke
前述の公式コンテナイメージをベースに、ローカルで Lambda 関数を起動できます。sam build で作成されたアーティファクトが存在する場合はコンテナ起動時にマウントされ、Lambda 関数の実行がエミュレートされます。

```shell-session
$ sam local invoke
Invoking app.lambdaHandler (nodejs14.x)
Image was not found.
Building image....................................................................................................
Skip pulling image and use local one: public.ecr.aws/sam/emulation-nodejs14.x:rapid-1.29.0.

Mounting /home/ec2-user/sam-app/hello-world as /var/task:ro,delegated inside runtime container
END RequestId: fa0cdfd6-9427-4ced-ba33-878bbb3769ab
REPORT RequestId: fa0cdfd6-9427-4ced-ba33-878bbb3769ab  Init Duration: 1.56 ms  Duration: 142.24 ms     Billed Duration: 200 ms Memory Size: 128 MB     Max Memory Used: 128 MB
{"statusCode":200,"body":"{\"message\":\"hello world\"}"}
```

### sam local generate-event 
特定のイベントソースのイベント情報を Lambda 関数に渡して処理したい場合、`--event` オプションで json ファイルを指定できます。`sam local generate-event` コマンドで様々なイベントソースのペイロードを作成することができます。その際、サービスごとに複数のイベントタイプを指定することができます。

DynamoDB Streams の updateイベント情報を生成し、Lambda関数を起動する例

```shell-session
$ sam local generate-event dynamodb update > ./events/dynamodb_event.json
$ sam local invoke HelloWorldFunction --event ./events/dynamodb_event.json
```

その他 v1.29.0 時点で生成に対応しているイベントソース

```shell-session
$ sam local generate-event --help
~省略~

Commands:
  alexa-skills-kit
  alexa-smart-home
  apigateway
  appsync
  batch
  cloudformation
  cloudfront
  cloudwatch
  codecommit
  codepipeline
  cognito
  config
  connect
  dynamodb
  kinesis
  lex
  rekognition
  s3
  sagemaker
  ses
  sns
  sqs
  stepfunctions
```

### sam local start-lambda
Lambda 関数の呼び出しをエミュレートするローカルエンドポイントを起動することができます。AWS CLI でローカルエンドポイントを指定したり、DynamoDB Local などの開発ツールと連携させたりすることで開発、テストを便利におこなうことができます。

```shell-session
$  sam local start-lambda
Starting the Local Lambda Service. You can now invoke your Lambda Functions defined in your template through the endpoint.
2019-12-12 14:00:04  * Running on http://127.0.0.1:3001/ (Press CTRL+C to quit)

# AWSCLIから呼び出し
$  aws lambda invoke --function-name HelloWorldFunction  --endpoint http://127.0.0.1:3001/ outfile.txt
{
    "StatusCode": 200
}
```

Step Functions Local や Dynamodb Local との連携についても以前に記事を書いたので参照いただければと思います。

https://qiita.com/hayao_k/items/14ff145a5d5c5191a18f

### sam local start-api
API 呼び出しを含めたサーバーレスアプリケーション全体のテストを行うために API Geteway のローカルインスタンスを起動することができます。起動中に Lambda 関数への変更を 行った場合は自動的にリロードされるため、start-api を再実行する必要はありません。SAM テンプレート自体を変更した場合はリスタートする必要があります。

```shell-session
$ 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
2019-12-12 14:18:08  * Running on http://127.0.0.1:3000/ (Press CTRL+C to quit)

# 起動したエンドポイントに curl で接続すると正常に応答し、hello worldを返す
$ curl http://127.0.0.1:3000/hello
{"message":"hello world"}
```

### sam validate
SAM テンプレートが SAM の仕様に沿った記述になっているか検証することができます。

```shell-session
$ sam validate
2021-08-23 13:30:33 Loading policies from IAM...
2021-08-23 13:30:37 Finished loading policies from IAM.
/home/ec2-user/sam-app/template.yaml is a valid SAM Template
```

## AWSへのデプロイ
### sam deploy
SAM で作成したアプリケーションのデプロイを行うことができます。以前は AWS SAM CLI でデプロイを行うには複数のステップが必要だったのですが、v0.33.1 以降は単一の `sam deploy` コマンドでデプロイを操作できるようになりました。

具体的には必要な設定を事前にプロジェクトルートディレクトリに設定ファイル (`samconfig.toml`)として保続しておくか、`g`, `--guided` オプションで対話的にデプロイをすすめることが可能です。初回にこのオプションを使用してデプロイすることで、選択した構成を `samconfig.toml` として保存することもできます。Lambda デプロイパッケージ用の S3 バケットも AWS SAM CLI が自動で作成し、管理します。

```shell-session

$ sam deploy -g

Configuring SAM deploy
======================

        Looking for samconfig.toml :  Not found

        Setting default arguments for 'sam deploy'
        =========================================
        Stack Name [sam-app]:                      ★CloudFormation スタック名の指定
        AWS Region [ap-northeast-1]:               ★リージョンの指定
        #Shows you resources changes to be deployed and require a 'Y' to initiate deploy
        Confirm changes before deploy [y/N]: y     ★デプロイ前にCloudformationの変更セットを確認するか
        #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]: y   ★SAM CLI に IAM ロールの作成を許可するか (CAPABILITY_IAM)
        HelloWorldFunction may not have authorization defined, Is this okay? [y/N]: y ★API イベントタイプの関数に認証が含まれていない場合、警告される
        Save arguments to samconfig.toml [Y/n]: y  ★この設定を samconfig.toml として保存するか
        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-xxxxxxxxxxxxx
                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

        Deploying with following values
        ===============================
        Stack name                 : sam-app
        Region                     : ap-northeast-1
        Confirm changeset          : True
        Deployment s3 bucket       : aws-sam-cli-managed-default-samclisourcebucket-xxxxxxxxxxxxx
        Capabilities               : ["CAPABILITY_IAM"]
        Parameter overrides        : {}
        Signing Profiles           : {}

Initiating deployment
=====================
Uploading to sam-app/93b0336bb7eaf29265c790583055f1c5.template  1090 / 1090  (100.00%)

Waiting for changeset to be created..

CloudFormation stack changeset
------------------------------------------------------------------------------------------------------------------------------------------------
Operation                                        LogicalResourceId                                ResourceType
------------------------------------------------------------------------------------------------------------------------------------------------
+ Add                                            HelloWorldFunctionHelloWorldPermissionProd       AWS::Lambda::Permission
+ Add                                            HelloWorldFunctionRole                           AWS::IAM::Role
+ Add                                            HelloWorldFunction                               AWS::Lambda::Function
+ Add                                            ServerlessRestApiDeployment47fc2d5f9d            AWS::ApiGateway::Deployment
+ Add                                            ServerlessRestApiProdStage                       AWS::ApiGateway::Stage
+ Add                                            ServerlessRestApi                                AWS::ApiGateway::RestApi
------------------------------------------------------------------------------------------------------------------------------------------------

Changeset created successfully. arn:aws:cloudformation:ap-northeast-1:123456789012:changeSet/samcli-deploy1576228579/a9ee2685-452f-47d0-851f-92e2ff217c9c


Previewing CloudFormation changeset before deployment
======================================================
Deploy this changeset? [y/N]: y     ★変更セットを確認し、デプロイ実行

2021-08-23 15:00:33 - 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::RestApi             ServerlessRestApi                    -
CREATE_IN_PROGRESS                   AWS::ApiGateway::RestApi             ServerlessRestApi                    Resource creation Initiated
CREATE_COMPLETE                      AWS::ApiGateway::RestApi             ServerlessRestApi                    -
CREATE_IN_PROGRESS                   AWS::Lambda::Permission              HelloWorldFunctionHelloWorldPermis   Resource creation Initiated
                                                                          sionProd
CREATE_IN_PROGRESS                   AWS::Lambda::Permission              HelloWorldFunctionHelloWorldPermis   -
                                                                          sionProd
CREATE_IN_PROGRESS                   AWS::ApiGateway::Deployment          ServerlessRestApiDeployment47fc2d5   -
                                                                          f9d
CREATE_IN_PROGRESS                   AWS::ApiGateway::Deployment          ServerlessRestApiDeployment47fc2d5   Resource creation Initiated
                                                                          f9d
CREATE_COMPLETE                      AWS::ApiGateway::Deployment          ServerlessRestApiDeployment47fc2d5   -
                                                                          f9d
CREATE_IN_PROGRESS                   AWS::ApiGateway::Stage               ServerlessRestApiProdStage           -
CREATE_IN_PROGRESS                   AWS::ApiGateway::Stage               ServerlessRestApiProdStage           Resource creation Initiated
CREATE_COMPLETE                      AWS::ApiGateway::Stage               ServerlessRestApiProdStage           -
CREATE_COMPLETE                      AWS::Lambda::Permission              HelloWorldFunctionHelloWorldPermis   -
                                                                          sionProd
CREATE_COMPLETE                      AWS::CloudFormation::Stack           sam-app                              -
-------------------------------------------------------------------------------------------------------------------------------------------------

Stack sam-app outputs:
-------------------------------------------------------------------------------------------------------------------------------------------------
OutputKey-Description                                                    OutputValue
-------------------------------------------------------------------------------------------------------------------------------------------------
HelloWorldFunctionIamRole - Implicit IAM Role created for Hello World    arn:aws:iam::123456789012:role/sam-app-
function                                                                 HelloWorldFunctionRole-1OUZSV1ENAMCB
HelloWorldApi - API Gateway endpoint URL for Prod stage for Hello        https://xxxxxxxxxx.execute-api.ap-
World function                                                           northeast-1.amazonaws.com/Prod/hello/
HelloWorldFunction - Hello World Lambda Function ARN                     arn:aws:lambda:ap-northeast-1:123456789012:function:sam-app-
                                                                         HelloWorldFunction-1IFZY75A4HM3V
-------------------------------------------------------------------------------------------------------------------------------------------------

Successfully created/updated stack - sam-app in ap-northeast-1
```

作成された `samconfig.toml` は以下のようになります。toml とは設定ファイルを定義するためのフォーマットの1種で、CloudWatch Agent などでも採用されています。

```samconfig.toml
[default]
[default.deploy]
[default.deploy.parameters]
stack_name = "sam-app"
s3_bucket = "aws-sam-cli-managed-default-samclisourcebucket-xxxxxxxxxxxxx"
s3_prefix = "sam-app"
region = "ap-northeast-1"
confirm_changeset = true
capabilities = "CAPABILITY_IAM"
```

`samconfig.toml` がプロジェクトのルートディレクトリに存在していれば `sam deploy` コマンドだけでデプロイを行うことができます。

```shell-session
$ sam deploy

        Deploying with following values
        ===============================
        Stack name                 : sam-app
        Region                     : ap-northeast-1
        Confirm changeset          : True
        Deployment s3 bucket       : aws-sam-cli-managed-default-samclisourcebucket-xxxxxxxxxxxxx
        Capabilities               : ["CAPABILITY_IAM"]
        Parameter overrides        : {}

Initiating deployment
=====================
HelloWorldFunction may not have authorization defined.

Waiting for changeset to be created..
~以下省略~
```

OutputValue に出力された API Gateway のエンドポイントに接続すると、正常に応答が得られました。

```shell-session
$ curl https://xxxxxxxxxx.execute-api.ap-northeast-1.amazonaws.com/Prod/hello/
{"message":"hello world"}
```

### sam package
SAM で作成したアプリケーションをパッケージ化できます。具体的には以下のことを行っています。

* Lambda 関数デプロイ用の ZIP ファイルを作成し、指定した S3 バケットにアップロード
* CodeUri の参照をローカルからアップロードした S3 のパスに書き換え

これらの処理は v0.33.1 以降であれば、sam deploy コマンド内で暗黙的実行されているため、個別に `sam package` コマンドを使用する必要はありません。v0.33.1 以前のように sam `package` と `sam deploy` 個別に実行しデプロイすることも可能です。

```shell-session
$ sam package --template-file template.yaml \
  --s3-bucket <bucket-name> --output-template-file packaged.yaml
Uploading to 65113397247fb02f6ff4bad985a3240c  2421730 / 2421730.0  (100.00%)

Successfully packaged artifacts and wrote output template to file packaged.yaml.
Execute the following command to deploy the packaged template
sam deploy --template-file /home/ec2-user/sam-app/packaged.yaml --stack-name <YOUR STACK NAME>

$ sam deploy --template-file packaged.yaml --stack-name sam-app --capabilities CAPABILITY_IAM
```

返されたSAMテンプレートを確認すると CodeUri が S3 のパスに書き換わっていることがわかります。

```diff
 Resources:
   HelloWorldFunction:
     Type: AWS::Serverless::Function
     Properties:
-      CodeUri: hello-world/
+      CodeUri: s3://<bucket-name>/65113397247fb02f6ff4bad985a3240c
       Handler: app.lambdaHandler
       Runtime: nodejs14.x
```

### sam publish
SAM で作成したアプリケーションを AWS Serverless Application Repository に公開できます。publish を実行するには SAM テンプレート内の Metadata に公開のために必要な情報を定義する必要があります。`LICENSE.txt` および、`README.md` も用意しておく必要があります。

```template.yaml
# publish を実行するにはメタデータが必要
Metadata:
  AWS::ServerlessRepo::Application:
    Name: my-app
    Description: hello world
    Author: user1
    SpdxLicenseId: Apache-2.0
    LicenseUrl: LICENSE.txt
    ReadmeUrl: README.md
    Labels: ['tests']
    HomePageUrl: https://github.com/user1/my-app-project
    SemanticVersion: 0.0.1
    SourceCodeUrl: https://github.com/user1/my-app-project
```

また Serverless Application Repository がアーティファクトが格納されている S3 バケットを参照することができるように、対象のバケットに以下のようなポリシーの追加が必要です。

```policy.json
{
    "Version": "2012-10-17",
    "Statement": [
        {
            "Effect": "Allow",
            "Principal": {
                "Service":  "serverlessrepo.amazonaws.com"
            },
            "Action": "s3:GetObject",
            "Resource": "arn:aws:s3:::<your-bucket-name>/*"
            "Condition" : {
                "StringEquals": {
                    "aws:SourceAccount": "<your-account-id>"
                }
            }
        }
    ]
}
```

テンプレートファイル内の LicenseUrl, ReadmeUrl, CodeUri は S3 上のファイルを指定する必要があるため、前述の `sam package` コマンドでパッケージ化後に publish を行います。

```shell-session
$ sam package --template-file template.yaml \
  --s3-bucket <bucket-name> --output-template-file packaged.yaml
~出力は省略~
```

LICENSE.txt および README.md も package コマンドにより S3にアップロードされ、各 Urlが書き換わっていることがわかります。

```diff
 Metadata:
   AWS::ServerlessRepo::Application:
     Name: my-app
     Description: hello world
     Author: user1
     SpdxLicenseId: Apache-2.0
-     LicenseUrl: LICENSE.txt
+     LicenseUrl: s3://<bukcet-name>/d41d8cd98f00b204e9800998ecf8427e
-     ReadmeUrl: README.md
+     ReadmeUrl: s3://<bukcet-name>/2a258235395cbaff804bbaab61a6d4ec
~以下略~
```

パッケージ後のテンプレートとリージョンを指定して publish します。アプリケーションはプライベートアプリケーションとして SAR に登録されます。

```shell-session
$ sam publish --template packaged.yaml --region ap-northeast-1
Created new application with the following metadata:
{
  "Name": "my-app",
  "Description": "hello world",
  "Author": "user1",
  "SpdxLicenseId": "Apache-2.0",
  "LicenseUrl": "s3://<bucket-name>/d41d8cd98f00b204e9800998ecf8427e",
  "ReadmeUrl": "s3://<bucket-name/2a258235395cbaff804bbaab61a6d4ec",
  "Labels": [
    "tests"
  ],
  "HomePageUrl": "https://github.com/user1/my-app-project",
  "SemanticVersion": "0.0.1",
  "SourceCodeUrl": "https://github.com/user1/my-app-project"
}
Click the link below to view your application in AWS console:
https://console.aws.amazon.com/serverlessrepo/home?region=ap-northeast-1#/published-applications/arn:aws:serverlessrepo:ap-northeast-1:0123456789012:applications~my-app
```

SAR のコンソールを確認すると、正常にアプリケーションが登録されてプライベートアプリケーションとして利用可能になっています。

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/125105/e4f49f0a-b983-91ea-c652-dc1e0408ed6f.png)

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/125105/4513db6e-1041-846a-4645-24a2ac1f26bb.png)

### sam delete
v1.29.0 以降で利用可能な SAM アプリケーションを削除するコマンドです。AWS SAM CLI によってデプロイされた CloudFormation スタック、S3 や ECR にパッケージ化およびデプロイされたアーティファクト、SAM テンプレートファイルを削除します。ローカルのファイルは削除されません。`--no-prompts` を指定すると確認メッセージなしで削除できます。

```shell-session
$ sam delete
        Are you sure you want to delete the stack sam-app in the region ap-northeast-1 ? [y/N]: y
        Are you sure you want to delete the folder sam-app in S3 which contains the artifacts? [y/N]: y
        - Deleting S3 object with key sam-app/b71fea080e2e2e88f4ef92ab98d33d0a
        - Deleting S3 object with key sam-app/93b0336bb7eaf29265c790583055f1c5.template
        - Deleting Cloudformation stack sam-app

Deleted successfully
```

## CI/CD パイプラインの作成

:::note warn
AWS SAM Pipelines は 2021/7/21 にアナウンスされたパブリックプレビューの機能です。2021/8/24 時点の情報を記載していますが、将来的に動作が変更になる可能性があるためご注意ください。
:::

AWS SAM Pipelines を使用すると、簡単に CI/CD パイプラインを作成することができます。

### sam pipeline bootstrap
CI/CD パイプラインの作成に必要な AWS リソースを作成する設定コマンドです。以下について既存の ARN を指定するか新規に作成することができます。このコマンドによりパイプラインの各ステージに必要なリソースを事前に作成しておくことができます。

* パイプライン用 IAM ユーザー
* パイプライン実行用 IAM ロール
* CloudFormation 実行用ロール
* アーティファクト格納用 S3 バケット
* ECR のイメージレポジトリ (AWS Lambda のコンテナサポートを使用する場合)

設定の入力が完了すると、`aws-sam-cli-managed-<ステージ名>-pipeline-resources` という CloudFormation スタックがデプロイされ、上述の各リソースが作成されます。

```shell-session
# sam pipeline bootstrap

sam pipeline bootstrap generates the required AWS infrastructure resources to connect
to your CI/CD system. This step must be run for each deployment stage in your pipeline,
prior to running the sam pipeline init command.

We will ask for [1] stage definition, [2] account details, and
[3] references to existing resources in order to bootstrap these pipeline resources.

[1] Stage definition
Enter a name for this stage. This will be referenced later when you use the sam pipeline init command:
Stage name: dev ★ステージ名を入力

[2] Account details
The following AWS credential sources are available to use:
To know more about configuration AWS credentials, visit the link below:
https://docs.aws.amazon.com/cli/latest/userguide/cli-configure-files.html
        1 - Environment variables (not available)
        2 - default (named profile)
        q - Quit and configure AWS credentials
Select a credential source to associate with this stage: 2 ★クレデンシャル情報を選択
Associated account 123456789012 with stage dev.

Enter the region in which you want these resources to be created [ap-northeast-1]: ★リージョンを入力
Enter the pipeline IAM user ARN if you have previously created one, or we will create one for you []: ★パイプライン用 IAM ユーザー名の入力

[3] Reference application build resources
Enter the pipeline execution role ARN if you have previously created one, or we will create one for you []: ★パイプライン実行用 IAM ロールの入力
Enter the CloudFormation execution role ARN if you have previously created one, or we will create one for you []:　★ CloudFormation 実行用 IAM ロールの入力
Please enter the artifact bucket ARN for your Lambda function. If you do not have a bucket, we will create one for you []: ★アーティファクト用 S3 バケットの入力
Does your application contain any IMAGE type Lambda functions? [y/N]: n ★ AWS Lambda でコンテナイメージを使用しているか

[4] Summary
Below is the summary of the answers:
        1 - Account: 123456789012
        2 - Stage name: dev
        3 - Region: ap-northeast-1
        4 - Pipeline user: [to be created]
        5 - Pipeline execution role: [to be created]
        6 - CloudFormation execution role: [to be created]
        7 - Artifacts bucket: [to be created]
        8 - ECR image repository: [skipped]
Press enter to confirm the values above, or select an item to edit the value:

This will create the following required resources for the 'dev' environment:
        - Pipeline IAM user
        - Pipeline execution role
        - CloudFormation execution role
        - Artifact bucket
Should we proceed with the creation? [y/N]: y

        Looking for resources needed for deployment: Not found.
        Creating the required resources...
        Successfully created!
The following resources were created in your account:
        - Pipeline IAM user
        - Pipeline execution role
        - CloudFormation execution role
        - Artifact bucket
Pipeline IAM user credential:
        AWS_ACCESS_KEY_ID: XXXXXXXXXXXXXXXXXXXX
        AWS_SECRET_ACCESS_KEY: YYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYY
View the definition in .aws-sam/pipeline/pipelineconfig.toml,
run sam pipeline bootstrap to generate another set of resources, or proceed to
sam pipeline init to create your pipeline configuration file.

Before running sam pipeline init, we recommend first setting up AWS credentials
in your CI/CD account. Read more about how to do so with your provider in
https://docs.aws.amazon.com/serverless-application-model/latest/developerguide/serverless-generating-example-ci-cd-others.html.
```

作成されたステージの定義と紐づくリソースの情報は `.aws-sam/pipeline/pipelineconfig.toml` に保存されます。

```shell-session
cat pipelineconfig.toml
version = 0.1
[default]
[default.pipeline_bootstrap]
[default.pipeline_bootstrap.parameters]
pipeline_user = "arn:aws:iam::123456789012:user/aws-sam-cli-managed-dev-pipeline-reso-PipelineUser-XXXXXXXXXXXX"

[dev]
[dev.pipeline_bootstrap]
[dev.pipeline_bootstrap.parameters]
pipeline_execution_role = "arn:aws:iam::123456789012:role/aws-sam-cli-managed-dev-pipe-PipelineExecutionRole-XXXXXXXXXXXXX"
cloudformation_execution_role = "arn:aws:iam::123456789012:role/aws-sam-cli-managed-dev-p-CloudFormationExecutionR-XXXXXXXXXXXX"
artifacts_bucket = "aws-sam-cli-managed-dev-pipeline-artifactsbucket-XXXXXXXXXXXX"
image_repository = ""
region = "ap-northeast-1"
```

### sam pipeline init
AWS SAM Pipelines が対応する CI/CD ツールの設定ファイルを生成するコマンドです。対応するツールは以下のとおりです。

* Jenkins (`Jenkinsfile`)
* GitLab CI/CD (`.gitlab-ci.yml`)
* GitHub Actions (`.github/workflows/pipeline.yaml`)
* AWS CodePipeline (CloudFormation テンプレートおよび buildspec ファイル)

以下はクイックスタートのテンプレートを使用して GitHub Actions のワークフロー定義ファイルを作成する例です。クイックスタートテンプレートは 2 ステージ構成となっているため、あらかじめ `sam pipeline bootstrap` コマンドで 2 ステージ作成しておくか、`sam pipeline init --bootstrap` を実行してください。

:::note info
--botstrap オプションをつけて sam pipeline init 実行することで必要なステージと紐づく AWS リソースの作成を同時に行うことができます。
:::


```shell-session
$ sam pipeline init

sam pipeline init generates a pipeline configuration file that your CI/CD system
can use to deploy serverless applications using AWS SAM.
We will guide you through the process to bootstrap resources for each stage,
then walk through the details necessary for creating the pipeline config file.

Please ensure you are in the root folder of your SAM application before you begin.

Select a pipeline structure template to get started:
Select template
        1 - AWS Quick Start Pipeline Templates
        2 - Custom Pipeline Template Location
Choice: 1  ★クイックスタートテンプレートを選択

Cloning from https://github.com/aws/aws-sam-cli-pipeline-init-templates.git
CI/CD system
        1 - Jenkins
        2 - GitLab CI/CD
        3 - GitHub Actions
        4 - AWS CodePipeline
Choice: 3  ★GitHub Actions を選択
You are using the 2-stage pipeline template.
 _________    _________
|         |  |         |
| Stage 1 |->| Stage 2 |
|_________|  |_________|

Checking for existing stages...


This template configures a pipeline that deploys a serverless application to a testing and a production stage.

What is the GitHub secret name for pipeline user account access key ID? [AWS_ACCESS_KEY_ID]:  ★pipeline ユーザーのアクセスキーを入力
What is the GitHub Secret name for pipeline user account access key secret? [AWS_SECRET_ACCESS_KEY]:  ★pipeline ユーザーのシークレットアクセスキーを入力
What is the git branch used for production deployments? [main]:　★本番環境で指定するブランチ名の指定
What is the template file path? [template.yaml]:　★SAM テンプレートファイルのパスを指定
We use the stage name to automatically retrieve the bootstrapped resources created when you ran `sam pipeline bootstrap`.

Here are the stage names detected in .aws-sam/pipeline/pipelineconfig.toml: ★事前に bootstrap で作成済みのステージを検知
        1 - dev
        2 - prod
What is the name of stage 1 (as provided during the bootstrapping)?
Select an index or enter the stage name: 1
What is the sam application stack name for stage 1? [sam-app-dev]:
Stage 1 configured successfully, configuring stage 2.

Here are the stage names detected in .aws-sam/pipeline/pipelineconfig.toml:
        1 - dev
        2 - prod
What is the name of stage 2 (as provided during the bootstrapping)?
Select an index or enter the stage name: 2
What is the sam application stack name for stage 2? [sam-app-prod]:
Stage 2 configured successfully.

SUMMARY
We will generate a pipeline config file based on the following information:
        What is the GitHub secret name for pipeline user account access key ID?: XXXXXXXXXXXXXXXXXXXX
        What is the GitHub Secret name for pipeline user account access key secret?: YYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYY
        What is the git branch used for production deployments?: main
        What is the template file path?: template.yaml
        What is the name of stage 1 (as provided during the bootstrapping)?
Select an index or enter the stage name: 1
        What is the sam application stack name for stage 1?: sam-app-dev
        What is the pipeline execution role ARN for stage 1?: arn:aws:iam::123456789012:role/aws-sam-cli-managed-dev-pipe-PipelineExecutionRole-XXXXXXXXXXXXX
        What is the CloudFormation execution role ARN for stage 1?: arn:aws:iam::123456789012:role/aws-sam-cli-managed-dev-p-CloudFormationExecutionR-XXXXXXXXXXXXX
        What is the S3 bucket name for artifacts for stage 1?: aws-sam-cli-managed-dev-pipeline-artifactsbucket-XXXXXXXXXXXXX
        What is the ECR repository URI for stage 1?:
        What is the AWS region for stage 1?: ap-northeast-1
        What is the name of stage 2 (as provided during the bootstrapping)?
Select an index or enter the stage name: 2
        What is the sam application stack name for stage 2?: sam-app-prod
        What is the pipeline execution role ARN for stage 2?: arn:aws:iam::123456789012:role/aws-sam-cli-managed-prod-pip-PipelineExecutionRole-XXXXXXXXXXXXX
        What is the CloudFormation execution role ARN for stage 2?: arn:aws:iam::123456789012:role/aws-sam-cli-managed-prod-CloudFormationExecutionR-XXXXXXXXXXXXX
        What is the S3 bucket name for artifacts for stage 2?: aws-sam-cli-managed-prod-pipeline-artifactsbucket-XXXXXXXXXXXXX
        What is the ECR repository URI for stage 2?:
        What is the AWS region for stage 2?: ap-northeast-1
Successfully created the pipeline configuration file(s):
        - .github/workflows/pipeline.yaml
```

生成された `.github/workflows/pipeline.yaml` を GitHub に Push すれば GitHub Actions による CI/CD パイプラインを実行できます。

## その他の機能
### sam logs
デプロイ済みの Lambda 関数のログを取得できます。
`--tail` でログをたれ流したり、`--filter "文字列"` でフィルタリングすることもできます。
以下では CloudFormation のスタック名と関数名を指定しています。

```shell-session
$ sam logs -n HelloWorldFunction --stack-name sam-app
2018/07/20/[$LATEST]c1e4c40fbbf2495aa91ecff5b21ce24d 2018-07-20T07:24:37.835000 START RequestId: f5664465-8bed-11e8-994b-8d4b4bdcc800 Version: $LATEST
2018/07/20/[$LATEST]c1e4c40fbbf2495aa91ecff5b21ce24d 2018-07-20T07:24:38.395000 END RequestId: f5664465-8bed-11e8-994b-8d4b4bdcc800
2018/07/20/[$LATEST]c1e4c40fbbf2495aa91ecff5b21ce24d 2018-07-20T07:24:38.395000 REPORT RequestId: f5664465-8bed-11e8-994b-8d4b4bdcc800  Duration: 542.93 ms     Billed Duration: 600 ms        Memory Size: 128 MB     Max Memory Used: 22 MB
```

もしくは関数名を直接指定してもよいので、AWS SAM CLI や CloudFormation でデプロイされたかどうかは関係なく、全ての Lanmbda 関数に対して実行できます。またフィルタリングした結果を tail するなどの組み合わせもできるのでトラブルシューティングを迅速に行うことができます。

```shell-session
$ sam logs -n ECRScanToSlack --tail --filter "INFO"
2019/12/12/[$LATEST]76c0c056a02541a8bf7b2568e9e8b06d 2019-12-12T08:32:26.793000 [INFO]  2019-12-12T08:32:26.792Z
        506de805-fb06-426f-b6b0-e89f2eb23660    Found credentials in environment variables.
2019/12/12/[$LATEST]76c0c056a02541a8bf7b2568e9e8b06d 2019-12-12T08:32:28.411000 [INFO]  2019-12-12T08:32:28.408Z
        506de805-fb06-426f-b6b0-e89f2eb23660    Message posted.
2019/12/12/[$LATEST]76c0c056a02541a8bf7b2568e9e8b06d 2019-12-12T08:34:32.572000 [INFO]  2019-12-12T08:34:32.572Z
        3dcde807-f150-4056-bb12-b791b77d0731    Message posted.
2019/12/12/[$LATEST]76c0c056a02541a8bf7b2568e9e8b06d 2019-12-12T08:34:35.812000 [INFO]  2019-12-12T08:34:35.811Z
        5ac31616-be63-4402-90ab-4d9b0b74a1a6    Message posted.
```

### Lambda Layersへの対応
AWS SAM CLI は Labmda Layers を使用した関数のローカル実行にも対応しています。(v0.8.1以降)
以下は Lambda Layers を含む SAM テンプレートの例です。

```template.yaml
# 該当箇所を抜粋
Resources:
  HelloWorldFunction:
    Type: AWS::Serverless::Function
    Properties:
      CodeUri: hello_world/
      Handler: app.lambda_handler
      Runtime: python3.8
      Layers:
        - arn:aws:lambda:ap-northeast-1:123456789012:layer:python-boto3:1 # Layerの指定
```

ローカル実行時、AWS SAM CLI は対象の Layer のパッケージをダウンロードし、ローカルにキャッシュします。その後、提供されているコンテナイメージをベースに対象 Layer のキャッシュがオーバーレイされたコンテナイメージが自動でビルドされ、そのイメージを使用して実行が行われます。

```shell-session
$ sam local invoke
Invoking app.lambda_handler (python3.8)
Image was not found.
Building image......................................................
Requested to skip pulling images ...

Mounting C:\test\sam-app2\hello_world as /var/task:ro,delegated inside runtime container
START RequestId: bfee13e1-74be-1953-d236-aa7e0bc13d8e Version: $LATEST
END RequestId: bfee13e1-74be-1953-d236-aa7e0bc13d8e
REPORT RequestId: bfee13e1-74be-1953-d236-aa7e0bc13d8e     Init Duration: 310.57 ms        Duration: 4.80 ms      Billed Duration: 100 ms Memory Size: 128 MB     Max Memory Used: 23 MB

{"statusCode":200,"body":"{\"message\": \"hello world\"}"}

# samcli/lambda が Layer が展開された後のコンテナイメージ
$ docker image ls
REPOSITORY                                    TAG                                   IMAGE ID       CREATED          SIZE
samcli/lambda                                 python3.8-a84bc9cd09799899970128014   99ac7e22ab97   13 seconds ago   548MB
amazon/aws-sam-cli-emulation-image-python3.8  latest                                0b8397b4f176   36 hours ago     490MB
```

### AWS Toolkit と AWS SAM CLI によるデバッグ
各種 IDE に対応した AWS Toolkit は AWS SAM との親和性が高く、SAM アプリケーションの作成、デバッグ、デプロイを行うことができます。以下は AWS Toolkit for Visual Studio Code 拡張で Node.js ランタイムの Lambda 関数のデバッグを行う例です。

デバッグの起動構成に以下のような構成を追加します。(.vscode/launch.json)

```launch.json
{
    "version": "0.2.0",
    "configurations": [
        {
            "name": "Attach to SAM CLI",
            "type": "node",
            "request": "attach",
            "address": "localhost",
            "port": 5858,
            "localRoot": "${workspaceRoot}/hello-world",
            "remoteRoot": "/var/task",
            "protocol": "inspector",
            "stopOnEntry": false
        }
    ]
}
```

-d, --debug-port オプションを指定し、sam local invoke します。

```shell-session
$ sam local invoke -e ./events/event.json -d 5858
Invoking app.lambdaHandler (nodejs10.x)

Fetching lambci/lambda:nodejs10.x Docker container image......
Mounting C:\vscode\sam-app\hello-world as /var/task:ro,delegated inside runtime container
Debugger listening on ws://0.0.0.0:5858/3e80f80b-bbaa-4a6c-b087-7f2f3fd46b6b
For help, see: https://nodejs.org/en/docs/inspector
```

Lambda 関数がデバッグモードで起動しますので、Visual Studio Code 側で設定した起動設定からデバッグを開始することができます。

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/125105/d50d2e3f-cefe-2064-9f51-8941310f243a.png)

## 参考
**AWS Serverless Application Model - Developer Guide**
https://docs.aws.amazon.com/serverless-application-model/latest/developerguide/what-is-sam.html
**GitHub - aws-sam-cli Releases**
https://github.com/awslabs/aws-sam-cli/releases

以上です。
参考になれば幸いです。