DynamoDBローカルをDockerコンテナとして動かす

## 1.概要
DynamoDBに、開発・テスト用途のDynamoDBローカルと呼ばれるものがあります。これはDynamoDBをローカルマシンのアプリケーションとして稼働させ、各種SDKにて接続・テーブル操作を実装できます。
DynamoDBローカルは、公式でJavaアプリケーションとして配布されていますが、Dockerイメージでも配布されているので、このイメージを使ってDockerコンテナとしてDynamoDBローカルを稼働させたいと思います。

ポイントはAWSアカウントを登録・所有していなくてもDynamoDBを使ったアプリケーションを開発できるということだと思います。Lambda/api gatewayも[AWS SAM Local](https://aws.amazon.com/jp/blogs/news/new-aws-sam-local-beta-build-and-test-serverless-applications-locally/)で開発・テスト可能になっているので、色々試しやすくなっているのかなと。

参考：主に本番環境で利用するDynamoDBはAmazon DynamoDB(ウェブサービス)という位置付けで表記されており、今回利用するものはDynamoDBローカル(ダウンロード可能バージョン)と表記されています。詳細は[DynamoDBのセットアップ](https://docs.aws.amazon.com/ja_jp/amazondynamodb/latest/developerguide/SettingUp.html)を参考。


## 2. DynamoDB Localコンテナの起動

Dockerレジストリからdynamodb-localイメージを入手してコンテナを起動します。事前にホストへDockerをインストールしておきます。

```
docker pull amazon/dynamodb-local
docker run -d --name dynamodb -p 8000:8000 amazon/dynamodb-local
```

## 3. DynamoDBローカルへの操作
各種SDKから接続するか、DynamoDB JavaScript ShellからDynamoDBを操作できるようになります。

DynamoDB JavaScript Shellは、以下URLにアクセスしてJavaScriptにてDynamoDBの操作を行います。
　http://localhost:8000/shell/
(コンテナを動かすホストとWebブラウザが異なる環境の場合、localhostではなくdockerのホストを指定。)



### DynamoDBへの接続
[AWS.config](https://docs.aws.amazon.com/AWSJavaScriptSDK/latest/AWS/Config.html#constructor-property)
[ローカルエンドポイントの設定](https://docs.aws.amazon.com/ja_jp/amazondynamodb/latest/developerguide/DynamoDBLocal.Endpoint.html
)

```javascript

const AWS = require('aws-sdk')
const config = {
  endpoint: 'http://localhost:8000',
  region: 'us-west-2',
  accessKeyId: 'fakeMyKeyId',
  secretAccessKey: 'fakeSecretAccessKey'
}
AWS.config.update(config)
const dynamodb = new AWS.DynamoDB()

let tableName = 'TestTable'
let params = {}
```

DynamoDBに接続する場合にはエンドポイントだけでなく、ダミーの認証情報が必要です。[こちら](https://docs.aws.amazon.com/ja_jp/amazondynamodb/latest/developerguide/DynamoDBLocal.html)を参照。

(!要確認)
~~デフォルトでデータはメモリのみ維持となり同一セッション内でのみアクセス可能の模様。別セッションから接続する場合は不可視、切断するとメモリから消失？すべてのクライアントから共有する場合、コンテナ内のアプリをsharedDbオプションで起動する必要があるようですが確認中~~
[こちら](https://qiita.com/tamo_breaker/items/f86c9b5fc6991813e3ca)に記載しました(2018/11/28)。



###テーブルの作成
[createTable](https://docs.aws.amazon.com/AWSJavaScriptSDK/latest/AWS/DynamoDB.html#createTable-property)
[テーブルの作成](https://docs.aws.amazon.com/ja_jp/amazondynamodb/latest/developerguide/WorkingWithTables.Basics.html#WorkingWithTables.Basics.CreateTable)

```javascript

params = {
  AttributeDefinitions: [
    {
      AttributeName: 'Id',
      AttributeType: 'S'
    },
    {
      AttributeName: 'Numbers',
      AttributeType: 'N'
    }
  ],
  KeySchema: [
    {
      AttributeName: 'Id',
      KeyType: 'HASH'
    },
    {
      AttributeName: 'Numbers',
      KeyType: 'RANGE'
    }
  ],
  ProvisionedThroughput: {
    ReadCapacityUnits: 1,
    WriteCapacityUnits: 1
  },
  TableName: tableName
}

dynamodb.createTable(params, (err, data) => {
  if (err) console.log(err, err.stack)
  else console.log(data)
})
```

DynamoDBローカルではプロビジョニングされたスループットの設定は無視されます。
またARNは、"arn:aws:dynamodb:ddblocal:000000000000:table/テーブル名"となるようです。

### テーブル一覧の表示

[listTables](https://docs.aws.amazon.com/AWSJavaScriptSDK/latest/AWS/DynamoDB.html#listTables-property)
[テーブル名のリスト化](https://docs.aws.amazon.com/ja_jp/amazondynamodb/latest/developerguide/WorkingWithTables.Basics.html#WorkingWithTables.Basics.ListTables)

```javascript

dynamodb.listTables({}, (err, data) => {
  if (err) console.log(err, err.stack)
  else console.log(data)
})
```

### テーブル定義の表示

[describeTable](https://docs.aws.amazon.com/AWSJavaScriptSDK/latest/AWS/DynamoDB.html#describeTable-property)
[テーブルの説明](https://docs.aws.amazon.com/ja_jp/amazondynamodb/latest/developerguide/WorkingWithTables.Basics.html#WorkingWithTables.Basics.DescribeTable)

```javascript

dynamodb.describeTable({ TableName: tableName }, (err, data) => {
  if (err) console.log(err, err.stack)
  else console.log(data)
})
```

### テーブルへの項目格納

[putItem](https://docs.aws.amazon.com/AWSJavaScriptSDK/latest/AWS/DynamoDB.html#putItem-property)
[項目を書き込む](https://docs.aws.amazon.com/ja_jp/amazondynamodb/latest/developerguide/WorkingWithItems.html#WorkingWithItems.WritingData)

```javascript

params = {
  TableName: tableName,
  Item: {
    'Id': { S: 'id1' },
    'Numbers': { N: '3' }
  }
}
dynamodb.putItem(params, (err, data) => {
  if (err) console.log(err, err.stack)
  else console.log(data)
})
```

### テーブルから項目取得

[getItem](https://docs.aws.amazon.com/AWSJavaScriptSDK/latest/AWS/DynamoDB.html#getItem-property)
[項目を読み込む](https://docs.aws.amazon.com/ja_jp/amazondynamodb/latest/developerguide/WorkingWithItems.html#WorkingWithItems.ReadingData)

```javascript

params = {
  Key: {
    'Id': { S: 'id1' },
    'Numbers': { N: '3' }
  },
  TableName: tableName
}
dynamodb.getItem(params, (err, data) => {
  if (err) console.log(err)
  else console.log(data)
})
```


### テーブルのスキャン
[scan](https://docs.aws.amazon.com/AWSJavaScriptSDK/latest/AWS/DynamoDB.html#scan-property)
[スキャンの使用](https://docs.aws.amazon.com/ja_jp/amazondynamodb/latest/developerguide/Scan.html)

```javascript

params = {
  ExpressionAttributeValues: {
    ':val': {
      N: '2'
    }
  },
  FilterExpression: 'Numbers > :val',
  TableName: tableName
}

dynamodb.scan(params, (err, data) => {
  if (err) console.log(err, err.stack)
  else console.log(data)
})
```

scanの他にqueryもありますが、こちらはプライマリキーによる項目取得となります。
[クエリの操作](https://docs.aws.amazon.com/ja_jp/amazondynamodb/latest/developerguide/Query.html)

## 4.そのほか
Dockerは[CentOS 用 Docker CE の入手](http://docs.docker.jp/engine/installation/linux/docker-ce/centos.html#docker-ce)などを参照。

AWS CLIは[AWS Command Line Interface のインストール](https://docs.aws.amazon.com/ja_jp/cli/latest/userguide/installing.html)を参照。
AWS CLIよりDynamoDBローカルのテーブルを参照できます。ただエンドポイントはローカルエンドポイントを指定します。

```
aws dynamodb list-tables --endpoint-url http://localhost:8000
```


今回はDockerコンテナを利用しましたが、アプリケーションとして実行する場合には[DynamoDB ローカル (ダウンロード可能バージョン) のセットアップ](https://docs.aws.amazon.com/ja_jp/amazondynamodb/latest/developerguide/DynamoDBLocal.html)を参照。
DynamoDB(Webサービス)とDynamoDBローカルの違いは[こちら](https://hub.docker.com/r/amazon/dynamodb-local/)を参照。

AWS SAM Localを試せば、ローカルな環境でAWSをターゲットとしたバックエンドなウェブアプリは作れそうですね。
[AWS SAM Local](https://aws.amazon.com/jp/blogs/news/new-aws-sam-local-beta-build-and-test-serverless-applications-locally/)
[SAM CLI を使用してサーバーレスアプリケーションをローカルでテストする](https://docs.aws.amazon.com/ja_jp/lambda/latest/dg/test-sam-cli.html)
[aws-sam-cli](https://github.com/awslabs/aws-sam-cli/blob/develop/docs/usage.rst)

そのほかS3ローカルなものもあるようなので、環境準備さえすればバシバシ開発ができそうですね。
[serverless-s3-local](https://www.npmjs.com/package/serverless-s3-local)
(CephでもS3仕様のREST APIはありましたが構築が大変な上、ブロックストレージやオブジェクトストレージが主の目的ですし今回のような開発・テスト用途の利用としてはオーバースペックかなと）



## 5.参考情報
[amazon/dynamodb-local](https://hub.docker.com/r/amazon/dynamodb-local/)
[Class: AWS.DynamoDB](https://docs.aws.amazon.com/AWSJavaScriptSDK/latest/AWS/DynamoDB.html)
[JavaScript と DynamoDB](https://docs.aws.amazon.com/ja_jp/amazondynamodb/latest/developerguide/GettingStarted.JavaScript.html)