【DynamoDB Local】快適なDynamoDBのローカル開発環境を構築する
DynamoDBをデータベースとして用いる開発を、完全にローカル環境のみで完結させることができるよう環境構築したので紹介します。
システムの開発フェーズにおいては、個人が好き勝手に作って壊せるデータベース環境が欲しくなることも多いかと思います。RDS等のRDBであれば、ローカルにデータベースを立てればそれで終わりですが、DynamoDBでも同様にローカルにデータベースを立てることが可能です。
この記事では、ただ単に「ローカルにDynamoDBを立てて終わり」ではなく、コマンド一発ですぐに開発が始められるような、快適な開発環境を構築することをゴールとします。
スポンサーリンク
目次
前提とする環境
Docker Composeが利用可能である、インターネットアクセス可能なWindows もしくは Linux環境
これから解説する環境構築の前提は、これだけです。MacOS環境でも動作確認こそしていませんが、使うのはDockerなのでおそらく動作するかと思います。
環境構築方法
使用ツール
まず、DynamoDBのローカル開発環境で使用するツールについて簡単に説明します。
DynamoDB Local
AWS公式がリリースしている、ローカル端末で動作可能なDynamoDB互換のデータベースです。JavaもしくはDocker上で動作します。
https://docs.aws.amazon.com/amazondynamodb/latest/developerguide/DynamoDBLocal.html
https://hub.docker.com/r/amazon/dynamodb-local
AWS環境のDynamoDBのAPIと同じAPIで操作可能であるため、本物を触るのと同じ感覚で開発を進めることができます。(なんとDynamoDB Streamsまで再現されています)もちろん利用料金は一切かかりません。
ただし、AWS上のDynamoDBとは一部異なる動作をしますので、注意する必要があります。
- プロビジョニングされたキャパシティー(Provisioned Read/Write Capacity)に設定した値は無視されます。
- 単一のローカルマシンで実行されるので、副次的にほとんどの読み取り操作で強力な整合性が取れているように見えます。(全く同じテーブルに対し、全く同じ読み取り操作を行っても、結果がAWS上で得られるものとは異なるケースがあります)
- トランザクションの競合によって発生する、TransactionConflictExceptionsはスローされません
- DynamoDB Localではテーブル名の大文字小文字を区別しませんが、AWS環境ではこれらは区別されます。
より詳細な差異については、下記を参照のこと。
Differences Between Downloadable DynamoDB and the DynamoDB Web Service
DynamoDB Localのソースは非公開なので、詳細な内部実装は分かりませんが、内部的にSQLiteを使用しているらしいです。すごい…
dynamodb-admin
ローカルで動作するDynamoDBを、GUIで操作可能なWebベースのツールです。node.jsもしくはDocker上で動作します。
localstackなど、DynamoDB Local以外の環境でも動作するようです。
https://github.com/aaronshaf/dynamodb-admin
ちなみに、DynamoDB Local自体にもJavaScriptのAWS SDKを実行できるWebインターフェースが用意されているのですが、テーブルの中身を一覧表示したり、少しレコードを追加したりする程度の操作を実行するには面倒なのでdynamodb-localを使用しています。
ベースとするdocker-compose.yml ファイル
上記のツールは、それぞれDockerイメージが配布されているので、Docker Composeで連携させてコマンド一発で起動するようにします。
基本となるdocker-compose.yml ファイルは下記です。
version: '3'
services:
dynamodb-local:
container_name: test_dynamodb-local
image: amazon/dynamodb-local:latest
user: root
command: -jar DynamoDBLocal.jar -sharedDb -dbPath /data
volumes:
- dynamodb-local-data:/data
ports:
- 8000:8000
networks:
- dynamodb-local-network
dynamodb-admin:
container_name: test_dynamodb-admin
image: aaronshaf/dynamodb-admin:latest
environment:
- DYNAMO_ENDPOINT=dynamodb-local:8000
ports:
- 8001:8001
depends_on:
- dynamodb-local
networks:
- dynamodb-local-network
volumes:
dynamodb-local-data:
networks:
dynamodb-local-network:
driver: bridge
Dockerfileは使わずにすべてDocker Composeのみで完結させることで、イメージのビルド作業を削減し素早い環境構築を可能にしています。
実装のポイント(DynamoDB Local)
# 一部のみ抜粋
user: root
command: -jar DynamoDBLocal.jar -sharedDb -dbPath /data
volumes:
- dynamodb-local-data:/data
user オプションを付けることで、rootユーザーで起動しています。
DynamoDB LocalのDockerイメージは、デフォルトでは一般ユーザーで実行されるようになっています。そのままだとLinux環境で名前付きボリュームを使えなかったため、rootユーザーで起動しています。名前付きボリュームを使わない場合はデフォルトの一般ユーザーで実行しても問題ありません。
command オプションには、コンテナ起動時にJavaのランタイムに渡すコマンドを指定します。
-sharedDb オプションを指定することで、DynamoDB LocalへのAPIコール時のリージョン指定を区別しないように設定しています。(デフォルトではリージョン指定が区別され、異なるリージョンを指定するとそれぞれ別々のDBに対する操作となります)
-dbPath オプションには、永続化するデータのファイルパスを指定しています。名前付きボリューム(volumes オプション)をここで指定したパスに展開すると、コンテナを停止・削除してもDBに保存したデータが永続化されます。これとは反対に、-inMemory オプションを指定すると、データはメモリ内に展開され、コンテナを停止・削除するとデータも破棄されます。(これはcommand オプションに何も指定しない場合のデフォルトの動作です。)ここはユースケースに応じて設定を変えると良いでしょう。
実装のポイント(dynamodb-admin)
# 一部のみ抜粋
environment:
- DYNAMO_ENDPOINT=dynamodb-local:8000
ports:
- 8001:8001
特に捻りはありません。環境変数DYNAMODB_ENDPOINTにDynamoDB Localで設定したポート番号を指定することで、接続先を設定します。
こちらは8001番ポートにバインドしてあるので、http://localhost:8001 にアクセスするとdynamodb-adminのwebインターフェースにアクセスできます。
コンテナを起動する
何の変哲もなく、docker-composeコマンドを叩くだけです。
$ docker-compose up -d
Creating network "dynamodb_dynamodb-local-network" with driver "bridge"
Creating test_dynamodb-local ... done
Creating test_dynamodb-admin ... done
これで、AWS SDK、AWS CLIやDynamoDB LocalのWebインターフェースからテーブルを作成してデータを投入できる状態になります。
Terraformを利用して自動でDynamoDB Localをセットアップする
上記のdocker-compose.ymlでもローカル開発を始めることはできますが、AWS環境でのDynamoDBの作成にTerraformを使っている場合、設定(.tfファイル)はほぼそのままでDynamoDB Localのテーブルやデータの作成も行うことができます。
先ほどの構成をTerraformと連携させることで、DynamoDB Localのコンテナが起動した時点でAWS上の開発/本番環境と同等の状態にセットアップすることができ、さらに開発の効率を向上させることが可能です。
ここからはその方法を紹介します。
Terraform 側の設定
既にTerraformでDynamoDBを構築している場合は、providerの設定を変えるだけです。
provider "aws" {
region = "ap-northeast-1"
skip_credentials_validation = true
skip_requesting_account_id = true
endpoints {
dynamodb = "http://dynamodb-local:8000"
}
}
skip_credential_validation と skip_requesting_account_id を有効にすることで、TerraformによるAWSの認証情報とアカウント情報の検証を無効化しています。こうすることで、後述するTerraformコンテナにAWS認証情報を設定する必要がなくなります。
そして、endpoints の設定に、DynamoDB Localのコンテナを指定することで、実行の向き先をローカルに切り替えることができます。(Dockerコンテナ同士の通信になるので、ホスト名にはlocalhostではなく、サービス名を指定します)
環境別にフォルダを切ってTerraformを使用している場合は、比較的簡単にローカル開発用の設定を追加することができるかと思います。下記にサンプル構成を載せておきます。
.infra
├── environment
│ ├── prod # 本番環境用の設定
│ │ ├── backend.tf
│ │ ├── main.tf
│ │ └── providers.tf
│ └── stg # ステージング環境用の設定
│ │ └── ... 略 ...
│ └── local # ★ローカル開発(DynamoDB Local)用の設定★
│ ├── main.tf
│ └── providers.tf # endpointをローカルに変更
└── modules
└── dynamodb
├── main.tf
└── variables.tf
モジュールを利用している場合のごく普通の構成かと思います。.tfstateファイルは共有したくないので、backendを指定しないことでローカル環境内に作成されるようにしています。
もちろんモジュールを利用していない場合やワークスペースを利用している場合でも、うまく設定はできるでしょう。
docker-compose.yml ファイル
Terraform以外の設定は、先ほどのベースとするdocker-compose.yml ファイルと同じなので割愛します。
terraform:
container_name: test_dynamodb-terraform
image: hashicorp/terraform:0.13.4
command: >
/bin/sh -c
'
echo "plugin_cache_dir = \"/root/.terraform.d/plugin-cache\"" > ~/.terraformrc &&
terraform init &&
terraform apply -auto-approve;
/bin/sh
'
entrypoint: ''
tty: true
environment:
- AWS_ACCESS_KEY_ID=dummy
- AWS_SECRET_ACCESS_KEY=dummy
working_dir: /terraform/environment/local
volumes:
- ../../.infra:/terraform
depends_on:
- dynamodb-local
networks:
- dynamodb-local-network
実装のポイント(docker-compose.yml)
image: hashicorp/terraform:0.13.4
Terraform公式のDockerイメージを使用しています。バージョンを固定していますが、必須ではありません。※1Terraformは、バージョンアップを挟むと比較的頻繁に構文が変わったり後方互換性がなくなったりするので個人的にはできる限りバージョンは固定にしておき、必要に応じて手動でアップデートしながら使いたいと思っています。
command: >
/bin/sh -c
'
echo "plugin_cache_dir = \"/root/.terraform.d/plugin-cache\"" > ~/.terraformrc && # AWSプラグインをキャッシュして使いまわす
terraform init &&
terraform apply -auto-approve;
/bin/sh
'
entrypoint: ''
tty: true
environment:
- AWS_ACCESS_KEY_ID=dummy
- AWS_SECRET_ACCESS_KEY=dummy
まず、公式のDockerイメージにはENTRYPOINTが設定されており、起動と同時にコマンドを実行して終了するようになっているので、entrypoint に空文字を指定することでこの挙動を無効化しています。
command オプションの最後に/bin/sh を指定し、tty オプションを有効化しておくことで、コンテナ起動時にDynamoDB Localの初期化処理を実行した後もコンテナを起動したままにしています。これにより、開発中にTerraformの設定を変え、すぐにTerraformコンテナに入って変更を適用することも可能です。
先ほどTerraformの設定でAWSの認証情報とアカウント情報の検証を無効化したので、正しいAWS認証情報を設定する必要はないのですが、設定自体がないとエラーになるので、でたらめな認証情報を環境変数に設定しています。
# 一部のみ抜粋
working_dir: /terraform/env/local
volumes:
- ../../.infra:/terraform
volumes オプションでTerraformの設定ファイル群をコンテナにマウントし、このディレクトリをコンテナ起動時のカレントディレクトリに設定します。
以上でTerraformとの連携設定は完了です。
まとめ
ここまでの設定を済ませることで、コマンド一発で本番環境同様のDynamoDBをローカルに立てて開発を進めることが可能になります。
コンテナで開発環境を構築しておくと、環境差異によってうまく動作しなくなることも少なくなり、誰でも構築/破棄がすぐにできるのがとてもうれしいですね。
スポンサーリンク
脚注
1. | 戻る | Terraformは、バージョンアップを挟むと比較的頻繁に構文が変わったり後方互換性がなくなったりするので個人的にはできる限りバージョンは固定にしておき、必要に応じて手動でアップデートしながら使いたいと思っています。 |