本記事は
IaCウィーク
11日目の記事です。
⚙️
10日目
▶▶ 本記事 ▶▶ 💻

はじめに
こんにちは。入社2年目のインフラエンジニアの渡部です!
本記事は、初学者の方が中級者になるための架け橋として、
AWS SAM(※以下 SAM)とはそもそも何なのかという概要からSAMの基本的なコマンド、
そして本記事の最終目的であるSAMテンプレートの作成方法についてお話したいと思います。
※本記事ではテンプレートの書き方にフォーカスしており、デプロイ手順などの内容は含まれていません。
SAMの概要
SAMというのは、イベント駆動の性質を持つサーバーレスアプリケーションのデプロイに特化した、AWS CloudFormationの拡張機能です。
イベント駆動? AWS CloudFormation?

よくわかりませんね。順番に説明していきます。
イベント駆動とは、イベント(出来事)をきっかけに処理が開始される仕組みや設計思想のことをいいます。
たとえば、アプリでユーザーがボタンをクリックすると、クリックというイベントを受けて処理が実行されます。
AWSでは、午前8時になると、その時刻をイベントとして検知し、自動的に関数を起動する仕組みもあります。これもイベント駆動型の一例です。
AWS CloudFormationとは、テンプレートを使用して、AWSのリソースをプロビジョニングできるサービスです。
こちらに関しては、私の同期である中村さんが詳しく解説していますので、以下のブログをご覧ください。
中村さんのブログでは、CloudFormationは、AWSのリソース構成をYAMLやJSON形式で記述することによって、テンプレートの定義を行い、それをもとにAWSが自動的にリソースを構築してくれる仕組みであると説明されています。
AWS SAMとCloudFormationの違い
中村さんのブログを見ていただくと、「CloudFormationもSAMもテンプレートで書くのならば、違いは何なのか。」という感想を抱く方もいらっしゃると思います。
ここで、CloudFormationとSAMの違いを整理します。
大きな違いは、CloudFormationはAWS全体のリソースをコードで管理するためのサービスですが、SAMはサーバーレスアプリケーション開発を簡単にするためのフレームワークだということです。
コードで比較してみましょう。 例として、Lambda関数 + API Gateway + S3バケットを含む構成を書いたときのCloudFormationのテンプレートがこちらです。
Resources:
MyBucket:
Type: AWS::S3::Bucket
Properties:
BucketName: my-app-bucket
MyLambdaFunction:
Type: AWS::Lambda::Function
Properties:
FunctionName: MyFunction
Handler: index.handler
Runtime: nodejs18.x
Code:
S3Bucket: my-code-bucket
S3Key: lambda-code.zip
Role: arn:aws:iam::xxxxxxxxxxxx:role/lambda-role
MyApi:
Type: AWS::ApiGateway::RestApi
Properties:
Name: MyApi
MyApiResource:
Type: AWS::ApiGateway::Resource
Properties:
ParentId: !GetAtt MyApi.RootResourceId
PathPart: hello
RestApiId: !Ref MyApi
MyApiMethod:
Type: AWS::ApiGateway::Method
Properties:
HttpMethod: GET
ResourceId: !Ref MyApiResource
RestApiId: !Ref MyApi
AuthorizationType: NONE
Integration:
IntegrationHttpMethod: POST
Type: AWS_PROXY
Uri: !Sub >-
そして、SAMテンプレートのコードがこちらになります。
Transform: AWS::Serverless-2016-10-31
Resources:
MyBucket:
Type: AWS::S3::Bucket
Properties:
BucketName: my-app-bucket
MyFunction:
Type: AWS::Serverless::Function
Properties:
Handler: index.handler
Runtime: nodejs18.x
CodeUri: ./src/
Role: arn:aws:iam::xxxxxxxxxxxx:role/lambda-role
Events:
HelloApi:
Type: Api
Properties:
Path: /hello
Method: get
同じ構成を書いたにも関わらず、CloudFormationは約40行、SAMは約20行となり、SAMであれば半分の行数で簡潔に書くことができます。
また、CloudFormationではローカルでテストすることはできませんが、SAMではSAM CLIと呼ばれるコマンドラインツールを使用することで可能になります。
他にも異なる点がありますので、表でまとめてみたいと思います。
| 項目 | CloudFormation | AWS SAM |
|---|---|---|
| 対象範囲 | AWS全リソース | サーバーレス関連リソースに特化 |
| 構文 | 標準CloudFormation構文(JSON/YAML) | SAM専用の簡略構文(YAML) |
| ローカルテスト | × | ○(SAM CLIで可能) |
| デプロイ補助 | 基本なし(AWS CLIやコンソールを利用) | 簡単(sam deployで簡単に自動化) |
SAMの概要の説明が終わったところで、AWSリソースをSAMで構築することによる開発者にとってのメリットを説明します。
開発者にとってのメリット
Lambda、API Gateway、DynamoDB、S3など、サーバーレスサービスを簡潔に定義できる。
CodePipelineやCodeBuildなどのCI/CDサービスとスムーズに連携できるため、継続的なデプロイ環境の構築が容易である。
例えば、下記のような構成だと、GitHubへのpushをトリガーに、ビルドからデプロイまで自動で実行することができ、さらにCodeBuild が SAM CLI に対応しているため、追加で複雑な設定をする必要はなくSAMのコマンドを実行することができます。
こちらのメリットにより、最終的に、開発サイクルが短縮され、新機能やサービスのリリースが迅速に行えるようになります。
コマンドの概要
ここでは、SAMテンプレートの作成に必要なコマンドについてお話をしていきたいと思います。
コマンド1:sam init
SAMテンプレートと必要なディレクトリを自動生成するコマンドです。
コマンドをうつと、以下のメッセージが表示されます。
Which template source would you like to use? 1 - AWS Quick Start Templates 2 - Custom Template Location
sam initコマンド実行後、AWSが公式に提供するテンプレートを利用するか、自分でテンプレートを指定するのかについての質問です。
Which runtime would you like to use? 1 - python3.13 2 - python3.12 3 - python3.11 4 - python3.10 5 - python3.9 6 - python3.8 7 - nodejs22.x 8 - nodejs20.x 9 - nodejs18.x 10 - nodejs16.x 11 - java21 12 - java17 13 - java11 14 - dotnet8 15 - dotnet6 16 - ruby3.4 17 - ruby3.3 18 - ruby3.2
こちらは、Lambda関数のランタイムを何に設定するかについての質問です。
Which package type would you like to use? 1 - Zip 2 - Image
ソースコードと依存関係をZIPファイルにまとめてアップロードするのか、コンテナイメージとしてデプロイするのか、Lambda関数のデプロイ方式を選択する質問です。
Project name [sam-app]:
プロジェクト名に関する質問です。このままEnterを押すと、デフォルトで設定されている「sam-app」になります。
この質問に回答すると、AWS SAM プロジェクトが作成されます。
このAWS SAMプロジェクトの中心となる設定ファイルがtemplate.ymlという名前のSAMテンプレートとなります。
コマンド2:sam validate
SAMテンプレートの構文や基本的な設定が正しいかを検証するためのコマンドです。
私が初めてSAMテンプレートを作成したときは、YAMLファイルの細かい文法エラーをすることが多く、
コマンド実行時には、エラーメッセージが表示されることが何回もあり、大変貴重な経験をさせていただきました。(笑)
template.ymlに問題なければ下記のメッセージが表示されます。
Template provided at template.yaml is valid SAM Template
コマンド3:sam build
SAMテンプレートに基づいてLambda関数やLayerのコードを依存関係込みでビルドし、デプロイ可能な形に整えるコマンドです。
デフォルトでカレントディレクトリにあるtemplate.yml を読み込み、別の場所にテンプレートがある場合は、--template オプションでパスを指定する必要があります。
template.yml ファイルが存在するディレクトリで実行すると、オプションなしでコマンドを実行することができるので、便利です。
コマンド4:sam deploy --guided
サーバーレスアプリケーションを 対話形式でデプロイするコマンドです。
初回デプロイするときは「--guided」オプションをつけます。
コマンドを実行すると下記について質問されます。
1.デプロイするCloudFormationのスタック名をどのようにするのか
Stack Name [sam-app]:
2.デプロイ先のリージョン(東京リージョンにデプロイしたい場合はap-northeast-1)
AWS Region [us-east-1]:
3.デプロイ前に変更内容を確認するかどうか。
Confirm changes before deploy [Y/n]:
4.Lambdaなどに必要なIAMロールをSAM CLIに作成させるかどうか。
Allow SAM CLI IAM role creation [Y/n]:
5.入力した設定をsamconfig.tomlに保存するかどうか。
Save arguments to samconfig.toml [Y/n]:
5つ目の質問に対して、「Y」を入力した結果、samconfig.tomlというファイルが生成されるようになります。
2回目以降はsam deploy コマンドを実行するだけで、samconfig.toml の設定が自動的に使用されるので、--guidedオプションを使用する必要はありません。
SAMテンプレートの説明
では、SAMの基本的コマンドについて説明したところで、下記3つのリソースをSAMテンプレートで作成したいと思います。
S3バケットに格納されているファイルの中身を出力するLambda関数
簡単な足し算を行うLambda関数
S3バケット
※Lambda 関数はコンテナイメージとしてデプロイします
下記がtemplate.ymlになります。
AWSTemplateFormatVersion: '2010-09-09'
Transform: 'AWS::Serverless-2016-10-31'
Resources:
MyLambdaFunction:
Type: AWS::Serverless::Function
Properties:
FunctionName: !Sub "${AWS::StackName}_printlambda"
Policies:
- S3ReadPolicy:
BucketName: !Ref MyS3Bucket
PackageType: Image
Metadata:
Dockerfile: Dockerfile
DockerContext: ./printlambda
MyS3Bucket:
Type: AWS::S3::Bucket
Properties:
BucketName: !Sub "s3-watanabe-${AWS::AccountId}-${AWS::Region}"
VersioningConfiguration:
Status: Enabled
- ec2-user/printlambda/app.py
import json
import boto3
BUCKET_NAME = 's3-watanabe'
OBJECT_KEY_NAME = 'hello.json'
s3 = boto3.resource('s3')
def lambda_handler(event, context):
bucket = s3.Bucket(BUCKET_NAME)
obj = bucket.Object(OBJECT_KEY_NAME)
response = obj.get()
body = response['Body'].read()
return json.loads(body.decode('utf-8'))
また、ディレクトリ構成は以下のようになります。
この場合、ec2-user/template.ymlに上記のSAMテンプレートを記載することになります。
ec2-user | | ---------printlambda | | | | ------Dockerfile | | ------requirements.txt | | ------app.py | | |---------------template.yml |---------------docker-compose.yml
SAMテンプレートの補足説明1.「!Sub」
Properties:
FunctionName: !Sub "${AWS::StackName}_printlambda"
の!Subとは何をしているかについて説明いたします。
!Subというのは、入力文字列の変数を、指定した値に置き換えるFn::Sub関数でYAMLファイルを記述するときの短縮形となります。
例えば、スタック名を「s3-watanabe」に設定すると、Lambda関数の名前は「s3-watanabe_printlambda」になります。
SAMテンプレートの補足説明2.「Policies」
Policies:
- S3ReadPolicy:
今回作成したLambda関数はS3バケットの中のファイルを読み取るため、s3の読み取り権限をこの箇所で付与しています。
S3ReadPolicy以外にも様々なポリシーがありますので、詳しくは、こちらの公式ドキュメントをご覧ください。
こちらのページでは、SAMで利用可能なポリシーテンプレートの一覧や使い方、記述例が詳しく紹介されています。
実際に私もSAMでIAMポリシーについてどう書いたらよいかわからなくなったときは、参考にしています。
SAMテンプレートの補足説明3.「PackageType」
PackageType: Image
の箇所は、サーバーレスアプリケーションをコンテナイメージとして構築するために宣言しています。
この場合、コードと依存関係を含むDockerイメージを自分で定義するため、
Metadata:
Dockerfile: Dockerfile
DockerContext: ./printlambda
のようにDockerfileの定義が必要になります。
AWS SAMで PackageType: Image を使うとき、SAM CLIは Dockerfile を使ってイメージをビルドします。
つまり、Dockerfileがないと、SAMは何をどうビルドすればいいか分からないということになります。
逆に、以下のようにPackageTypeがZip の場合は、SAMが自動でビルドしてくれるため、Dockerfileは不要です。
PackageType: Zip
SAMテンプレートの作成方法のコツ
私が尊敬している先輩から教えてもらったSAMテンプレートを効率的に作成するためのコツを紹介します。
私が作成したtemplate.ymlのように基本的なリソースについてテンプレートが記載されているものをWebで検索して雛形を作成する。
たとえばEventBridgeについてSAMで記載したい場合、「AWS SAM EventBridge」などで調べると、検索結果にtemplate.ymlを記載したブログや記事が表示されやすいです。Lambda関数に追加したい設定があればAWSの公式ドキュメントをもとに書いてみる。
最後に
AWS SAMはサーバーレス開発を効率化する強力なツールですが、IaCの世界にはTerraformやCloudFormationなど、さまざまな選択肢があります。
重要なのは、プロジェクトの要件やチームのスキルセットに最適なツールを選ぶことです。
SAMがすべてのケースに万能というわけではありません。ぜひ、複数の選択肢を比較しながら、最適なアーキテクチャを設計してください。
最後までお読みいただきありがとうございました。