AWS SAM によるサーバーレスアプリケーション開発

AWS SAM の役割と CloudFormation との関係、テンプレートの主要セクション、AWS SAM CLI を使った初期化・ビルド・ローカルテスト・デプロイ・同期・リモート呼び出しの流れを解説します。

学習順Step 47 / 101サービス自動化 / IaC試験ドメインデプロイメント

サーバーレスを理解する

クラウドサービスの提供範囲を整理する分類として、SaaS、PaaS、IaaSがあります。SaaS(Software as a Service)は利用者がインターネット経由でアプリケーションを使う形態、PaaS(Platform as a Service)はアプリケーションを実行するためのプラットフォームを利用する形態、IaaS(Infrastructure as a Service)は仮想サーバーやネットワークなどの基盤を利用する形態です。一般に、IaaSからPaaS、SaaSへと抽象度が高まるほど、利用者が直接管理する範囲は小さくなります。

サーバーレスも、利用者がサーバーを直接管理しないという点で高い抽象化を提供します。ただし、SaaS・PaaS・IaaSがサービスの提供レイヤーを表す分類であるのに対し、サーバーレスはコンピューティングや運用のモデルを表す言葉です。サーバーレスであっても、裏側でサーバーが存在しないという意味ではありません。サーバー、OS、容量調整、可用性の維持などの管理をクラウド事業者に委ね、利用者はコード、データ、権限、設定など自らの責任範囲に集中します。

たとえば、ある地域配送サービスが荷物の状態更新を受け付け、更新内容を保存し、条件に応じて通知を送る機能を考えます。利用者が仮想マシンを常時稼働させて処理を待ち受ける代わりに、API、関数実行、データベース、メッセージングなどのマネージドサービスを組み合わせれば、イベントが発生したときに必要な処理を実行する構成にできます。需要の増減に応じた実行環境の調整や基盤の保守をAWSに委ねられるため、開発者はアプリケーションの動作や業務ルールに注力できます。

サーバーレスは運用作業をなくすのではなく、運用の対象を変えます。OSのパッチ適用や物理ホストの管理が不要になる一方で、IAM権限、タイムアウト、同時実行、データ保護、監視、コスト、障害時の再試行といったアプリケーション側の設計は引き続き必要です。

AWS SAMの役割

AWS SAM(AWS Serverless Application Model)は、サーバーレスアプリケーションをInfrastructure as Code(IaC)として定義し、開発・テスト・デプロイするためのオープンソースのフレームワークです。SAMには、主に二つの要素があります。

  • AWS SAMテンプレート:CloudFormationテンプレートを拡張し、サーバーレスリソースを短い構文で記述するための仕様です。
  • AWS SAM CLI:テンプレートとアプリケーションコードを扱い、初期化、ビルド、ローカルテスト、デプロイ、クラウド上のリソースとの同期やテストを行うコマンドラインツールです。

SAMはCloudFormationの代替として独立したプロビジョニング機構を持つのではなく、CloudFormationの機能をサーバーレス開発向けに拡張します。SAMテンプレートには、SAM固有のリソースだけでなく通常のCloudFormationリソースも同じResourcesセクションに記述できます。デプロイ時にはSAMの変換処理によってSAMリソースがCloudFormationリソースに展開され、最終的なスタックの作成・更新はCloudFormationが担います。そのため、CloudFormationのパラメーター、出力、依存関係、スタック管理などの仕組みも引き続き利用できます。

サーバーレスの実行基盤の細部をSAMのリソース型やイベント定義に任せることで、同じ構成を通常のCloudFormationリソースだけで表す場合よりも、テンプレートを簡潔に記述しやすくなります。簡潔な定義が何行になるかは、実装する機能や権限、運用要件によって変わるため、常に一定の記述量になるわけではありません。

SAMテンプレートの構成

SAMテンプレートはYAMLまたはJSONで記述し、CloudFormationテンプレートにSAM固有の変換宣言と機能を加えます。次の例では、配送状況の記録を受け付けるAPI、Lambda関数、DynamoDBテーブルを表しています。テンプレートの具体的な設定値はアプリケーション要件に応じて調整します。

Transform: AWS::Serverless-2016-10-31
Description: 配送状況を受け付けるサーバーレスAPI

Globals:
  Function:
    Runtime: python3.12
    Timeout: 12
    MemorySize: 384

Parameters:
  StageName:
    Type: String
    Default: sandbox

