AWS SAM CLIのチュートリアルやってみた

業務でAWS SAM CLIを学ぶ必要性がでてきたので、下記チュートリアルを実施しました。

https://docs.aws.amazon.com/ja_jp/serverless-application-model/latest/developerguide/serverless-getting-started-hello-world.html


このチュートリアルを、M1のMacbook Air（Sequoia 15.3.2）でやった際のメモ書きとなります。

## SAM CLIのインストール
まずは下記からSAM CLIパッケージをダウンロードします。

https://github.com/aws/aws-sam-cli/releases/latest/download/aws-sam-cli-macos-arm64.pkg

ダウンロードしたパッケージを任意のディレクトリにおき、そこで下記インストールコマンドを実行します。

```
$ sudo installer -pkg aws-sam-cli-macos-arm64.pkg -target /
Password:
installer: Package name is AWS SAM CLI
installer: Installing at base path /
installer: The install was successful.
```

無事インストールが終わったので、念の為、正常にインストールされたか確認します。
```
$ which sam
/usr/local/bin/sam

$ sam --version
SAM CLI, version 1.136.0

```

## SAMプロジェクトの初期化
SAMプロジェクトの初期化を行います。
今回は、Node.js（ver22）でTypeScriptを選択しました。

```
$ mkdir sam-tutorial

$ cd sam-tutorial

$ sam init

You can preselect a particular runtime or package type when using the `sam init` experience.
Call `sam init --help` to learn more.

Which template source would you like to use?
	1 - AWS Quick Start Templates
	2 - Custom Template Location
Choice: 1

Choose an AWS Quick Start application template
	1 - Hello World Example
	2 - Data processing
	3 - Hello World Example with Powertools for AWS Lambda
	4 - Multi-step workflow
	5 - Scheduled task
	6 - Standalone function
	7 - Serverless API
	8 - Infrastructure event management
	9 - Lambda Response Streaming
	10 - GraphQLApi Hello World Example
	11 - Full Stack
	12 - Lambda EFS example
	13 - Serverless Connector Hello World Example
	14 - Multi-step workflow with Connectors
	15 - DynamoDB Example
	16 - Machine Learning
Template: 1

Use the most popular runtime and package type? (python3.13 and zip) [y/N]: n

Which runtime would you like to use?
	1 - dotnet8
	2 - dotnet6
	3 - go (provided.al2)
	4 - go (provided.al2023)
	5 - graalvm.java11 (provided.al2)
	6 - graalvm.java17 (provided.al2)
	7 - java21
	8 - java17
	9 - java11
	10 - java8.al2
	11 - nodejs22.x
	12 - nodejs20.x
	13 - nodejs18.x
	14 - python3.9
	15 - python3.13
	16 - python3.12
	17 - python3.11
	18 - python3.10
	19 - ruby3.4
	20 - ruby3.3
	21 - ruby3.2
	22 - rust (provided.al2)
	23 - rust (provided.al2023)
Runtime: 11

What package type would you like to use?
	1 - Zip
	2 - Image
Package type: 1

Based on your selections, the only dependency manager available is npm.
We will proceed copying the template using npm.

Select your starter template
	1 - Hello World Example
	2 - Hello World Example TypeScript
Template: 2

Would you like to enable X-Ray tracing on the function(s) in your application?  [y/N]: n

Would you like to enable monitoring using CloudWatch Application Insights?
For more info, please view https://docs.aws.amazon.com/AmazonCloudWatch/latest/monitoring/cloudwatch-application-insights.html [y/N]: n

Would you like to set Structured Logging in JSON format on your Lambda functions?  [y/N]: n

Project name [sam-app]: sam-app

    -----------------------
    Generating application:
    -----------------------
    Name: sam-app
    Runtime: nodejs22.x
    Architectures: x86_64
    Dependency Manager: npm
    Application Template: hello-world-typescript
    Output Directory: .
    Configuration file: sam-app/samconfig.toml

    Next steps can be found in the README file at sam-app/README.md


Commands you can use next
=========================
[*] Create pipeline: cd sam-app && sam pipeline init --bootstrap
[*] Validate SAM template: cd sam-app && sam validate
[*] Test Function in the Cloud: cd sam-app && sam sync --stack-name {stack-name} --watch

```
プロジェクトの初期化が完了したので出力されたフォルダをここで確認しておきます。

```
tree
.
└── sam-app
    ├── README.md
    ├── events
    │   └── event.json
    ├── hello-world
    │   ├── app.ts
    │   ├── jest.config.ts
    │   ├── package.json
    │   ├── tests
    │   │   └── unit
    │   │       └── test-handler.test.ts
    │   └── tsconfig.json
    ├── samconfig.toml
    └── template.yaml

6 directories, 9 files

```
ポイントとなるファイルは下記となります。
- `sam-app/hello-world/app.ts`：Lambda関数のコード
- `sam-app/samconfig.toml`：SAMのデフォルトパラメータ設定ファイル
- `sam-app/template.yaml`：SAMテンプレートファイル

