1. 概要

前回の記事では、RESTエンドポイント用のAPI Gateway、ビジネスロジック用のAWS Lambda、データベースとしてのDynamoDBを使用して、フルスタックサーバーレスアプリケーションをAWSに実装しました。

ただし、展開は多くの手動の手順で構成されているため、複雑さが増したり、環境の数が増えたりすると、手に負えなくなる可能性があります。

このチュートリアルでは、 AWSサーバーレスアプリケーションモデル(SAM)の使用方法について説明します。これにより、テンプレートベースの説明とAWSでのサーバーレスアプリケーションの自動デプロイが可能になります。

詳細については、次のトピックを見ていきます。

  • サーバーレスアプリケーションモデル(SAM)の基本、および基盤となるCloudFormationの基本
  • SAMテンプレート構文を使用したサーバーレスアプリケーションの定義
  • CloudFormationCLIを使用したアプリケーションの自動デプロイ

2. 基本

以前で説明したように、AWSでは、API Gateway、Lambda関数、DynamoDBを使用して、完全にサーバーレスのアプリケーションを実装できます。 間違いなく、これはパフォーマンス、コスト、およびスケーラビリティに関してすでに多くの利点を提供します。

ただし、欠点は、各関数の作成、コードのアップロード、DynamoDBテーブルの作成、IAMロールの作成、APIおよびAPI構造の作成など、現時点でAWSコンソールに多くの手動手順が必要なことです。

複雑なアプリケーションや、テスト、ステージング、本番環境などの複数の環境では、その労力は急速に増大します。

ここで、一般的なAWS上のアプリケーション用のCloudFormationと、特にサーバーレスアプリケーション用のサーバーレスアプリケーションモデル(SAM)が役立ちます。

2.1. AWS CloudFormation

CloudFormationは、AWSインフラストラクチャリソースの自動プロビジョニングのためのAWSサービスです。 ユーザーがブループリント(テンプレートと呼ばれる)で必要なすべてのリソースを定義し、AWSがプロビジョニングと構成を処理します。

次の用語と概念は、CloudFormationとSAMを理解するために不可欠です。

テンプレートは、アプリケーションの説明であり、実行時にどのように構造化する必要があるかを示します。 必要なリソースのセットと、これらのリソースの構成方法を定義できます。 CloudFormationは、テンプレートを定義するための共通言語を提供し、JSONとYAMLをフォーマットとしてサポートします。

リソースはCloudFormationの構成要素です。リソースには、RestApi、RestApiのステージ、バッチジョブ、DynamoDBテーブル、EC2インスタンス、ネットワークインターフェース、IAMロールなどがあります。などなど。 公式ドキュメントには、現在CloudFormationの約300のリソースタイプがリストされています。

スタックはテンプレートのインスタンス化です。CloudFormationはスタックのプロビジョニングと構成を処理します。

2.2. サーバーレスアプリケーションモデル(SAM)

よくあることですが、強力なツールを使用すると、非常に複雑で扱いにくくなる可能性があります。これは、CloudFormationの場合にも当てはまります。

そのため、Amazonはサーバーレスアプリケーションモデル(SAM)を導入しました。 SAMは、サーバーレスアプリケーションを定義するためのクリーンでわかりやすい構文を提供するという主張から始めました。 現在、Lambda関数、DynamoDBテーブル、APIの3つのリソースタイプしかありません。

SAMはCloudFormationテンプレート構文に基づいているため、単純なSAM構文を使用してテンプレートを定義でき、CloudFormationはそのテンプレートをさらに処理します。

詳細については、公式GitHubリポジトリおよびAWSドキュメントをご覧ください。

3. 前提条件

次のチュートリアルでは、AWSアカウントが必要です。 無料利用枠アカウントで十分です。

さらに、AWSCLIをインストールする必要があります

最後に、リージョンにS3バケットが必要です。これは、AWSCLIを介して次のコマンドで作成できます。