Resources:
  DeliveryApiResource:
    Type: AWS::Serverless::Api
    Properties:
      StageName: !Ref StageName

  DeliveryUpdates:
    Type: AWS::DynamoDB::Table
    Properties:
      BillingMode: PAY_PER_REQUEST
      AttributeDefinitions:
        - AttributeName: trackingCode
          AttributeType: S
      KeySchema:
        - AttributeName: trackingCode
          KeyType: HASH

  RecordDeliveryUpdate:
    Type: AWS::Serverless::Function
    Properties:
      CodeUri: src/
      Handler: app.handler
      Policies:
        - DynamoDBWritePolicy:
            TableName: !Ref DeliveryUpdates
      Environment:
        Variables:
          TABLE_NAME: !Ref DeliveryUpdates
      Events:
        UpdateEndpoint:
          Type: Api
          Properties:
            RestApiId: !Ref DeliveryApiResource
            Path: /deliveries/{trackingCode}/updates
            Method: post

Outputs:
  DeliveryApi:
    Description: 配送状況更新APIのURL
    Value: !Sub "https://${DeliveryApiResource}.execute-api.${AWS::Region}.amazonaws.com/${StageName}"

テンプレートの各要素を読み分けます。

セクション・型 役割
Transform AWS::Serverless-2016-10-31を指定し、このテンプレートをSAMの変換対象として識別します。SAMテンプレートでは必須です。
Globals 対応するSAMリソースに共通設定を適用します。例では関数のランタイム、タイムアウト、メモリ設定を共通化しています。通常のCloudFormationテンプレートにはないSAM固有セクションです。
Parameters スタック作成・更新時に与える値を宣言します。sam deploy --guidedでは、テンプレートのパラメーターに応じた入力を求められることがあります。
Resources SAMリソースとCloudFormationリソースを定義します。例では通常のDynamoDBテーブルとAWS::Serverless::Functionを組み合わせています。
Outputs スタック作成・更新後に確認できる値を定義します。APIのURL、関数のARN、テーブル名などを出力できます。別スタックから自動的に参照可能になるわけではなく、スタック間で共有する場合はCloudFormationのエクスポートとインポートなどを別途設定します。

AWS::Serverless::FunctionはLambda関数を表し、コードの場所やハンドラー、環境変数、ポリシーなどを関連付けます。Eventsプロパティにイベントソースを定義すると、API Gateway APIや各種イベントとの連携を宣言できます。SAMは関数だけでなく、設定に応じて実行ロール、APIのリソース、イベントソースマッピングや呼び出し権限など、実行に必要な関連リソースも生成します。生成されるものは指定したプロパティや既存リソースの利用方法に依存するため、すべてのテンプレートで同じ関連リソース一式が自動作成されるわけではありません。

SAMが扱う主なリソースには、Lambda関数、API GatewayのAPI、DynamoDBのシンプルなテーブル、Step Functionsのステートマシンなどがあります。SAMイベント定義の例として、S3オブジェクトの通知、SNS通知、SQSメッセージ、APIリクエスト、スケジュールイベントなどがあります。イベント型や対象サービスごとに設定方法や制約が異なるため、実装時は該当するSAMリソースとイベントの仕様を確認します。

例のPoliciesではDynamoDBテーブルへの書き込みに必要なポリシーテンプレートを指定しています。関数の実行ロールが生成される場合でも、SAMを使えば必要権限を何も考えずに済むわけではありません。アクセス対象と操作を限定し、最小権限になるようポリシーを設計します。また、Globalsに置けるプロパティはリソース型ごとに定められており、任意の設定をすべて共通化できるものではありません。

AWS SAM CLIを使う開発フロー

SAM CLIの利用は、プロジェクトの準備、ビルド、ローカル検証、AWS環境へのデプロイ、デプロイ済み環境での確認という流れで考えると整理しやすくなります。

AWS SAMテンプレートからCloudFormationを経てAWSリソースをデプロイする流れ

1. sam init:プロジェクトを初期化する

sam init

sam initは新しいSAMプロジェクトを作るコマンドです。対話形式またはコマンドラインのオプションで、ランタイム、プロジェクトテンプレート、プロジェクト名などを選択できます。選んだスターターテンプレートに応じて、SAMテンプレート、関数コードと依存関係を置くディレクトリ、テスト用イベント、ユニットテストの構造、samconfig.tomlなどが用意されます。生成物はテンプレートや選択肢によって異なり、すべてのプロジェクトに同じフォルダーやファイルが必ず作られるわけではありません。

