【DynamoDB】【Docker】docker-composeでDynamoDBとDjangoの開発環境を構築する

# docker-composeでDynamoDBとDjangoの開発環境を構築する
## はじめに
DynamoDBって安くて早くていいですよね。そんなDynamoDBをローカルで開発するためのDockerImageがあるってご存知ですか？そんなDockerImageを利用した開発環境構築の一例を照会します。

## 環境
プロダクション環境に即して利用するイメージのバージョンは以下です。
DynamoDBのGUI操作用に[dynamodb-admin](https://github.com/aaronshaf/dynamodb-admin)を利用します。Nodeはその環境を一緒に構築する際に利用します。

|環境|バージョン|
| --- | --- |
Python|3.7.4
MySQL|5.7
Node|10.16.3-alpine



## 環境構築
### DjangoとMySQL
完全にゼロから構築するのでまずはDjangoプロジェクトを開始します。
公式のDjangoイメージはバージョンが古いので自分で作ります。

```shell
$ django-admin startproject dynamodb_example
$ cd dynamodb_example/
$ touch docker-compose.yml
$ touch Dockerfile
```

```Dockerfile
FROM python:3.7.4

RUN apt-get update
RUN apt-get install -y --no-install-recommends apt-utils gettext
RUN mkdir /app; mkdir /app/dynamodb_example

WORKDIR /app
COPY dynamodb_example /app/dynamodb_example
COPY requirements.txt /app/
COPY manage.py /app/

RUN pip install -r requirements.txt

EXPOSE 8080
CMD ["python", "manage.py", "runserver", "0.0.0.0:8080"]
```

```docker-compose.yml
version: "3"
services:
  mysql:
    container_name: example-mysql
    ports:
      - 53306:3306
    image: mysql:5.7
    command: mysqld --character-set-server=utf8mb4 --collation-server=utf8mb4_unicode_ci
    volumes:
      - ./persist/mysql:/var/lib/mysql
    restart: always
    environment:
      MYSQL_USER: example
      MYSQL_PASSWORD: example
      MYSQL_DATABASE: example
      MYSQL_ROOT_PASSWORD: example

  django:
    container_name: example-django
    build: .
    volumes:
      - .:/app
    working_dir: /app
    command: sh -c "./wait-for-it.sh db:3306; python3 manage.py runserver 0.0.0.0:8000"
    env_file: .env
    ports:
      - 58080:8000
    depends_on:
      - mysql
```

ポートが50000台なのは絶対被りたくないからです。とくに意味はありません。
DynamoDBと接続するためのライブラリは**boto3**とそれをWrapしている**pynamodb**を入れておきます。

```requirements.txt
boto3
pynamodb
Django==2.2.4
djangorestframework==3.10.3
django-filter
mysqlclient==1.3.13
```

環境変数の意味をあまりなしていないですが一応…

```.env
DB_ENGINE=django.db.backends.mysql
DB_HOST=mysql
DB_DATABASE=example
DB_USERNAME=root
DB_PASSWORD=example
DB_PORT=3306
```
とりあえずDjangoとMySQLの疎通を確認したいのでDjangoのDATABASESを書き換えます。

```setting.py
DATABASES = {
    'default': {
        'ENGINE': os.getenv('DB_ENGINE'),
        'NAME': os.getenv('DB_DATABASE'),
        'USER': os.getenv('DB_USERNAME'),
        'PASSWORD': os.getenv('DB_PASSWORD'),
        'HOST': os.getenv('DB_HOST'),
        'OPTIONS': {
            'init_command': 'SET foreign_key_checks = 0;',
            'charset': 'utf8mb4',
        },
    }
}
```

ここまで来たらとりあえず起動するか確認します。

```shell
$ docker-compose up -d
$ docker-compose exec django bash
$ python manage.py migrate
```

問題なければ、次に**DynamoDB Local**と**dynamodb-admin**を入れてきます。

### DynamoDB Local
docker-compose.ymlにdynamodbを記載します。
永続化ようにコマンドの最後にdbPathを指定します。

```docker-compose.yml
  dynamodb:
    container_name: example-dynamodb
    image: amazon/dynamodb-local
    command: -jar DynamoDBLocal.jar -dbPath /home/dynamodblocal/data
    volumes:
      - ./persist/dynamodb:/home/dynamodblocal/data
    ports:
      - 50706:8000
```

### dynamodb-admin
公式イメージがあったのですが、作ってしまったのでそちらを利用します。

```shell
$ mkdir dynamodb-admin
$ touch dynamodb-admin/Dockerfile
$ touch dynamodb-admin/.env
```

```dynamodb-admin/Dockerfile
FROM node:10.16.3-alpine

RUN ["apk", "update"]
RUN ["npm", "install", "dynamodb-admin", "-g"]

EXPOSE 50727
CMD ["dynamodb-admin", "-p", "50727"]
```
環境変数の`DYNAMO_ENDPOINT`にはdynamodbのコンテナーサービス名とコンテナ側のポートを指定します。

```.env
DYNAMO_ENDPOINT=http://dynamodb:8000
AWS_REGION=ap-northeast-1
AWS_ACCESS_KEY_ID=ACCESS_ID
AWS_SECRET_ACCESS_KEY=ACCESS_KEY
```

このdyanamodb-adminを加えた最終的なdocker-compose.ymlファイルは以下のようになります。

```docker-compose.yml
version: "3"
services:
  dynamodb:
    container_name: example-dynamodb
    image: amazon/dynamodb-local
    command: -jar DynamoDBLocal.jar -dbPath /home/dynamodblocal/data
    volumes:
      - ./persist/dynamodb:/home/dynamodblocal/data
    ports:
      - 50706:8000
  dynamodb-admin:
    container_name: example-dynamodb-admin
    build: dynamodb-admin/
    command: dynamodb-admin -p 8000
    env_file: dynamodb-admin/.env
    ports:
      - 50727:8000
    depends_on:
      - dynamodb
  mysql:
    container_name: example-mysql
    ports:
      - 53306:3306
    image: mysql:5.7
    command: mysqld --character-set-server=utf8mb4 --collation-server=utf8mb4_unicode_ci
    volumes:
      - ./persist/mysql:/var/lib/mysql
    restart: always
    environment:
      MYSQL_USER: example
      MYSQL_PASSWORD: example
      MYSQL_DATABASE: example
      MYSQL_ROOT_PASSWORD: example
  django:
    container_name: example-django
    build: .
    volumes:
      - .:/app
    working_dir: /app
    command: sh -c "./wait-for-it.sh db:3306; python3 manage.py runserver 0.0.0.0:8000"
    env_file: .env
    ports:
      - 58080:8000
    depends_on:
      - mysql
      - dynamodb
```

[http://localhost:50727](http://localhost:50727)をブラウザで表示して以下のように表示されていれば成功です。
<img width="1440" alt="スクリーンショット 2019-09-29 23.11.48.png" src="https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/235240/2d30bb09-2dd5-10ec-cf3f-e46d89da1ac4.png">
Create Table等したい放題です。

## 永続化の確認
適当にテーブルを作ってみます。
<img width="1440" alt="スクリーンショット 2019-09-29 23.18.51.png" src="https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/235240/d43230de-6525-3da5-022b-5c423f329a3f.png">
作成されました。
<img width="1143" alt="スクリーンショット 2019-09-29 23.19.02.png" src="https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/235240/819ed312-83a5-6778-cf52-e45ea8fde64b.png">



コンテナーを削除して再起動します。

``` shell
$ docker-compose down
$ docker-compose up -d
```
[http://localhost:50727](http://localhost:50727)を開いて先程のテーブルが残っていれば永続化もうまく行っています。

## 最後に
このリポジトリーは以下で公開します。今後更新するかもしれないのでtagは**1.0.0**です。
[https://github.com/Cohey0727/example_dynamodb](https://github.com/Cohey0727/example_dynamodb)
もしよければ利用してください。