【AWS SAM 入門③】Lambda-DynamoDB連携編

 AWS Serverless Application Model 入門ハンズオンシリーズ - log4ketancho の第3弾です。

 前回の記事では、AWS SAM を使って Lambda Function をプログラマブルに構築する方法について紹介しました。今回は、

  • SAM を用いて DynamoDB のテーブルを構築する
  • Lambda から DynamoDB にデータストアする

について手順を解説していきます。

DynamoDB テーブルを構築

 まず DynamoDB テーブルを構築します。記載の方法は CloudFormation と同じで、Resources 以下に設定情報を記載していきます。下記のようなテーブルを構築します。

  • プライマリーキーは name という文字列型のカラム
  • Read / Write ユニットともに2
Resources:
  SamSampleLambda:
    (省略. 前回と同じです.)
  SamSampleDynamoTable:
    Type: AWS::Serverless::SimpleTable
    Properties:
      PrimaryKey:
        Name: name
        Type: String
      ProvisionedThroughput:
        ReadCapacityUnits: 2
        WriteCapacityUnits: 2

テンプレートを変更したので、package コマンドと deploy コマンドを実行します。コマンドを再掲しておきます。

$ aws cloudformation package \
    --template-file template.yaml \
    --s3-bucket ketancho-sam-sample \
    --output-template-file packaged-template.yaml \
    --profile sam-sample
$ aws cloudformation deploy \
    --template-file packaged-template.yaml \
    --stack-name sam-sample-stack \
    --capabilities CAPABILITY_IAM \
    --profile sam-sample

ここまでで、DynamoDB のテーブルが構築できるはずです。マネージメントコンソールで確認してみましょう。

f:id:ketancho_jp:20180104003340p:plain

うまく構築できているでしょうか?DynamoDBのテーブル名の最後にランダムな文字列が付いていることを覚えておいてください。

Lambda から DynamoDB にデータストアする

 前回の記事で作成した、外部APIを叩く Lambda 関数を改修し、APIで取得した値をテーブルに格納するようにしてみます。

Lambda Function の作成

 データ格納は boto3 という AWS の Python SDK を用いて行います。boto3 は Lambda 標準でインストールされているライブラリになりますので、前回のような pip install は不要です。その他、JSON 形式のデータを作成するために json パッケージ、浮動小数点を扱うために decimal パッケージを用いて、下記のような Lambda Function を作成します。

# -*- coding: utf-8 -*-
import requests
import boto3
import json
import decimal

def lambda_handler(event, context):
    bf_res = requests.get("https://api.bitflyer.jp/v1/ticker?product_code=BTC_JPY")
    _insert_dynamo(bf_res.json()["ltp"])

def _insert_dynamo(price):
    dynamo = boto3.resource('dynamodb').Table("**テーブル名**")

    json_str = '''
    {
        "name": "btc",
        "price": %f
    }
    ''' % (price)

    item = json.loads(json_str, parse_float=decimal.Decimal)
    dynamo.put_item(Item = item)

    return {"status": "OK"}

 注意しないといけないのが、テーブル名は構築時(deploy 時)に決定するので、このプログラム作成時点では確定していない点です。このような CloudFormation Stack 構築時に決まるリソースIDを扱うには、Lambda の環境変数(Environment > Variables)機能と CloudFormation の Ref 関数を用います。

Lambda の環境変数を使ってハードコーディングを避ける

 環境に応じて変わる値を、Lambda のプログラムにハードコーディングしないようにするためには、Lambda の環境変数機能を用います。SAMの最初の記事でも少しだけ紹介したのですが、下記のように Environment > Variables に値を書くことで、環境変数を設定することができます。

Globals:
  Function:
    Runtime: python3.6
    Timeout: 15
    MemorySize: 256
    Environment:
      Variables:
        TABLE_NAME: "table_name"

ここでは、Globals セクションに設定していますが、Lambda Function ごとに定義することも可能です。

 ここで設定した環境変数を Lambda Function の中で参照するには、下記のように os パッケージを利用します。

# -*- coding: utf-8 -*-
import os
import requests
import boto3
import json
import decimal

def lambda_handler(event, context):
    bf_res = requests.get("https://api.bitflyer.jp/v1/ticker?product_code=BTC_JPY")
    _insert_dynamo(bf_res.json()["ltp"])

def _insert_dynamo(price):
    dynamo = boto3.resource('dynamodb').Table(os.environ['TABLE_NAME'])

    json_str = '''
    {
        "name": "btc",
        "price": %f
    }
    ''' % (price)

    item = json.loads(json_str, parse_float=decimal.Decimal)
    dynamo.put_item(Item = item)

    return {"status": "OK"}

Ref 関数を用いて CFn Stack 構築時に決まる値を取得する

 環境変数に埋め込む値(ここでは DynamoDB のテーブル名)は、Stack 構築時に決まります。このような値を参照するには、CloudFormation の Ref 関数を用います。

Globals:
  Function:
    Runtime: python3.6
    Timeout: 15
    MemorySize: 256
    Environment:
      Variables:
        TABLE_NAME: !Ref SamSampleDynamoTable #★変更箇所

Resources:
  SamSampleLambda:
    (省略. 前回と同じです.)
  SamSampleDynamoTable:
    Type: AWS::Serverless::SimpleTable
    Properties:
      PrimaryKey:
        Name: name
        Type: String
      ProvisionedThroughput:
        ReadCapacityUnits: 2
        WriteCapacityUnits: 2

Resources セクションで定義したリソース名を Ref 関数で参照することで、動的に決まる値を取得することができます。

 CloudFormation には便利な関数がたくさん用意されています。関数を用いることで、環境に依存しない、再利用しやすいテンプレートを作ることができます。Cfn 関数のうち代表的なものの利用方法は、下記の本で解説させていただきました。もしよろしければご覧いただけると幸いです。

Amazon Web Services 業務システム設計・移行ガイド (Informatics&IDEA)

Amazon Web Services 業務システム設計・移行ガイド (Informatics&IDEA)

 以上で、Lambda から DynamoDB への接続を、SAM で構築することができました。不明点、うまくいかない点がございましたら、ご連絡いただければと思います。

まとめと今後

 DynamoDB のテーブル構築と、Lambda - DynamoDB 間の連携ができるようになりました。次回は、API Gateway を用いて Rest API を SAM でプログラマブルに構築する方法についてまとめられればと考えています。

 この記事は、AWS Serveless Application Model 入門シリーズの第3弾です。

www.ketancho.net