AWS SAM
AWS のサーバーレスアプリケーションを定義 / デプロイするためのフレームワーク
SAM とは
AWS SAM (Serverless Application Model) は、Lambda、API Gateway、DynamoDB などのサーバーレスリソースを簡潔な YAML で定義し、デプロイするフレームワークである。CloudFormation の拡張で、サーバーレスに特化した省略記法を提供する。
拡張の仕掛けはテンプレート先頭の Transform: AWS::Serverless-2016-10-31 宣言にある。この 1 行があるファイルは SAM テンプレートとして扱われ、デプロイ時に変換が走って省略記法が素の CloudFormation リソースへ展開される。SAM テンプレートで必須なのはこの Transform と Resources の 2 セクションだけで、残りの書き方は CloudFormation と同じである。Resources には SAM のリソースと素の CloudFormation リソースを混ぜて並べられる。AWS::LanguageExtensions など別の変換を併用するときは、サーバーレスの変換より前に書く。
もう 1 つ SAM 固有なのが Globals セクションで、関数や API に共通するプロパティ (ランタイム、タイムアウト、環境変数など) をここへ一度書けば各リソースへ引き継がれる。同じ値を関数ごとに繰り返さずに済む。なお SAM という名前は 2 つのものを指す。テンプレートの記法そのものと、手元で使う SAM CLI (sam コマンド) は別物で、変換を行うのは CloudFormation 側なので記法だけを使って CloudFormation へ直接テンプレートを渡すこともできる。
CloudFormation との比較
同じ関数を素の CloudFormation で書くと、関数本体のほかに実行ロール、API Gateway の REST API とその配下のリソース、DynamoDB を触るための IAM ポリシーをそれぞれ宣言することになる。SAM では次のように 1 つのリソースへ畳める。
# Transform: AWS::Serverless-2016-10-31 を宣言したテンプレートの Resources 配下
MyFunction:
Type: AWS::Serverless::Function
Properties:
Handler: index.handler
Runtime: nodejs22.x
Events:
Api:
Type: Api
Properties:
Path: /users/{id}
Method: GET
Policies:
- DynamoDBCrudPolicy:
TableName: !Ref UsersTable
AWS::Serverless::Function からは必ず AWS::Lambda::Function が作られる。実行ロール AWS::IAM::Role が一緒に作られるのは Role プロパティを書かなかった場合で、既存のロールを指定したときは生成されない。上の例のように Api イベントを書いて RestApiId を省略すると、テンプレートに現れない AWS::ApiGateway::RestApi が論理 ID ServerlessRestApi で作られる。Events に DynamoDB や Kinesis、SQS を指定した場合は AWS::Lambda::EventSourceMapping、Schedule や EventBridgeRule なら AWS::Events::Rule が同じように生成される。この暗黙のリソースを他の箇所から参照するときは、生成される論理 ID を書くしかない点に注意する。
SAM リソースタイプ
よく使うタイプは次のとおりで、いずれも展開後は複数の CloudFormation リソースになる。
| タイプ | 説明 |
|---|---|
AWS::Serverless::Function | Lambda 関数 |
AWS::Serverless::Api | API Gateway (REST) |
AWS::Serverless::HttpApi | API Gateway (HTTP API) |
AWS::Serverless::SimpleTable | DynamoDB テーブル |
AWS::Serverless::LayerVersion | Lambda Layer |
AWS::Serverless::StateMachine | Step Functions のステートマシン |
これで全部ではなく、GraphQL API やリソース間の接続を扱うタイプも用意されている。省略記法が無いリソースは、同じテンプレートに素の CloudFormation の記法で並べて書けばよい。
コマンド
流れは、雛形を作り (init)、依存関係を解決して成果物を組み立て (build)、CloudFormation のスタックとして適用する (deploy) という順になる。
sam init # プロジェクトの初期化
sam build # ビルド
sam local invoke # ローカルで Lambda を実行
sam local start-api # ローカルで API Gateway を起動
sam deploy # デプロイ
sam logs -t # ログのテール
sam delete # スタックの削除
sam build は、ソースと依存関係をローカル実行やデプロイへそのまま渡せる形に組み立てる工程である。--use-container を付けると Lambda の実行環境に合わせたコンテナイメージの中でビルドするので、ネイティブ拡張を含む依存関係を手元の OS 向けに固めてしまう事故を避けられる。sam deploy は CloudFormation 経由で適用するため、初回は --guided でスタック名やリージョン、変更確認の有無を対話で決めて設定ファイルに残しておくと以降が楽になる。テンプレートが IAM リソースを含む場合は --capabilities CAPABILITY_IAM (名前を明示したロールを作るなら CAPABILITY_NAMED_IAM) が要る。付け忘れると権限不足を示すエラーで止まる。入れ子のアプリケーションを含むなら CAPABILITY_AUTO_EXPAND も足す。
ローカル開発
イベントの JSON を用意して関数を単発で叩くか、HTTP の入口ごと立ち上げて手元のブラウザから触るかの 2 通りがある。
# Lambda をローカルで実行
sam local invoke MyFunction --event event.json
# API Gateway をローカルで起動
sam local start-api
# → http://localhost:3000 でテスト
sam local の各コマンドは、Lambda の実行環境に似せた Docker コンテナの中でコードを動かす。手元で Docker が動いていることが前提で、初回はイメージの取得に時間がかかる。使うのは手元の認証情報なので、実行ロールに権限が足りていない類の不具合はローカルでは表面化せず、デプロイして初めて出る。信用できないコードをこの仕組みで動かすのも避ける。
ポリシーテンプレート
IAM のアクションを 1 つずつ書く代わりに、用途の名前でよく使う権限のまとまりを指定できる。
Policies:
- DynamoDBCrudPolicy:
TableName: !Ref UsersTable
- S3ReadPolicy:
BucketName: !Ref DataBucket
- SQSSendMessagePolicy:
QueueName: !GetAtt OrderQueue.QueueName
テンプレートは、権限の範囲をアプリケーションが使うリソースへ絞り込むための既製品である。記述量は確かに減るが、選んだテンプレートに含まれる操作の一式がそのまま付く点は意識しておきたい。上の DynamoDBCrudPolicy は読み取りと書き込みの両方を許すので、参照しかしないなら DynamoDBReadPolicy のように用途の狭いものを選ぶ。どのテンプレートも対象を指す値を渡す決まりで、渡す値が無いテンプレートでも空のオブジェクト {} を明示しないとエラーになる。まとまりで足りない権限は、素の IAM ポリシーを同じ Policies に並べて補える。
Terraform との使い分け
構成のうちサーバーレスが占める割合と、AWS の外まで同じ道具で書きたいかで分かれる。
| 構成 | 選ぶ道具 | 理由 |
|---|---|---|
| Lambda と API Gateway が中心 | SAM | AWS::Serverless::Function の省略記法が効く範囲そのもので、sam local invoke で手元から実行して確かめられる |
| VPC や RDS、ECS が主役 | Terraform | SAM の省略記法はサーバーレス向けのリソースに用意されたもので、これらを書くうえでの短縮にはならない |
| サーバーレスに一部の EC2 などが混ざる | SAM と CloudFormation を併用 | SAM は CloudFormation の拡張なので、省略記法が無いリソースは同じテンプレートに素の記法で並べて書ける |
| AWS 以外の環境も同じ書き方で管理したい | Terraform | SAM は CloudFormation へ展開される前提の記法で、AWS の外のリソースを対象にできない |
SAM で書いたテンプレートの実体は CloudFormation のスタックである。想定と違う挙動に出会ったら、展開後のテンプレート (sam build が出力するものや、CloudFormation の処理済みテンプレートの表示) を見て、省略記法が何に化けたかを確かめるのが早い。
この記事は役に立ちましたか?
関連用語
Terraform
HashiCorp の IaC ツールで、マルチクラウドのインフラをコードで宣言的に管理する
Lambda Layer
Lambda 関数間で共有ライブラリやカスタムランタイムを再利用する仕組み
CloudFormation
AWS のインフラをテンプレート (YAML/JSON) で宣言的に定義および管理する IaC サービス
Infrastructure as Code
インフラの構成をコードで定義し、バージョン管理 / 自動化 / 再現性を実現する手法
Helm
Kubernetes のパッケージマネージャーで、アプリケーションのデプロイをテンプレート化して管理する
CDK
TypeScript や Python などのプログラミング言語で AWS インフラを定義する IaC フレームワーク