$>aws s3 mb s3://baeldung-sam-bucket

チュートリアルでは以下でbaeldung-sam-bucketを使用しますが、バケット名は一意である必要があるため、名前を選択する必要があることに注意してください。

デモアプリケーションとして、 Using AWS Lambda with APIGatewayのコードを使用します。

4. テンプレートの作成

このセクションでは、SAMテンプレートを作成します。

個々のリソースを定義する前に、まず全体的な構造を見ていきます。

4.1. テンプレートの構造

まず、テンプレートの全体的な構造を見てみましょう。

AWSTemplateFormatVersion: '2010-09-09'
Transform: 'AWS::Serverless-2016-10-31'
Description: Baeldung Serverless Application Model example
 
Resources:
  PersonTable:
    Type: AWS::Serverless::SimpleTable
    Properties:
      # Define table properties here
  StorePersonFunction:
    Type: AWS::Serverless::Function
    Properties:
      # Define function properties here
  GetPersonByHTTPParamFunction:
    Type: AWS::Serverless::Function
    Properties:
      # Define function properties here
  MyApi:
    Type: AWS::Serverless::Api
    Properties:
      # Define API properties here

ご覧のとおり、テンプレートはヘッダーと本文で構成されています。

ヘッダーは、CloudFormationテンプレートのバージョン( AWSTemplateFormatVersion )とSAMテンプレートのバージョン( Transform )を指定します。 説明を指定することもできます。

本体は一連のリソースで構成されます。各リソースには、名前、リソース Type 、および一連のPropertiesがあります。

SAM仕様は現在、 AWS :: Serverless :: Api AWS :: Serverless :: Function 、および AWS :: Serverless ::SimpleTableの3つのタイプをサポートしています。 ]。

サンプルアプリケーションをデプロイするため、1つの SimpleTable 、2つの Functions 、および1つのApiを定義する必要があります。テンプレート-本体。

4.2. DynamoDBテーブル定義

今すぐDynamoDBテーブルを定義しましょう:

AWSTemplateFormatVersion: '2010-09-09'
Transform: 'AWS::Serverless-2016-10-31'
Description: Baeldung Serverless Application Model example
 
Resources:
  PersonTable:
    Type: AWS::Serverless::SimpleTable
    Properties:
      PrimaryKey:
          Name: id
          Type: Number
      TableName: Person

SimpleTable の2つのプロパティを定義するだけで済みます。テーブル名と、 id と呼ばれ、タイプ Numberinの主キーです。私たちの場合。

サポートされているSimpleTableプロパティの完全なリストは、公式仕様にあります。

注:主キーを使用してテーブルにアクセスするだけなので、 AWS :: Serverless ::SimpleTableで十分です。 より複雑な要件については、ネイティブのCloudFormationタイプ AWS :: DynamoDB ::Tableを代わりに使用できます。

4.3. ラムダ関数の定義

次に、2つの関数を定義しましょう。

AWSTemplateFormatVersion: '2010-09-09'
Transform: 'AWS::Serverless-2016-10-31'
Description: Baeldung Serverless Application Model example
 
Resources:
  StorePersonFunction:
    Type: AWS::Serverless::Function
    Properties:
      Handler: com.baeldung.lambda.apigateway.APIDemoHandler::handleRequest
      Runtime: java8
      Timeout: 15
      MemorySize: 512
      CodeUri: ../target/aws-lambda-0.1.0-SNAPSHOT.jar
      Policies: DynamoDBCrudPolicy
      Environment:
        Variables:
          TABLE_NAME: !Ref PersonTable
      Events:
        StoreApi:
          Type: Api
            Properties:
              Path: /persons
              Method: PUT
              RestApiId:
                Ref: MyApi
  GetPersonByHTTPParamFunction:
    Type: AWS::Serverless::Function
    Properties:
      Handler: com.baeldung.lambda.apigateway.APIDemoHandler::handleGetByParam
      Runtime: java8
      Timeout: 15
      MemorySize: 512
      CodeUri: ../target/aws-lambda-0.1.0-SNAPSHOT.jar
      Policies: DynamoDBReadPolicy
      Environment:
        Variables:
          TABLE_NAME: !Ref PersonTable
      Events:
        GetByPathApi:
          Type: Api
            Properties:
              Path: /persons/{id}
              Method: GET
              RestApiId:
                Ref: MyApi
        GetByQueryApi:
          Type: Api
            Properties:
              Path: /persons
              Method: GET
              RestApiId:
                Ref: MyApi

