SAMでDynamoDBを使ったサーバレスアプリを構築

SAMで構築するDynamoDBを使ったサーバーレスアプリ

DynamoDBを使ったサーバレスアプリをSAMで構築する

AWS DVAの出題範囲の1つでもある、デプロイに関する内容です。
AWS SAM(Serverless Application Model)を使ったサーバレスアプリの作成方法を確認します。

以下のページで、SAMを使って、LambdaとAPI Gatewayを組み合わせて、サーバレスアプリの構築方法をご紹介しました。

あわせて読みたい
SAMを使用したサーバーレスアプリ 【SAMを使ってAPI GatewayとLambdaでサーバーレスアプリケーションを作成する】 以下のページで、API GatewayとLambdaを使ったサーバーレスアプリを作成する方法を取り...

今回はこの続編ということで、新たにDynamoDBを組み込んだサーバレスアプリを構築します。

構築する環境

Diagram of serverless app using DynamoDB built with SAM.

基本的には、以前の構成と同様です。
API Gatewayをエンドポイント、バックエンドでLambdaとして作成します。

LambdaからDynamoDBへアクセスし、データの読み書きを実行します。
ユーザからアクセスがあった場合、その日時データを保存します。その後、保存されている全日時データをスキャンし、結果を返します。

SAMテンプレートファイル

以下の構成をSAMで作成します。
以下のURLに、SAMテンプレートとLambda関数用スクリプトファイルを配置しています。

https://github.com/awstut-an-r/awstut-dva/tree/main/01/001

ポイント解説

SAMの基本的な事項については、以下のページをご確認ください。

あわせて読みたい
SAMを使用したサーバーレスアプリ 【SAMを使ってAPI GatewayとLambdaでサーバーレスアプリケーションを作成する】 以下のページで、API GatewayとLambdaを使ったサーバーレスアプリを作成する方法を取り...

DynamoDBの基本については、以下のページをご確認ください。

あわせて読みたい
DynamoDB入門 – レビューデータ用DB構築 【DynamoDBでシンプルなレビューデータ用DBを構築する】 AWS DVAの出題範囲の1つでもある、AWSのサービスによる開発に関する内容です。DynamoDBの入門として、簡単なデ...

本ページでは、上記で触れられてない点について取り上げます。

LambdaからDynamoDBにアクセスするための権限

Lambda関数およびAPI Gatewayの定義は、先述のページと同様です。
ただ今回はLambdaからDynamoDBにアクセスするため、IAMロールを作成し、必要な権限を付与します。

Resources:
  HelloWorldFunctionRole:
    Type: AWS::IAM::Role
    Properties:
      AssumeRolePolicyDocument:
        Version: 2012-10-17
        Statement:
          - Effect: Allow
            Action: sts:AssumeRole
            Principal:
              Service:
                - lambda.amazonaws.com
      ManagedPolicyArns:
        - arn:aws:iam::aws:policy/service-role/AWSLambdaBasicExecutionRole
      Policies:
        - PolicyName: HelloWorldFunctionPolicies
          PolicyDocument:
            Version: 2012-10-17
            Statement:
              - Effect: Allow
                Action:
                  - dynamodb:List*
                  - dynamodb:DescribeReservedCapacity*
                  - dynamodb:DescribeLimits
                  - dynamodb:DescribeTimeToLive
                Resource: "*"
              - Effect: Allow
                Action:
                  #- dynamodb:BatchGet*
                  #- dynamodb:DescribeStream
                  #- dynamodb:DescribeTable
                  #- dynamodb:Get*
                  #- dynamodb:Query
                  - dynamodb:Scan
                  #- dynamodb:BatchWrite*
                  #- dynamodb:CreateTable
                  #- dynamodb:Delete*
                  #- dynamodb:Update*
                  #- dynamodb:PutItem
                Resource: !GetAtt Table.Arn
Code language: YAML (yaml)

今回はAWS公式のAmazon DynamoDB: 特定のテーブルへのアクセスを許可するを参考にIAMロールを定義しました。

SAMでDynamoDBを定義する

SAMには、専用の記法が用意されています。
今回はSAMの記法に則って、現在日時を保存するためのDynamoDBテーブルを定義します。

Resources:
  Table:
    Type: AWS::Serverless::SimpleTable
    Properties:
      PrimaryKey:
        Name: dt
        Type: String
      #ProvisionedThroughput:
      TableName: !Sub ${Prefix}-Table
Code language: YAML (yaml)

通常のCloudFormationでは、DynamoDBを作成する場合、Typeプロパティに「AWS::DynamoDB::Table」を指定しますが、SAMの記法に従うと「AWS::Serverless::SimpleTable」となります。
PrimaryKeyプロパティでパーティションキーを指定します。今回は「dt」という文字列タイプの属性をパーティションキーとするように指定します。
今回はProvisionedThroughputプロパティを設定しません。設定しないということは、オンデマンドモードを選択するという意味になります。

