AWSサーバーレスアプリケーションモデルの紹介

AWSサーバーレスアプリケーションモデルの概要

1. 概要

our previous articleでは、RESTエンドポイント用のAPI Gateway、ビジネスロジック用のAWS Lambda、およびデータベースとしてのDynamoDBを使用して、AWSにフルスタックサーバーレスアプリケーションをすでに実装しています。

ただし、展開は多くの手動の手順で構成されており、複雑さが増し、環境の数が増えると手間がかかる場合があります。

このチュートリアルでは、AWS Serverless Application Model (SAM), which enables a template-based description and automated deployment of serverless applications on AWSの使用方法について説明します。

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

  • サーバーレスアプリケーションモデル(SAM)の基礎と、基盤となるCloudFormationの基礎

  • SAMテンプレート構文を使用したサーバーレスアプリケーションの定義

  • CloudFormation CLIを使用したアプリケーションの自動展開

2. 基本

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

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

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

これは一般にAWS上のアプリケーションのCloudFormationであり、特にサーバーレスアプリケーション専用のサーバーレスアプリケーションモデル(SAM)が登場します。

2.1. AWS CloudFormation

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

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

A template is a description of an application、実行時にどのように構造化するか。 必要なリソースのセットと、これらのリソースの構成方法を定義できます。 CloudFormationは、テンプレートを定義し、JSONおよびYAMLをフォーマットとしてサポートするための共通言語を提供します。

Resources are the building blocks in CloudFormation.リソースには、RestApi、RestApiのステージ、バッチジョブ、DynamoDBテーブル、EC2インスタンス、ネットワークインターフェイス、IAMロールなど、何でもかまいません。 The official documentationは現在、CloudFormationの約300のリソースタイプを一覧表示しています。

A stack is the instantiation of a template. CloudFormationは、スタックのプロビジョニングと構成を処理します。

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

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

AmazonがServerless Application Model(SAM)を導入したのはそのためです。 SAM started with the claim to provide a clean and straightforward syntax for defining serverless applications. Currently, it has only three resource types, which are Lambda functions, DynamoDB tables, and APIs

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

詳細については、at the official GitHub repositoryおよびAWS documentation内をご覧ください。

3. 前提条件

次のチュートリアルでは、AWSアカウントが必要です。 A free tier accountで十分です。

さらに、AWS CLIinstalledが必要です。

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

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

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

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

4. テンプレートの作成

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

個々のリソースを定義する前に、まず全体的な構造を確認します。

4.1. テンプレートの構造

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

AWSTemplateFormatVersion: '2010-09-09'
Transform: 'AWS::Serverless-2016-10-31'
Description: example 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)を指定します。 Descriptionを指定することもできます。

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

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

example applicationをデプロイするため、テンプレート本体に1つのSimpleTable、2つのFunctions、および1つのApiを定義する必要があります。

4.2. DynamoDBテーブル定義

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

AWSTemplateFormatVersion: '2010-09-09'
Transform: 'AWS::Serverless-2016-10-31'
Description: example Serverless Application Model example

Resources:
  PersonTable:
    Type: AWS::Serverless::SimpleTable
    Properties:
      PrimaryKey:
          Name: id
          Type: Number
      TableName: Person

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

サポートされているSimpleTableプロパティの完全なリストは、in the official specificationにあります。

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

4.3. ラムダ関数の定義

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

AWSTemplateFormatVersion: '2010-09-09'
Transform: 'AWS::Serverless-2016-10-31'
Description: example Serverless Application Model example

Resources:
  StorePersonFunction:
    Type: AWS::Serverless::Function
    Properties:
      Handler: com.example.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.example.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

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

Handler defines the logic of the function. Javaを使用しているため、メソッド名に関連するパッケージを含むクラス名です。

Runtime defines how the function was implemented、この場合はJava8です。

AWSが実行を終了する前のTimeout defines how long the execution of the code may take at most

MemorySizedefines the size of the assigned memory in MB. AWSはCPUリソースをMemorySizeに比例して割り当てることを知っておくことが重要です。 そのため、CPUを集中的に使用する関数の場合、関数がそれほど多くのメモリを必要としない場合でも、MemorySizeを増やす必要がある場合があります。

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

Policiescan hold a set of AWS-managed IAM policies or SAM-specific policy templates.StorePersonFunctionにはSAM固有のポリシーDynamoDBCrudPolicyを使用し、GetPersonByPathParamFunctionGetPersonByQueryParamFunctionにはDynamoDBReadPolicyを使用します。

Environmentdefines environment properties at runtime.DynamoDBテーブルの名前を保持するために環境変数を使用します。

Eventscan hold a set of AWS events, which shall be able to trigger the function.この場合、タイプApiEventを定義します。 path、HTTPMethod、およびRestApiIdの一意の組み合わせにより、関数がAPIのメソッドにリンクされます。これについては次のセクションで定義します。

サポートされているFunctionプロパティの完全なリストは、in the official specificationにあります。

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

DynamoDBテーブルと関数を定義したら、APIを定義できるようになりました。

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

AWSTemplateFormatVersion: '2010-09-09'
Transform: 'AWS::Serverless-2016-10-31'
Description: example 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 はAPIの実際の構造を含みます。

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

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

各メソッドには、1つ以上のパラメーターと要求検証ツールを含めることができます。

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

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

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

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

サポートされているApiプロパティの完全なリストは、in the official specificationにあります。

4.5. 暗黙のAPI定義

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

AWSTemplateFormatVersion: '2010-09-09'
Transform: 'AWS::Serverless-2016-10-31'
Description: example Serverless Application Model Example with Implicit API Definition

Globals:
  Api:
    EndpointConfiguration: REGIONAL
    Name: "TestAPI"

Resources:
  StorePersonFunction:
    Type: AWS::Serverless::Function
    Properties:
      Handler: com.example.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.example.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 resourceはもうありません。

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

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

1つの制限のみが発生します。APIを暗黙的に定義する場合、ステージ名を設定できません。 これが、AWSがいずれにせよProdと呼ばれるステージを作成する理由です。

5. 展開とテスト

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

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

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

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

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

AWS CLIを介してCloudFormationを呼び出すことでこれを行うことができます。

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

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

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 

5.2. 展開

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

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

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

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

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

5.3. 展開レビュー

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

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

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

5.4. Test

最後に、任意の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 example-sam-stack

6. 結論

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

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

  • サーバーレスアプリケーションモデル(SAM)の基礎と、基盤となるCloudFormation

  • SAMテンプレート構文を使用したサーバーレスアプリケーションの定義

  • CloudFormation CLIを使用したアプリケーションの自動展開

いつものように、この記事のすべてのコードはon GitHubで利用できます。