ご覧のとおり、各関数には同じプロパティがあります。

ハンドラーは関数のロジックを定義します。Javaを使用しているため、メソッド名に関連するパッケージを含むクラス名です。

ランタイムは、関数の実装方法を定義します。この場合はJava8です。

Timeoutは、AWSが実行を終了するまでにコードの実行に最大でかかる時間を定義します。

MemorySize は、割り当てられたメモリのサイズをMB単位で定義します。AWSはCPUリソースをMemorySizeに比例して割り当てることを知っておくことが重要です。 そのため、CPUを集中的に使用する関数の場合、関数がそれほど多くのメモリを必要としない場合でも、MemorySizeを増やす必要がある場合があります。

CodeUri は、関数コードの場所を定義します。現在、ローカルワークスペースのターゲットフォルダーを参照しています。 後でCloudFormationを使用して関数をアップロードすると、S3オブジェクトへの参照を含む更新されたファイルが取得されます。

ポリシーは、AWSが管理するIAMポリシーまたはSAM固有のポリシーテンプレートのセットを保持できます。 StorePersonFunctionには、SAM固有のポリシーDynamoDBCrudPolicyを使用しますGetPersonByPathParamFunctionおよびGetPersonByQueryParamFunctionおよびDynamoDBReadPolicy

環境実行時に環境プロパティを定義します。DynamoDBテーブルの名前を保持するために環境変数を使用します。

イベントは、関数をトリガーできる一連のAWSイベントを保持できます。この場合、タイプApiのイベントを定義します。 path 、HTTP Method 、および RestApiId の独自の組み合わせにより、関数がAPIのメソッドにリンクされます。これについては次のセクションで定義します。 。

サポートされている機能プロパティの完全なリストは、公式仕様にあります。

4.4. SwaggerファイルとしてのAPI定義

DynamoDBテーブルと関数を定義した後、APIを定義できます。

最初の可能性は、Swagger形式を使用してAPIをインラインで定義することです。

AWSTemplateFormatVersion: '2010-09-09'
Transform: 'AWS::Serverless-2016-10-31'
Description: Baeldung Serverless Application Model example
 
Resources:
  MyApi:
    Type: AWS::Serverless::Api
    Properties:
      StageName: test
      EndpointConfiguration: REGIONAL
      DefinitionBody:
        swagger: "2.0"
        info:
          title: "TestAPI"
        paths:
          /persons:
            get:
              parameters:
              - name: "id"
                in: "query"
                required: true
                type: "string"
              x-amazon-apigateway-request-validator: "Validate query string parameters and\
                \ headers"
              x-amazon-apigateway-integration:
                uri:
                  Fn::Sub: arn:aws:apigateway:${AWS::Region}:lambda:path/2015-03-31/functions/${GetPersonByHTTPParamFunction.Arn}/invocations
                responses: {}
                httpMethod: "POST"
                type: "aws_proxy"
            put:
              x-amazon-apigateway-integration:
                uri:
                  Fn::Sub: arn:aws:apigateway:${AWS::Region}:lambda:path/2015-03-31/functions/${StorePersonFunction.Arn}/invocations
                responses: {}
                httpMethod: "POST"
                type: "aws_proxy"
          /persons/{id}:
            get:
              parameters:
              - name: "id"
                in: "path"
                required: true
                type: "string"
              responses: {}
              x-amazon-apigateway-integration:
                uri:
                  Fn::Sub: arn:aws:apigateway:${AWS::Region}:lambda:path/2015-03-31/functions/${GetPersonByHTTPParamFunction.Arn}/invocations
                responses: {}
                httpMethod: "POST"
                type: "aws_proxy"
        x-amazon-apigateway-request-validators:
          Validate query string parameters and headers:
            validateRequestParameters: true
            validateRequestBody: false