生成されたコードや設定をそのまま使うのではなく、実装したい機能、アクセス権、入力イベント、エラー処理などに合わせて編集します。

2. sam build:デプロイ可能な成果物を用意する

sam build

sam buildは関数やレイヤーをビルドし、後続のローカルテストやデプロイで利用する形式にアプリケーションを準備します。依存ライブラリの解決やコピー、ランタイムに応じたビルド処理を行い、標準ではプロジェクト内に.aws-samディレクトリを作成します。ビルド後のテンプレートと成果物は、一般に.aws-sam/build以下に配置されます。プロジェクトの構成やビルダーの種類に応じて処理内容は異なります。

ネイティブ依存を含む関数など、開発端末とLambda実行環境の差がビルド結果に影響する場合は、sam build --use-containerを使ってコンテナ内でビルドする方法があります。コンテナを使用するビルドではDockerなど実行環境の準備が必要です。

3. sam local:ローカルで関数やAPIを試す

関数をイベント一件で実行するには、たとえば次のコマンドを使います。

sam local invoke RecordDeliveryUpdate --event events/delivery-update.json

sam local invokeは指定したテストイベントを使い、関数をローカルで一度実行します。APIをHTTP経由で試す場合はsam local start-apiでローカルのHTTPサーバーを起動し、エンドポイントにリクエストを送ります。sam local generate-eventを使ってAWSサービスの形式に沿ったテストイベントを生成することもできます。

ローカルテストは実装を早く確認するのに役立ちますが、AWS上の権限、ネットワーク、マネージドサービスの振る舞いを完全に再現するとは限りません。特にクラウドサービスとの実際の連携や環境固有設定は、AWS環境でのテストも必要です。

4. sam deploy:CloudFormation経由でAWSへ配備する

sam deploy --guided

初回は--guidedを付けると、スタック名、AWSリージョン、デプロイ時の確認、SAMが必要なIAMロールを作成するための許可などを対話形式で設定できます。設定を保存すれば、後続のデプロイではsam deployを利用し、必要に応じてsamconfig.tomlやコマンドラインオプションで設定を変更できます。

デプロイでは、LambdaのZIPパッケージなどのアプリケーション成果物をパッケージ化してアップロードし、アップロード先を含むテンプレートをCloudFormationへ渡します。コンテナイメージ形式の関数では、イメージレジストリへの登録などパッケージ種別に応じた処理が行われます。その後CloudFormationがテンプレートに基づいてスタックの作成・更新を進めます。したがって、SAMが直接リソースを一つずつ作成するのではなく、SAM CLIが成果物とテンプレートを準備し、CloudFormationがAWSリソースを管理します。

スタックの出力には、エンドポイントURLやリソースARNなどを設定できます。デプロイ完了後に出力値を確認すれば、テスト用URLの把握や他の作業への引き渡しが容易になります。

5. sam sync:開発中の変更をクラウドに素早く同期する

sam sync --watch --stack-name delivery-sandbox

sam syncは、デプロイ済みの開発環境へローカルの変更を反映するためのコマンドです。--watchを使うと変更を監視し、更新内容に応じた方法でクラウド側へ同期します。変更の種類によってはサービスAPIを利用した更新が行われ、CloudFormationデプロイを経ずにコードなどを素早く反映できます。一方、サービスAPIで更新できない変更ではCloudFormationを通じたスタック更新が必要になることがあります。

そのため、「常にCloudFormationを経由せずに全種類の変更を反映する」と理解するのは正確ではありません。またAWSはsam syncを開発環境向けに推奨しており、本番環境ではsam deployまたはCI/CDパイプラインを使います。変更の速さを優先する開発用同期と、レビューや承認、再現性を含めたリリースプロセスを区別してください。

6. sam remote invoke:AWS上のリソースを呼び出す

sam remote invoke RecordDeliveryUpdate --stack-name delivery-sandbox \
  --event events/delivery-update.json

sam remote invokeは、すでにAWSにデプロイされた対応リソースをクラウド上で呼び出すコマンドです。Lambda関数へのイベント送信のほか、対応するKinesis Data Streams、SQS、Step Functionsなどのリソースとのやり取りに利用できます。リソースの論理名や物理IDなどで対象を指定し、必要に応じてイベントデータを渡して結果を確認します。

これはローカルマシン内で関数を実行するsam local invokeとは異なります。sam remote invokeの処理対象はAWS上のリソースであり、クラウド環境の挙動を使って確認できます。AWS認証情報、リージョン、呼び出し権限などが必要になるほか、実際のリソースを呼び出すため、テストデータや副作用にも注意します。

