DockerでDynamoDBのローカル開発環境を構築するための下準備まとめ

# はじめに
DynamoDBを使用したアプリケーションを開発・テストしていると、AWS上のリソースを利用する必要が生じます。
しかしDynamoDB localを利用することで、アプリケーションの開発やテストをローカル環境で行えるようになります。

本記事では、DockerでDynamoDBのローカル開発環境を構築する方法と関連するツールについてまとめました。

# DynamoDB localのコンテナ生成
DynamoDB localのDockerイメージを利用します。
DynamoDB localを使えば、AWS上のDynamoDB(Webサービス)に接続することなくDynamoDBを使ったアプリケーションの開発やテストができるようになります。

[AWS公式ドキュメント](https://docs.aws.amazon.com/ja_jp/amazondynamodb/latest/developerguide/DynamoDBLocal.DownloadingAndRunning.html#docker)をもとに`docker-compose.yml`を記述するだけで、簡単にDynamoDB localのコンテナを用意することができます。

```yaml:docker-compose.yml
version: '3.8'
services:
  dynamodb-local:
    command: "-jar DynamoDBLocal.jar -sharedDb -dbPath ./data"
    image: "amazon/dynamodb-local:latest"
    container_name: dynamodb-local
    ports:
      - "8000:8000"
    volumes:
      - "./docker/dynamodb:/home/dynamodblocal/data"
    working_dir: /home/dynamodblocal
```

以下のコマンドでコンテナを立ち上げてください。
```shell
docker compose up -d
```

## 注意点

### エンドポイントURLの指定が必要になる

DynamoDB localのコンテナを操作する際はエンドポイントURLを指定する必要があります。
例えばAWS CLIを使ってテーブル一覧を取得したい場合は次のようなコマンドを実行します。
```shell
aws dynamodb list-tables --endpoint-url http://localhost:8000
```

別のDockerコンテナからアクセスする場合はURLに注意してください。
```shell
aws dynamodb list-tables --endpoint-url http://dynamodb-local:8000
```

### DynamoDB(Webサービス)と挙動の異なる部分がある
DynamoDB localの挙動にはAWS上のDynamoDB(Webサービス)といくらか異なる部分があります。

DynamoDB local特有の挙動の例
- 設定したRCU・WCUの値が使用されない
- `TransactionConflictExceptions`エラーが発生しない

詳しくは[こちら](https://docs.aws.amazon.com/ja_jp/amazondynamodb/latest/developerguide/DynamoDBLocal.UsageNotes.html#DynamoDBLocal.Differences)にまとまっているので、一度目を通しておくと良いでしょう。


# GUIツール
DynamoDB localによりアプリの開発やテストのほとんどをローカル環境で行えるようになりますが、テーブルやデータをGUIで確認・操作できるとよりスムーズに開発・テストを進められます。
ここではDynamoDB localに使えるGUIツールを2つ紹介します。

## NoSQL Workbench
[NoSQL Workbench](https://docs.aws.amazon.com/ja_jp/amazondynamodb/latest/developerguide/workbench.html)はAWSによって提供されているDynamoDB用のGUIアプリケーションです。

ダウンロード・インストール方法については次のドキュメントに記載されています。

- [DynamoDB 用の NoSQL Workbench のダウンロード - Amazon DynamoDB](https://docs.aws.amazon.com/ja_jp/amazondynamodb/latest/developerguide/workbench.settingup.html)
- [DynamoDB 用の NoSQL Workbench のインストール - Amazon DynamoDB](https://docs.aws.amazon.com/ja_jp/amazondynamodb/latest/developerguide/workbench.settingup.install.html)

### NoSQL Workbenchの画面の例

テーブル作成
![スクリーンショット 2024-03-27 18.27.22.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/777885/cc885626-04d5-777b-6737-502b519de690.png)

テーブル一覧(左)・データ一覧・検索
![スクリーンショット 2024-03-27 18.31.57.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/777885/cc25de85-4524-c460-02ee-c51ecfc3a975.png)

データ編集
![スクリーンショット 2024-03-27 18.44.01.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/777885/0171c367-3690-aae9-5b3f-0d6280a4d64e.png)


## dynamodb-admin
### Node.jsのパッケージを使って起動する
[dynamodb-admin](https://github.com/aaronshaf/dynamodb-admin)はNode.jsのパッケージとしてインストールして使用できます。
以下は[dynamodb-admin/README.md](https://github.com/aaronshaf/dynamodb-admin/blob/master/README.md)に載っている使用方法です。
```shell
npm install -g dynamodb-admin

# For Windows:
set DYNAMO_ENDPOINT=http://localhost:8000
dynamodb-admin

# For Mac/Linux:
DYNAMO_ENDPOINT=http://localhost:8000 dynamodb-admin
```

[http://localhost:8001/](http://localhost:8001/) から管理画面にアクセスできます。

### Dockerイメージを使って起動する

dynamodb-adminはDockerイメージとしても提供されているので、こちらを利用するのも良いでしょう。
[aaronshaf/dynamodb-admin - Docker Image | Docker Hub](https://hub.docker.com/r/aaronshaf/dynamodb-admin/)

`docker-compose.yml`に次のように追加することでdynamodb-adminのDockerコンテナを用意できます。

```yaml:docker-compose.yml
version: '3.8'
services:
  dynamodb-local:
    # ...

  dynamodb-admin:
    image: "aaronshaf/dynamodb-admin:latest"
    container_name: dynamodb-admin
    environment:
      - DYNAMO_ENDPOINT=dynamodb-local:8000
    ports:
      - "8001:8001"
    depends_on:
      - dynamodb-local
```

`docker compose up -d`でコンテナを立ち上げた後、 [http://localhost:8001/](http://localhost:8001/) を開くと管理画面が表示されます。

### dynamodb-adminの画面の例

テーブル作成
![スクリーンショット 2024-03-26 22.44.28.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/777885/b39c2145-bfd7-11ce-b85c-7b1e50effef0.png)

テーブル一覧
![スクリーンショット 2024-03-26 22.59.12.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/777885/fd5902ec-e7c6-ccb1-6b1a-34ca51088bf1.png)

データ一覧・検索
![スクリーンショット 2024-03-26 22.53.38.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/777885/dda173f2-5a27-68b3-4a6f-31e30e58bd17.png)

データ編集
![スクリーンショット 2024-03-27 21.49.39.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/777885/eeb6487e-63ab-da8b-f1ab-5c34b4f17be4.png)


# コンテナ生成時にテーブル・データ作成
コンテナを生成する際にテーブルや初期データを作成しておけば、開発やテストをよりスムーズに進められます。
ここではコンテナ生成時にテーブルや初期データを作成しておくための方法を2つ紹介します。

## AWS CLIコンテナでシェルスクリプトを実行する
まずは必要なAWS CLIコマンドを1つのファイルにまとめておきます。

```shell:init-dynamodb-local.sh
#!/bin/sh

# テーブル作成
aws dynamodb create-table --table-name user \
  --region ap-northeast-1 \
  --endpoint-url http://dynamodb-local:8000 \
  --attribute-definitions AttributeName=uuid,AttributeType=S \
  --key-schema AttributeName=uuid,KeyType=HASH \
  --provisioned-throughput ReadCapacityUnits=5,WriteCapacityUnits=5 \
  --no-cli-pager;

# データ追加
aws dynamodb put-item --table-name user \
  --region ap-northeast-1 \
  --endpoint-url http://dynamodb-local:8000 \
  --no-cli-pager \
  --item '
    {
      "uuid": {"S": "f9f72546-b5b4-8f11-1aaa-71albb80a56e"},
      "name": {"S": "山田太郎"}
    }
  ';
```
`--no-cli-pager`はコマンド出力のページャーを無効化するために加えてあります。
このオプション指定がない場合、コマンド実行時の出力表示に対して`q`を入力しないと次のコマンドが実行されない状態になってしまいます。

ファイルが準備できたら、それをAWS CLIコンテナで実行できるよう`docker-compose.yml`に追記してコンテナを立ち上げます。

```yaml:docker-compose.yml
version: '3.8'
services:
  dynamodb-local:
    # ...

  aws-cli:
    command: >
      /bin/sh -c './init-dynamodb-local.sh; /bin/sh'
    image: amazon/aws-cli:latest
    container_name: aws-cli
    environment:
      - AWS_ACCESS_KEY_ID=dummy
      - AWS_SECRET_ACCESS_KEY=dummy
    ports:
      - "8080:8080"
    volumes:
      - "./:/workdir/"
    working_dir: /workdir
    entrypoint: ['']
    tty: true
    depends_on:
      - dynamodb-local
```

## Terraformを使用する
[Terraform](https://www.terraform.io/)を使ってテーブルやデータを作成しておくこともできます。

まずはtfファイルを準備しましょう。
例では簡単のため`main.tf`に必要な記述を全てまとめてしまいます。
```terraform:main.tf
provider "aws" {
  region                      = "ap-northeast-1"
  skip_credentials_validation = true
  skip_requesting_account_id  = true
  endpoints {
    dynamodb = "http://dynamodb-local:8000"
  }
}

# テーブル作成
resource "aws_dynamodb_table" "sample_table" {
  name           = "user"
  billing_mode   = "PROVISIONED"
  read_capacity  = 5
  write_capacity = 5
  hash_key       = "uuid"

  attribute {
    name = "uuid"
    type = "S"
  }
}

# データ追加
resource "aws_dynamodb_table_item" "sample_data" {
  table_name = aws_dynamodb_table.sample_table.name
  hash_key   = aws_dynamodb_table.sample_table.hash_key
  item = <<ITEM
{
  "uuid": {"S": "f9f72546-b5b4-8f11-1aaa-71albb80a56e"},
  "name": {"S": "山田太郎"}
}
ITEM
}
```
providerで`skip_credentials_validation`や`skip_requesting_account_id`をtrueに設定しておくことで、認証情報の検証やアカウントIDの確認をスキップします。
またここでも`endpoints`としてエンドポイントURLの指定が必要になります。

tfファイルを準備できたら、`docker-compose.yml`にTerraform実行用のコンテナを追加して立ち上げます。

```yaml:docker-compose.yml
version: '3.8'
services:
  dynamodb-local:
    # ...

  terraform:
    command: >
      /bin/sh -c 'terraform init && terraform apply -auto-approve; /bin/sh'
    image: hashicorp/terraform:latest
    container_name: terraform
    environment:
      - AWS_ACCESS_KEY_ID=dummy
      - AWS_SECRET_ACCESS_KEY=dummy
    volumes:
      - "./:/workdir/"
    working_dir: /workdir
    entrypoint: ['']
    tty: true
    depends_on:
      - dynamodb-local
```

# おわりに
ここまでDynamoDB localの導入方法や、DynamoDB localを利用しやすくするための関連ツールを紹介してきました。
これらのツールを組み合わせながら、より開発のしやすいローカル環境を構築してみてください。

# 参考・関連ページ
- [コンピュータ上で DynamoDB をローカルでデプロイする - Amazon DynamoDB](https://docs.aws.amazon.com/ja_jp/amazondynamodb/latest/developerguide/DynamoDBLocal.DownloadingAndRunning.html)
- [DynamoDB local の使用に関する注意事項 - Amazon DynamoDB](https://docs.aws.amazon.com/ja_jp/amazondynamodb/latest/developerguide/DynamoDBLocal.UsageNotes.html)
- [DynamoDB 用の NoSQL Workbench - Amazon DynamoDB](https://docs.aws.amazon.com/ja_jp/amazondynamodb/latest/developerguide/workbench.html)
- [aaronshaf/dynamodb-admin: GUI for DynamoDB Local or dynalite](https://github.com/aaronshaf/dynamodb-admin)
- [【DynamoDB Local】快適なDynamoDBのローカル開発環境を構築する – Hacker's High](https://hackers-high.com/aws/dynamodb-local-development/)
- [Docs overview | hashicorp/aws | Terraform | Terraform Registry](https://registry.terraform.io/providers/hashicorp/aws/latest/docs)
- [Terraform AWS Provider Custom Service Endpoint Configuration | Guides | hashicorp/aws | Terraform | Terraform Registry](https://registry.terraform.io/providers/hashicorp/aws/latest/docs/guides/custom-service-endpoints)