Apiには3つのプロパティがあります。StageName はAPIのステージを定義し、 EndpointConfiguration はAPIがリージョナルかエッジ最適化かを定義し、 DefinitionBody [ X196X]APIの実際の構造が含まれています。

DefinitionBody では、3つのパラメーターを定義します。 swagger version as “ 2.0” info:title: as 「testAPI」、および一連のパス

ご覧のとおり、パスはAPI構造を表しており、の前に手動で定義する必要がありました。 Swaggerのpathsは、AWSコンソールのリソースと同等です。 そのように、各 path には1つ以上のHTTP動詞を含めることができます。これは、AWSコンソールのメソッドと同等です。

各メソッドは、1つ以上のパラメーターとリクエストバリデーターを持つことができます。

最もエキサイティングな部分は、属性 x-amazon-apigateway-integration です。これは、SwaggerのAWS固有の拡張機能です。

uri は、呼び出されるLambda関数を指定します。

response は、関数によって返される応答を変換する方法のルールを指定します。 Lambda Proxy Integrationを使用しているため、特定のルールは必要ありません。

type は、Lambdaプロキシ統合を使用することを定義します。したがって、httpMethod「POST」に設定する必要があります。これはLambda関数が期待するものです。

サポートされているApiプロパティの完全なリストは、公式仕様にあります。

4.5. 暗黙のAPI定義

2番目のオプションは、関数リソース内で暗黙的にAPIを定義することです。

AWSTemplateFormatVersion: '2010-09-09'
Transform: 'AWS::Serverless-2016-10-31'
Description: Baeldung Serverless Application Model Example with Implicit API Definition
 
Globals:
  Api:
    EndpointConfiguration: REGIONAL
    Name: "TestAPI"
 
Resources:
  StorePersonFunction:
    Type: AWS::Serverless::Function
    Properties:
      Handler: com.baeldung.lambda.apigateway.APIDemoHandler::handleRequest
      Runtime: java8
      Timeout: 15
      MemorySize: 512
      CodeUri: ../target/aws-lambda-0.1.0-SNAPSHOT.jar
      Policies:
        - DynamoDBCrudPolicy:
            TableName: !Ref PersonTable
      Environment:
        Variables:
          TABLE_NAME: !Ref PersonTable
      Events:
        StoreApi:
          Type: Api
          Properties:
            Path: /persons
            Method: PUT
  GetPersonByHTTPParamFunction:
    Type: AWS::Serverless::Function
    Properties:
      Handler: com.baeldung.lambda.apigateway.APIDemoHandler::handleGetByParam
      Runtime: java8
      Timeout: 15
      MemorySize: 512
      CodeUri: ../target/aws-lambda-0.1.0-SNAPSHOT.jar
      Policies:
        - DynamoDBReadPolicy:
            TableName: !Ref PersonTable
      Environment:
        Variables:
          TABLE_NAME: !Ref PersonTable
      Events:
        GetByPathApi:
          Type: Api
          Properties:
            Path: /persons/{id}
            Method: GET
        GetByQueryApi:
          Type: Api
          Properties:
            Path: /persons
            Method: GET

ご覧のとおり、テンプレートは少し異なります。 AWS :: Serverless ::Apiリソースはもうありません。

ただし、CloudFormationは、タイプApiEvents属性を暗黙の定義として受け取り、とにかくAPIを作成します。 アプリケーションをテストするとすぐに、Swaggerを使用してAPIを明示的に定義した場合と同じように動作することがわかります。

さらに、 Globals セクションがあり、APIの名前を定義できます。また、エンドポイントはリージョナルである必要があります。