## アプリケーションの構築
アプリをビルドしてみます。
```
$ sam build
Error: Template file not found at /Users/kazunori/repo/sam-tutorial-2/template.yml
```
拡張子が異なるよと怒られたので、ファイル名を指定してもう一度ビルドします。
```
$ sam build --template-file template.yaml
Starting Build use cache                                                                                                             
Manifest file is changed (new hash: 3a55b648027d1145164f225fad481127) or dependency folder                                           
(.aws-sam/deps/5496a8c1-21da-43c5-8702-c49ca5470c0b) is missing for (HelloWorldFunction), downloading dependencies and               
copying/building source                                                                                                              
Building codeuri: /Users/kazunori/repo/sam-tutorial-2/sam-app/hello-world runtime: nodejs22.x architecture: x86_64 functions:        
HelloWorldFunction                                                                                                                   
 Running NodejsNpmEsbuildBuilder:CopySource                                                                                          
 Running NodejsNpmEsbuildBuilder:NpmInstall                                                                                          
 Running NodejsNpmEsbuildBuilder:EsbuildBundle                                                                                       
 Running NodejsNpmEsbuildBuilder:CleanUp                                                                                             
 Running NodejsNpmEsbuildBuilder:MoveDependencies                                                                                    
                                                                                                                                     
Sourcemap set without --enable-source-maps, adding --enable-source-maps to function HelloWorldFunction NODE_OPTIONS                  
                                                                                                                                     
You are using source maps, note that this comes with a performance hit! Set Sourcemap to false and remove NODE_OPTIONS:              
--enable-source-maps to disable source maps.                                                                                         
                                                                                                                                     

Build Succeeded

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

Commands you can use next
=========================
[*] Validate SAM template: sam validate
[*] Invoke Function: sam local invoke
[*] Test Function in the Cloud: sam sync --stack-name {{stack-name}} --watch
[*] Deploy: sam deploy --guided
```
ビルドすると、`.aws-sam`ディレクトリ配下にビルドファイルが出力されています。

```
tree -a
.
├── .aws-sam
│   ├── build
│   │   ├── HelloWorldFunction
│   │   │   ├── app.js
│   │   │   └── app.js.map
│   │   └── template.yaml
│   ├── build.toml
│   ├── cache
│   └── deps
（以下省略）
```

## AWSへデプロイ
AWSへデプロイしてみます。
IAMユーザーに下記AWS管理ポリシーをアタッチすればデプロイできます。
- AmazonAPIGatewayAdministrator
- AWSLambda_FullAccess
- AWSCloudFormationFullAccess
- AmazonS3FullAccess
- IAMFullAccess

```
$ sam deploy --guided     

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

        Looking for config file [samconfig.toml] :  Found
        Reading default arguments  :  Success

        Setting default arguments for 'sam deploy'
        =========================================
        Stack Name [sam-app]: 
        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]: 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]: y
        #Preserves the state of previously provisioned resources when an operation fails
        Disable rollback [y/N]: n
        HelloWorldFunction has no authentication. Is this okay? [y/N]: y
        Save arguments to configuration file [Y/n]: y
        SAM configuration file [samconfig.toml]: 
        SAM configuration environment [default]: 

 （〜省略〜）


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

簡単にデプロイできました。
## アプリケーションの実行

デプロイしたAPIエンドポイントを実行してみます。
```
$ curl https://xxxxxxxxxx.execute-api.ap-northeast-1.amazonaws.com/Prod/hello/  
{"message":"hello world"}%  
```

リモートでLambda関数を実行してみます。
```
$ sam remote invoke HelloWorldFunction --stack-name sam-app
Invoking Lambda Function HelloWorldFunction                                                                                                                                    
START RequestId: b9c55556-00cd-4423-aa96-5932256c096d Version: $LATEST
END RequestId: b9c55556-00cd-4423-aa96-5932256c096d
REPORT RequestId: b9c55556-00cd-4423-aa96-5932256c096d  Duration: 1.62 ms       Billed Duration: 2 ms   Memory Size: 128 MB     Max Memory Used: 69 MB
{"statusCode":200,"body":"{\"message\":\"hello world\"}"}%     
```
問題ないようです。

## アプリケーションの削除
最後にアプリを削除してみます。
```
$ 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/9b50565930077c7654a2bdad51e868cf                                                                                                 
        - Deleting S3 object with key sam-app/81b007ef11efb88c3bf02732d480e41d.template                                                                                        
        - Deleting Cloudformation stack sam-app

Deleted successfully
```
SAM CLI便利ですね。
まだまだわかっていないことだらけですがこれからいろいろ学んでいきたいと思っています。