コマンドの使い分け

コマンド 主な目的 実行対象・結果
sam init 新規プロジェクトの作成 開発端末にテンプレートやスターターコードを用意
sam build コードと依存関係のビルド 開発端末にローカルテスト・デプロイ向け成果物を作成
sam local invoke 関数を一度実行してテスト 開発端末上のローカル実行環境
sam local start-api APIエンドポイントをローカルでテスト 開発端末上のHTTPサーバー
sam deploy アプリケーションを配備・更新 成果物をアップロードし、CloudFormationスタックを作成・更新
sam sync 開発環境への変更を同期 デプロイ済みのAWSリソース。変更内容に応じて同期方法が異なる
sam remote invoke デプロイ済みリソースをクラウド上で呼び出す AWS上の対応リソース

開発ではinitの後、コードやテンプレートの編集とbuild、localによるテストを必要に応じて繰り返します。クラウドでの動作確認が必要になったらdeployでスタックを作り、開発中の迅速な反映にはsync、AWS上の関数やワークフローを直接試すにはremote invokeを利用できます。これらのコマンドは一度きりの直線的な手順ではなく、検証と修正の反復を支援します。

学習・設計で押さえる点

  • SAMとCloudFormationの関係:SAMはサーバーレス向けのテンプレート記法とCLIを提供し、CloudFormationテンプレートとの互換性を保ちながら既存のAWSリソースも組み合わせます。デプロイ後のスタック管理の中心はCloudFormationです。
  • 抽象化と権限設計:短いテンプレートで関数やイベント連携を定義できても、必要なIAM権限、暗号化、ログ、再試行、タイムアウトなどの設計責任は残ります。
  • ローカル検証とクラウド検証:sam localは開発時のフィードバックに適しますが、AWS環境との完全な同等性を保証しません。環境依存の動作はデプロイ後に確認します。
  • 本番デプロイと高速同期:sam syncは開発中の短いフィードバックサイクル向けです。本番変更はsam deployやCI/CDを通じ、変更確認とリリース管理を行います。
  • 出力値の利用:Outputsはスタックの情報を表示するために使えます。別スタックで値を参照させるには、必要なエクスポート/インポートの仕組みを明示します。

まとめ

サーバーレスでは、物理サーバーや仮想マシンなどの基盤管理をクラウド事業者に委ね、コードやアプリケーションの動作に集中できます。SaaS・PaaS・IaaSがサービス提供レイヤーの分類であるのに対し、サーバーレスはサーバー管理を抽象化する実行モデルです。

AWS SAMはCloudFormationを拡張したIaCフレームワークです。AWS::Serverless::FunctionなどのSAMリソースやイベントを簡潔に定義し、デプロイ時にCloudFormationリソースへ変換します。テンプレートではTransform、共通プロパティをまとめるGlobals、実行時入力のParameters、リソース定義のResources、スタック情報を返すOutputsの役割を区別します。

開発工程では、sam initでプロジェクトを用意し、sam buildで成果物を作り、sam localで端末上のテストを行います。sam deployは成果物をアップロードしてCloudFormation経由でスタックを更新し、sam syncは開発環境への変更を素早く同期します。sam remote invokeはデプロイ済みリソースをAWS上で実行するため、ローカル呼び出しとの違いを理解することが重要です。

公式ドキュメント

重要ポイント

  • ▸サーバーレスはサーバー管理を利用者が意識せずに済む実行モデルであり、SaaS・PaaS・IaaSとは分類の観点が異なる
  • ▸AWS SAMはCloudFormationを拡張するIaCフレームワークで、短縮構文をCloudFormationリソースへ変換してデプロイする
  • ▸TransformにはAWS::Serverless-2016-10-31を指定し、Globalsで対応するSAMリソースの共通プロパティを定義できる
  • ▸AWS::Serverless::FunctionはLambda関数に加え、実行ロールやイベント連携などの関連リソースを表現できる
  • ▸sam init、build、local、deployを使い、ひな形作成からローカル確認、CloudFormation経由の配備まで段階的に進める
  • ▸sam syncは開発環境向けの迅速な同期であり、本番環境にはsam deployまたはCI/CDを使う
  • ▸sam remote invokeはデプロイ済みの対応リソースをクラウド上で呼び出し、ローカル開発端末から結果を確認する

このトピックの学習を完了しますか?

完了状態はいつでも切り替えられます