唯一の制限が発生します。APIを暗黙的に定義する場合、ステージ名を設定することはできません。 これが、AWSがProdというステージを作成する理由です。

5. 展開とテスト

テンプレートを作成したら、展開とテストに進むことができます。

このため、実際のデプロイをトリガーする前に、関数コードをS3にアップロードします。

最終的には、任意のHTTPクライアントを使用してアプリケーションをテストできます。

5.1. S3へのコードのアップロード

最初のステップでは、機能コードをS3にアップロードする必要があります。

これを行うには、AWSCLIを介してCloudFormationを呼び出します。

$> aws cloudformation package --template-file ./sam-templates/template.yml --s3-bucket baeldung-sam-bucket --output-template-file ./sam-templates/packaged-template.yml

このコマンドを使用して、CloudFormationをトリガーし、 CodeUri:で指定された機能コードを取得してS3にアップロードします。 CloudFormationはpackaged-template.ymlファイルを作成します。このファイルは、 CodeUri:がS3オブジェクトを指すことを除いて同じ内容です。

CLI出力を見てみましょう。

Uploading to 4b445c195c24d05d8a9eee4cd07f34d0 92702076 / 92702076.0 (100.00%)
Successfully packaged artifacts and wrote output template to file packaged-template.yml.
Execute the following command to deploy the packaged template
aws cloudformation deploy --template-file c:\zz_workspace\tutorials\aws-lambda\sam-templates\packaged-template.yml --stack-name <YOUR STACK NAME>

5.2. 展開

これで、実際の展開をトリガーできます。

$> aws cloudformation deploy --template-file ./sam-templates/packaged-template.yml --stack-name baeldung-sam-stack  --capabilities CAPABILITY_IAM

スタックにはIAMロール(DynamoDBテーブルにアクセスするための関数のロールなど)も必要なので、 –capabilitiesパラメーターを指定して明示的に確認する必要があります。

また、CLI出力は次のようになります。

Waiting for changeset to be created..
Waiting for stack create/update to complete
Successfully created/updated stack - baeldung-sam-stack

5.3. 展開レビュー

展開後、結果を確認できます。

$> aws cloudformation describe-stack-resources --stack-name baeldung-sam-stack

CloudFormationは、スタックの一部であるすべてのリソースを一覧表示します。

5.4. テスト

最後に、任意のHTTPクライアントを使用してアプリケーションをテストできます。

これらのテストに使用できるcURLコマンドのサンプルを見てみましょう。

StorePersonFunction

$> curl -X PUT 'https://0skaqfgdw4.execute-api.eu-central-1.amazonaws.com/test/persons' \
   -H 'content-type: application/json' \
   -d '{"id": 1, "name": "John Doe"}'

GetPersonByPathParamFunction

$> curl -X GET 'https://0skaqfgdw4.execute-api.eu-central-1.amazonaws.com/test/persons/1' \
   -H 'content-type: application/json'

GetPersonByQueryParamFunction

$> curl -X GET 'https://0skaqfgdw4.execute-api.eu-central-1.amazonaws.com/test/persons?id=1' \
   -H 'content-type: application/json'

5.5. 掃除

最後に、スタックと含まれているすべてのリソースを削除することでクリーンアップできます。

aws cloudformation delete-stack --stack-name baeldung-sam-stack

6. 結論

この記事では、AWSサーバーレスアプリケーションモデル(SAM)について説明しました。これにより、テンプレートベースの説明とAWSでのサーバーレスアプリケーションの自動デプロイが可能になります。

詳細には、次のトピックについて説明しました。

  • サーバーレスアプリケーションモデル(SAM)の基本、および基盤となるCloudFormation
  • SAMテンプレート構文を使用したサーバーレスアプリケーションの定義
  • CloudFormationCLIを使用したアプリケーションの自動デプロイ

いつものように、この記事のすべてのコードは、GitHubから入手できます。