【AWS】AWS SAM触ってみた(概念理解・デプロイまで)

こんにちは。 今回はIaCツール AWS SAM (Serverless Application Model) を使ってみます。

TerraformやAWS CLIなどの他のIaCツールを導入する方法もありますが、AWS SAMはサーバーレスサービスの開発に特化したフレームワークとなります。
個人利用や小規模開発であれば、常時稼働のサーバーを立てるよりも、サーバーレスの仕組みを活用する場面が多いため、AWS SAMを開発で使用する場面があるかと思います。
こちらの公式ハンズオンをもとに、AWS SAMでできること、開発手順を整理してみました。

AWS SAMでできること

IaC(Infrastructure as Code)での環境構築

AWS CLIでのリソースのテンプレート化とほぼほぼ同じことを、SAMテンプレートを使うことで可能です。
ロールやVPC設定もテンプレート側でマネージドしてくれるため、かなり便利です。

ローカルでの動作確認

Lambda関数やAPI Gatewayをローカルのコンテナ環境でシミュレーションできます。
デプロイ前ローカル上にて、サーバーレスリソースの挙動を無料で確認できるのが、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"}

おわりに

サーバーレスリソースに特化したAWS SAMを触ってみました。
本ブログでは、SAMインストールと、SAMを使用してAPI Gateway+Lambdaアプリのデプロイまで行いました。
次回は、SAMを使用してローカルコンテナを使用したデプロイ前テスト、トラブルシューティングや小技を書いていきます。

それでは。