【AWS】AWS SAM触ってみた
目次
こんにちは。 今回はIaCツール AWS SAM (Serverless Application Model) を使ってみます。
TerraformやAWS CLIなどの他のIaCツールを導入する方法もありますが、AWS SAMはサーバーレスサービスの開発に特化したフレームワークとなります。
個人利用や小規模開発であれば、常時稼働のサーバーを立てるよりも、サーバーレスの仕組みを活用する場面が多いため、AWS SAMを開発で使用する場面があるかと思います。
こちらの公式ハンズオンを参考に、AWS SAMを触ってみました。
また、実践する中で詰まった部分や小技を共有していきます。
AWS SAMでできること
AWSサービスの中でAWS SAMは次の2点の機能が特徴となります。
IaC(Infrastructure as Code)での環境構築
AWS CLIでのリソースのテンプレート化とほぼほぼ同じことを、SAMテンプレートを使うことで可能です。
ロールやVPC設定もテンプレート側でマネージドしてくれるため、かなり便利です。
ローカルでの動作確認
Lambda関数やAPI Gatewayをローカルのコンテナ環境でシミュレーションできます。
デプロイ前ローカル上にて、サーバーレスリソースの挙動を無料で確認できるのが、SAMの強みとなります。
AWS SAMの導入
AWS SAMをターミナル環境で導入していきます。
AWS CLIをインストールし設定
AWS SAMはAWS CLIの拡張である故、まずAWS CLIの設定を行う必要があります。
AWS CLIのインストールおよび、CLI内の設定でAWS側との疎通を取るためのキーの設定を行います。
インストーラーをダウンロードし、AWS CLIをインストールします。
$ curl "https://awscli.amazonaws.com/awscli-exe-linux-x86_64.zip" -o "awscliv2.zip"
$ unzip awscliv2.zip
$ sudo ./aws/install
下記コマンドでバージョンが表示されれば、AWS CLIのインストールが完了できています。
$ aws --version
> aws-cli/2.xxx Python/3.xxx Linux/5.xxx-WSL2 exe/x86_64.ubuntu.20
AWS CLIのCONFファイルに下記の設定を行います。
# ・awsユーザのアクセスキー/シークレット
# ・リソースを作成するリージョンの設定
# ・CLIの結果表示の形式の指定(基本的にJSONでOK)
$ aws configure
> ※すでに設定済みの場合の2回目以降は下記のように設定値が表示される。
AWS Access Key ID [********************]:
AWS Secret Access Key [********************]:
Default region name [ap-northeast-1]:
Default output format [json]:
AWS SAMのインストール
まず、AWS SAMのインストーラーをダウンロードします。
筆者はWSL2環境を使用しており、linux用インストーラーをダウンロードしました。
なお、その他の環境の場合は、こちらから対象環境のものをインストールください。
また、筆者環境では、curlでインストールしたインストーラーが挙動不審(ファイルが空)となっていたため、手動DLするのがいいかと思います。
次に解凍し、インストーラーを実行します。
$ unzip aws-sam-cli-linux-x86_64.zip
$ sudo ./install
バージョンが表示されれば、AWS SAMをインストールできています。
$ sam --version
> SAM CLI, version 1.xxx
AWS SAMでAPI Gateway+Lambdaをデプロイ
SAMプロジェクトを作成し、ビルドすることで、ビルド済みテンプレートファイルを作成します。
そのテンプレートファイルを元に、AWSへのリソースのデプロイを実施します。
SAMプロジェクトの作成
まず、SAMプロジェクトを作成します。
$ sam init
# テンプレートからの作成か、カスタム作成を選択できます。
# 今回は、Quick Start から Hello World を選択
> Which template source would you like to use?
1 - AWS Quick Start Templates
2 - Custom Template Location
1
> Choose an AWS Quick Start application template
1 - Hello World Example
2 - Data processing...
1
# Lambdaのランタイムのバージョン選択
> Use the most popular runtime and package type? (python3.13 and zip) [y/N]: y
# XRayを使用してリソース横断した監視を入れるか
> Enable X-Ray tracing? [y/N]: y
# Cloudwatch監視を入れるか
> Enable CloudWatch Application Insights? [y/N]: y
# リソースのログを残すか
> Enable Structured Logging in JSON format? [y/N]: y
#下記のようにテンプレートとして定義されたリソース情報が表示されればOK
-----------------------
Generating application:
-----------------------
Name: sam-app
Runtime: python3.13
Application Template: hello-world
...
SAMプロジェクトをざっくり解読
ちなみに、SAMプロジェクトのファイル構造としては下記のようになります。
sam-app
├── README.md
├── __init__.py # SAMプロジェクト用のinitファイル
├── events
│ └── event.json # Lambda をローカル実行する際のサンプルイベント
├── hello_world
│ ├── __init__.py
│ ├── app.py # Lambda 関数のメインコード(エントリポイント)
│ └── requirements.txt # Lambda 関数用の依存ライブラリ
├── samconfig.toml # SAM CLI の設定ファイル(デプロイ時のパラメータ保持)
├── template.yaml # SAM テンプレート(IaC定義の中核)
└── tests # リソース内コードをビルド前テスト用するためのスクリプト
├── __init__.py
├── integration
│ └── test_api_gateway.py # API Gateway を含む統合テスト
├── requirements.txt # テスト用ライブラリ
└── unit
└── test_handler.py # Lambda 関数のユニットテスト
Lambdaの中身「helloWorld/app.py」は下記の通りです。
「Hello world」応答を返すようです。
import json
# hello worldというメッセージを返す。
def lambda_handler(event, context):
return {
"statusCode": 200,
"body": json.dumps({
"message": "hello world",
}),
}
では、この「Hello world」応答が、API Gatewayへのどんなリスエストで呼び出されるかを確認するには、「template.yaml」を確認します。
<urlパス>/helloにGETメソッドでリクエストしたときに、「Hello world」応答が返ってくるようです。
# 特定リソース周りの設定を確認するには、Resource項目を確認する
Resources:
HelloWorldFunction:
Type: AWS::Serverless::Function # Lambdaを意味する
Properties:
CodeUri: hello_world/ # hello_worldについての設定だとわかる。
Handler: app.lambda_handler
Runtime: python3.13
# API Gatewayというイベントが来た時に発動する。
Events:
HelloWorld:
Type: Api
# 具体的には、helloパスにGETメソッドでリクエストしたとき。
Properties:
Path: /hello
Method: get
SAMプロジェクトのデプロイ
次にSAMプロジェクトをビルドします。
# SAMプロジェクト(sam-app)内で実行
$ sam build
Building codeuri: hello_world
runtime: python3.13 architecture: x86_64 functions: HelloWorldFunction
# ビルド成功
Build Succeeded
# ビルド済みテンプレート先
Built Artifacts : .aws-sam/build
Built Template : .aws-sam/build/template.yaml
buildフォルダにビルド済みテンプレートが作成されます。
デプロイやローカルコンテナ環境でのテストでは、buildフォルダのテンプレートをもとにリソースを作成されます。
AWSへデプロイ
テンプレートがビルドされたため、デプロイ作業が出来ます。
なお、デプロイ時のAWSとの疎通には、AWS CLIのCONFファイルを参照しています。
# SAMプロジェクト(sam-app)内で実行
$ sam deploy --guided
# デプロイ時の諸々設定(基本的にデフォルト設定で良いため、yもしくは空白を選択)
Configuring SAM deploy
======================
Stack Name [sam-app]: # デプロイ先のCloudFormationスタック名
AWS Region [ap-northeast-1]: # デプロイするリージョン
Confirm changes before deploy [Y/n]: y # デプロイ前に差分確認するか
Allow SAM CLI IAM role creation [Y/n]: y # 必要なIAMロールをSAMに作成させるか
Disable rollback [y/N]: y # エラー時に自動ロールバックを無効化するか
HelloWorldFunction has no authentication. Is this okay? [y/N]: y
Save arguments to configuration file [Y/n]: y # 設定を samconfig.toml に保存
デプロイが完了すると、API GatewayやLambdaのエンドポイントを案内してくれます。
>
CloudFormation outputs
======================
Key HelloWorldApi
Description API Gateway endpoint URL
Value https://****.execute-api.ap-northeast-1.amazonaws.com/Prod/hello/
Key HelloWorldFunction
Description Hello World Lambda Function ARN
Value arn:aws:lambda:ap-northeast-1:****:function:sam-app-HelloWorldFunction-****
デプロイしたAPIを叩いてみる
/helloパスにGETリクエストすると、「hello world」が返っており、想定通りの結果が得られました。
curl https://****.execute-api.ap-northeast-1.amazonaws.com/Prod/hello/
>{"message": "hello world"}
ローカルコンテナでLambda・API Gatewayをテストする
sam local コマンドを使うと、ローカルPC上のDockerコンテナでLambdaやAPI Gatewayを疑似的に再現してテストできます。
これにより、実際にクラウドへデプロイする前に動作確認ができ、修正やデバッグを効率的に行うことが可能になります。
Lambdaをローカルで実行
ローカル上でLambdaのテストを行えます。sam local invokeにて、Lambdaを仮に実行した場合の結果が確認できます。
# ローカルPCにて、Lambda上の関数を実行して結果確認
$ sam local invoke
Invoking app.lambda_handler (python3.9)
Local image was not found.
Building image...
Using local image: public.ecr.aws/lambda/pythonxxx
# 結果
{"statusCode": 200, "body": "{\"message\": \"hello world\"}"}
APIをローカルで実行
ローカル上でAPI Gatewayのテストを行えます。sam local start-apiにて、API Gatewayを仮に構築した場合のエンドポイントURLをコンテナで構築します。
ローカルホスト127.0.0.1を叩くと、API Gatewayに相当する応答が返ってきます。
$ sam local start-api
# ローカルホスト上にAPI Gatewayのエンドポイントを構築
Mounting HelloWorldFunction at http://127.0.0.1:3000/hello [GET]
You can now browse to the above endpoints to invoke your functions.
#ブラウザやcurlで `http://127.0.0.1:3000/hello` にアクセスすると、Lambdaの応答が確認可能
【トラブルシューティング】コンテナが立ち上がらない場合
コンテナが立ち上がらない場合は、Docker Desktopをインストールして、稼働しているかを確認ください。
もしWSL2のUbuntuを使用している場合は、設定の見直しが必要な場合があります。
こちらのブログも参照ください。
【小技】SAMでクラウド上のLambda呼び出し
クラウド上で作成済みのLambdaを直接テストできます。
API Gatewayであれば、HTTPSリクエストで叩けますが、Lambdaでは一癖あります。sam remote invokeを使用して、クラウド上のLambdaを直接叩き応答を確認できます。デプロイ後の確認に有用です。
# sam-appというプロジェクトの中のHelloWorldFunctionを呼び出し
$ sam remote invoke HelloWorldFunction --stack-name sam-app
{"statusCode": 200, "body": "{\"message\": \"hello world\"}"}
【小技】ローカルファイル変更時のクラウド上リソースの自動同期
sam sync コマンドを使うと、ローカルコードの変更を即座にクラウドに反映できます。
ローカル上のプロジェクト内のファイルを変更し保存すると、即座に下記のようにクラウド上のリソースの上書きが起こります。
# 一旦sam syncを実行
$ sam sync --watch
# ローカルファイルを変更すると、リソースも変更される
Syncing Lambda Function HelloWorldFunction...
Finished syncing Lambda Function HelloWorldFunction.
--no-watch の場合、sam sync実行時に更新されます。
ある程度ローカルファイルを更新したうえで、まとめて上書きする際に良さそうです。
# sam syncを実行したときに、リソースが変更される
$ sam sync --no-watch
Syncing Lambda Function HelloWorldFunction...
Finished syncing Lambda Function HelloWorldFunction.
ちなみに、sam sync --watch/no-watchでは、クラウド上のリソースすべてに上書き(削除→再作成)がかかっていました。
更新されるべきものだけ上書きされるようなコマンドを捜索中ですが、一旦は、sam sync --no watchにて、手動でまとめてリソース作成したほうが、コスト的にも良さそうです。
【小技】作成したリソースの確認
sam deployで作成したリソースは sam list endpoints で確認できます。
API GatewayのURLとメソッドは、CloudEndpointおよびMethods項目で確認できます。
$ sam list endpoints --output json
# lambdaとapi gatewayのリソースが表示される。
# lambdaはインターネットへの入出口がないので、CloudEndpointおよびMethods項目が「-」となる
[
{
"LogicalResourceId": "HelloWorldFunction",
"CloudEndpoint": "-",
"Methods": "-"
},
{
"LogicalResourceId": "ServerlessRestApi",
"CloudEndpoint": ["https://*****.execute-api.ap-northeast-1.amazonaws.com/Prod"],
"Methods": ["/hello['get']"]
}
]
【小技】クラウド上のリソース削除
SAMプロジェクトで作成したリソースをsam deleteで一斉削除できます。
$ sam delete
Are you sure you want to delete the stack sam-app in the region ap-northeast-1 ? [y/N]: y
Deleted successfully
コマンドまとめ
| コマンド | 用途 |
|---|---|
| sam init | SAMプロジェクト作成 |
| sam build | SAMプロジェクトのビルド |
| sam deploy | デプロイしてクラウド上にリソース作成 |
| sam list endpoints | 作成したリソースの確認 |
| sam local invoke | ローカルでLambda関数を疑似的に実行 |
| sam local start-api | ローカルでAPIを疑似的に呼び出し |
| sam sync | ローカルファイルの更新をリソースに反映 |
| sam delete | 作成したリソースを削除 |
おわりに
サーバーレスリソースに特化したAWS SAMを触ってみました。
特に sam local コマンドを使ったローカルテストは、コスト削減や開発効率化に大きく貢献します。
前回のブログと合わせて、SAMを使った効率的な開発フローの参考になれば幸いです。
それでは。