🕌

AWS SAM+DynamoDBのDockerローカル開発環境を作る

2022/03/13に公開

概要

AWS で API Gateway、Lambda、DynamoDB を組み合わせた開発を行うために、AWS SAM を用いて開発環境を構築してみます。

今回は DynamoDB を組み合わせてみますが、AWS SAM による、基本的な API Gateway、Lambda での環境構築および操作方法は、以下を参考にしてみてください。

https://zenn.dev/ttani/articles/aws-sam-setup

また、ローカル DynamoDB 単体の構築方法は以下を参考にしてみてください。

https://zenn.dev/ttani/articles/docker-dynamodb-local

前提

以下の内容は、インストール済みの前提とします。

  • AWS CLI
  • AWS SAM CLI
  • Docker

構成

最終的に作成する構成は以下の通りとします。

.
|-- .gitignore
|-- Dockerfile-awscli
|-- README.md
|-- __tests__
|   `-- unit
|       `-- handlers
|           |-- get-all-items.test.js
|           |-- get-by-id.test.js
|           `-- put-item.test.js
|-- bin
|-- buildspec.yml
|-- docker-compose.yml
|-- env.json
|-- events
|   |-- event-get-all-items.json
|   |-- event-get-by-id.json
|   `-- event-post-item.json
|-- package.json
|-- src
|   `-- handlers
|       |-- get-all-items.js
|       |-- get-by-id.js
|       `-- put-item.js
`-- template.yaml

手順

SAM プロジェクトの作成

SAM プロジェクトを作成します。
今回は、ランタイム環境は、Node.js としています。

shell
sam init --runtime nodejs14.x

対話方式で聞かれるので、以下のように選択していきます。

  • 1 - AWS Quick Start Templates
  • 6 - Serverless API

プロジェクト名を聞かれるので、任意のプロジェクト名(例:sam-dynamodb-sample)を入力します。

docker network の作成

ローカル DynamoDB と SAM 環境を接続するための、docker network を 1 つ個別に作成しておきます。

shell
docker network create lambda-local

AWS CLI(DynamoDB 直操作用)の Dockerfile 作成

作成したプロジェクトフォルダに移動し、以下のファイルを作成します。

Dockerfile-awscli
FROM amazon/aws-cli

ENV AWS_ACCESS_KEY_ID=fake_access_key\
    AWS_SECRET_ACCESS_KEY=fake_secret_access_key\
    DYNAMODB_REGION=ap-northeast-1
WORKDIR /usr/app

ローカル DynamoDB 用の Dockerfile 作成

以下のファイルを作成します。

docker-compose.yml
version: '3'
services:
    dynamodb:
        image: amazon/dynamodb-local
        command: -jar DynamoDBLocal.jar -sharedDb -dbPath . -optimizeDbBeforeStartup
        volumes:
            - dynamodb:/home/dynamodblocal
        ports:
            - 8001:8000
        networks:
            - lambda-local
    awscli:
        build:
            context: .
            dockerfile: Dockerfile-awscli
        entrypoint: [""]
        tty: true
        command:
            - /bin/sh
        volumes:
            - ./bin:/usr/app
        networks:
            - lambda-local
volumes:
    dynamodb:
        driver: local
    bin:
        driver: local
networks:
    lambda-local:
        external: true

※DynamoDB のポートは他の処理と衝突しないよう 8000 番ポート →8001 番ポートにマッピングしています。環境に合わせて設定してください。(8000 番ポートでも問題ないです)

設定のポイントとしては、dynamodbawscliの 2 つのサービスを、 lambda-localネットワークに参加させている点と、networks-lambda-local-external: trueを設定している点になります。

ローカル DynamoDB にテーブルとテストデータを作成する

SAM から接続確認をするための、テーブルを、ローカル DynamoDB 上に作成しておきます。

コンテナを起動する

shell
docker-compose up -d

AWS CLI 用コンテナ名を確認する

shell
docker ps -a

AWS CLI 用コンテナに入る

shell
docker exec -it [AWS CLI用コンテナ名] /bin/bash

テーブル作成

shell
aws dynamodb \
  --region ap-northeast-1 \
  --endpoint-url http://dynamodb:8000 \
    create-table \
  --table-name SampleTable \
  --attribute-definitions \
    AttributeName=id,AttributeType=S \
  --key-schema \
    AttributeName=id,KeyType=HASH \
  --billing-mode PAY_PER_REQUEST

※テーブル名SampleTable及びパーティションキーidは、SAM の6 - Serverless APIで使用している名前のため、今回は動作確認しやすいように、それに合わせています。
※結果が表示されたら下までスクロールしてqで抜けます。

テストデータ追加

shell
aws dynamodb put-item \
    --region ap-northeast-1 \
    --endpoint-url http://dynamodb:8000 \
    --table-name SampleTable \
    --item '{
        "id": {"S": "123"},
        "name": {"S": "Test"}
      }'

操作が終わったら、exitでコンテナから抜けます。

DynamoDBClient の接続情報をローカル接続に対応させる

Lambda ソース内の DynamoDBClient 接続に関して、ローカル環境の場合にローカル DynamoDB を参照するように、以下のように書き換えておきます。

対象ファイル(例)

src/handlers/get-all-items.js

編集前

const docClient = new dynamodb.DocumentClient();

編集後

const docClient = new dynamodb.DocumentClient(
  process.env.AWS_SAM_LOCAL
    ? {
        credentials: {
          accessKeyId: "fakeMyKeyId",
          secretAccessKey: "fakeSecretAccessKey",
        },
        region: "ap-northeast-1",
        endpoint: "http://dynamodb:8000",
      }
    : {}
);

※SAM Local で実行した場合process.env.AWS_SAM_LOCALtrueになっています。

SAM ローカルで関数を実行する

以下の関数を実行し、ローカルで関数の動作を確認します。

shell
sam local invoke -e events/event-get-all-items.json --docker-network lambda-local getAllItemsFunction

実行結果

INFO	response from: undefined statusCode: 200 body: [{"name":"Test","id":"123"}]

事前に投入したテストデータが出力されれば OK です。

SAM ローカルで API を実行する

続いて、ローカルで API を動かして確認してみます。

shell
sam local start-api --docker-network lambda-local

ブラウザで次の URL にアクセスします。

http://127.0.0.1:3000/

次のレスポンスが返却されれば OK です。

[{ "name": "Test", "id": "123" }]

ローカルでの確認は以上で終了です。

あとは、sam deploy --guidedで実際に AWS 環境にデプロイして確認していけば OK です。

注意点

SAM から DynamoDB テーブルを作成した場合、自動的に次のような名前のテーブルが生成されます。

sam-app-SampleTable-FGDKBGW9SS75

SAM 以外からも参照するテーブルや既存テーブルの場合は、SAM 側からはテーブルを作成しないようにするといった工夫が必要になると思います。

まとめ

APΙ Gateway+Lambda+DynamoDB で API を作成するパターンは多いかと思います。

いずれ、ローカル DynamoDB や docker network を用意しなくても、AWS SAM だけで出来るようになりそうにも思いますが、ローカルで DynamoDB も含めて確認できると便利な場面はいろいろとありそうです。

株式会社トッカシステムズ

Discussion