はじめに
インプルの矢島です。
AWS DVAの勉強でSAMを使ってデプロイとローカルでの検証をした内容をまとめます。
こちらは、超初心者向けです。また、このような内容はすでに素晴らしい記事は多いかと思いますが、勉強の一貫でまとめたので、最後まで読んでいただけますと嬉しいです。
AWS SAMとは
正式名称はServerless Application Modelといいます。サーバーレス構築をするためのオープンソースのフレームワークのようです。
Dockerをマシンにインストールしているのであれば、ローカルでの検証も可能になります。
SAMはCloudFormationの拡張機能です。そのため、デプロイするとCloudFormationを使用してリソースを定義できるほか、組み込み関数やテンプレート機能といったものを一式使えます。
詳細はこちらをお読みください。(公式 AWS SAMについて)
やること
- SAMを使ってテンプレートを作成してAPI GatewayとLambdaをデプロイする
- SAMを使ってローカル環境で検証する
つかってみる
AWS SAM CLIのインストール
下記公式の記事を参考にインストールして、セットアップします。
バージョンが表示されればOKです。
$ sam --version
> SAM CLI, version 1.70.0
SAMをデプロイする時のために、AWSのコンソールからアクセスキーを作成しておきます。
今回はユーザーにアタッチするポリシーは最強にしておきます。(練習のためです。本番ではこのような運用はおすすめしません)

SAMでテンプレートを作成
sam initコマンドを実行すると、簡単なサーバーレス環境を構築するテンプレートを構築してくれます。
sam init --runtime nodejs16.x
コマンドを打つと、色々質問されます。今回は以下のように質問に回答します。

以下のようなファイル構成が完成しました!

作成されたtemplate.yamlを確認していきます。
AWSTemplateFormatVersion: '2010-09-09'
Transform: AWS::Serverless-2016-10-31
Description: >
lambda_test
Sample SAM Template for lambda_test
# More info about Globals: https://github.com/awslabs/serverless-application-model/blob/master/docs/globals.rst
Globals:
Function:
Timeout: 3
MemorySize: 128
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: nodejs16.x
Architectures:
- x86_64
Tracing: Active
Environment:
Variables:
POWERTOOLS_SERVICE_NAME: helloWorld
POWERTOOLS_METRICS_NAMESPACE: lambda_test
LOG_LEVEL: INFO
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
Metadata: # Manage esbuild properties
BuildMethod: esbuild
BuildProperties:
Minify: true
Target: "es2020"
# Sourcemap: true # Enabling source maps will create the required NODE_OPTIONS environment variables on your lambda function during sam build
EntryPoints:
- app.ts
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
Transformというセクションは、SAMテンプレートの変換方法を指定するための指示です。この場合は、AWS::Serverless-2016-10-31を使用しています。
Globalsというセクションは、すべての関数リソースに適用される共通設定を指定するための指示です。この場合は、関数のタイムアウトとメモリサイズを指定しています。
Resourcesというセクションは、AWSリソースの定義を指定するための指示です。ここでは、HelloWorldFunction
という名前のAWS Lambda関数を定義しています。この関数は、Node.jsランタイムを使用し、hello-world/
ディレクトリにあるapp.lambdaHandler
をハンドラー関数として指定されています。また、API GatewayでHTTP GETリクエストを処理するためのHelloWorld
イベントも設定されています。
Metadataというセクションは、Lambda関数のビルド方法を指定するための指示です。この場合は、esbuild
というツールを使用する設定になっており、TypeScriptファイルをJavaScriptに変換して最適化するように設定されています。
Outputsというセクションは、スタックを作成する際に自動的に作成されるリソースの情報を出力するための指示です。ここでは、API GatewayのエンドポイントURLやLambda関数のARN、IAMロールのARNなどが指定されています。
ビルド
sam buildコマンドを実行して、依存関係を解決していきます。
sam build

buildの結果、.aws-samディレクトリが構築されました。
デプロイ
aws環境にデプロイしていきます。
–guildオプションをつけることで対話的にデプロイすることができます。
今回は以下のように質問に回答していきます。

デプロイに成功しました!

AWSマネジメントコンソールからもCloudFormationにスタックが構成されていることが確認できます。

aws-sam-cli-managed-defaultというスタックもできていますが、sam deployの過程で作成され、ソースを保存するS3バケットとバケットポリシーが生成されます。
curlでapiを叩いてみると、ちゃんとレスポンスが返ってきていることを確認できました!

ローカルで検証してみる
2種類の方法があります。
- Lambda関数を直接実行する
- ローカルHTTPサーバーを構築して実行する
Lambda関数を直接実行する
以下コマンドを打つことで実行することができます。
sam local invoke

無事想定通りのレスポンスが返ってきていることを確認できました!
また、以下のようにFUNCTION_IDENTIFIERをつけてLambda関数を指定して、実行することもできます!
sam local invoke HelloWorldFunction
ローカルHTTPサーバーを構築して実行する
以下のコマンドを実行すると、ローカルのHTTPサーバーを構築できます。アクセスされると、Dockerコンテナをローカルで起動して関数を呼び出します。
sam local start-api

curlで叩くと、ちゃんとレスポンスが返ってきます。

オプションをついけることによって、ローカルホスト名や、ポート番号を変えること、Lambda環境関数の設定ファイルの読み込みなどもできるようになります。
sam local start-api --host '192.168.11.5' -p 9000

このように想定通りのレスポンスが返ってきました。

参考