ProvisionedThroughput

スループットプロビジョニング情報の読み取りと書き込み。
ProvisionedThroughput を指定しなかった場合、BillingMode は PAY_PER_REQUEST として指定されます。

AWS::Serverless::SimpleTable

なおオンデマンドモードは、事前のキャパシティプロビジョニングが不要で、トラフィック量に応じた支払いが可能なモデルです。

DynamoDB on-demandはシンプルなpay-per-request課金モデルを提供しreadリクエストとwriteリクエストを使った分に応じて支払うだけになります。これによりシンプルなコスト計算とパフォーマンス管理を実現します。

Amazon DynamoDB On-Demand – 事前のキャパシティプランニングが不要のリクエスト課金が可能になりました。

参考までに、通常のCloudFormationの記法で、同様のテーブルを作成する場合のコードを記載します。

Resources:
  SampleTable:
    Type: AWS::DynamoDB::Table
    Properties:
      AttributeDefinitions:
        - AttributeName: dt
          AttributeType: S
      BillingMode: PAY_PER_REQUEST
      KeySchema:
        - AttributeName: dt
          KeyType: HASH
      TableName: !Sub ${Prefix}-SampleTable
Code language: YAML (yaml)

PythonからDynamoDBにアクセスする

PythonスクリプトからDynamoDBへアクセスし、アイテムを読み書きする方法を確認します。

import json
import boto3
import datetime
import json

TABLE_NAME = 'dva-01-001-Table'
REGION_NAME = 'ap-northeast-1'

def lambda_handler(event, context):
    now = datetime.datetime.now()
    now_str = now.strftime('%Y-%m-%d %H:%M:%S')

    dynamodb_config = {
        'region_name': REGION_NAME
    }
    dynamodb = boto3.resource('dynamodb', **dynamodb_config)
    table = dynamodb.Table(TABLE_NAME)

    table.put_item(Item={
        'dt': now_str
    })

    result = table.scan()

    return {
        "statusCode": 200,
        "body": json.dumps(
            {"AccessDatetime": result},
            indent=2
        )
    }
Code language: Python (python)

ポイントを取り上げます。
datetimeオブジェクトを作成し、現在日時を取得します。取得後、フォーマットを指定して文字列として取得します。
boto3.resourceでBynamoDBにアクセスするためのクライアントオブジェクトを作成します。
同オブジェクトを使用し、テーブル名を指定して、テーブルオブジェクトを作成します。
テーブルオブジェクトのput_itemメソッドで項目を保存できます。今回は属性名をdtとし、先ほど取得した現在日時データを保存します。
保存済みの全項目を取得する場合は、同オブジェクトのscanメソッドを使用します。
最後にHTTPのステータスコードとともに、scanメソッドで取得したデータを返します。

SAMアプリをビルド・デプロイ

samコマンドを使用して、アプリをビルドし、デプロイします。
以下のページをご確認ください。

あわせて読みたい
SAMを使用したサーバーレスアプリ 【SAMを使ってAPI GatewayとLambdaでサーバーレスアプリケーションを作成する】 以下のページで、API GatewayとLambdaを使ったサーバーレスアプリを作成する方法を取り...

今回生成された主要リソースの情報は以下の通りです。

  • API Gateway:HelloWorldApi
  • Lambda関数:HelloWorldFunction
  • DynamoDB:dva-01-001-SimpleTable

AWS Management Consoleからも、リソースの作成状況を確認します。
まずCloudFormationで作成されたスタックを確認します。

The CloudFormation stack is created by SAM deployment.

SAMアプリをデプロイすることによって、自動的にCloudFormationスタックが作成されました。
これはSAMがCloudFormationの変形であるためです。

The resources defined in the SAM template are created in the stack.

Resourcesタブを見ると、実際に作成されたリソースを確認することができます。

作成されたリソースの詳細を確認します。

Lambda Function is created by SAM deployment.
DynamoDB is created by SAM deployment.
The API Gateway was created by SAM deployment.

Lambda、DynamoDB、API Gatewayが作成されました。特にAPI Gatewayに関しては、エンドポイントのURLが確認できます。

A Lambda function is associated with /hello in API Gateway.

SAMアプリにアクセス

準備が整いましたので、アプリにアクセスします。

Access to Serverless Apps 1.

応答がありました。API Gatewayを介して、Lambda関数が呼び出され、同関数内からDynamoDBにアクセスしています。
現在日時情報が1件書き込まれた後、scanが実行されていることがわかります。

何度かアクセスしてみます。

Access to Serverless Apps 2.

アクセスする度に、アイテム数が増えていくことがわかります。

最後にAWS Management ConsoleからDynamoDBを確認してみます。

DynamoDB scan results.

こちらからも保存されているアイテムが表示されました。
先ほどと同様に3件分が確認できます。

まとめ

SAMを使用して、Lambda、API Gateway、そしてDynamoDBで構成されるWebアプリの作成方法を確認しました。