MySQL + DynamoDB の docker-compose 環境を作成しました
背景
Cykinso の 研究&データ技術開発 の山﨑です。
MySQL と DynamoDB を同時に利用する環境を構築するプロダクトの開発を行いました。
各人が開発環境を構築すると大変なのでチームで共有して利用するように docker-compose.yml
にまとめて VS Code の devcontainer
で起動できるようにしました。
MySQL, DynamoDB 単独でまとめている記事はあったのですが両方同時に利用している例はなかったので他の方の助けになるかと思いますのでまとめておきます。
方法
Frontend: Next.js
Backend: Nest.js
プログラミング言語: TypeScript
と、今回は環境を決定し、以下の docker-compose.yml
を作成しました。
version: "3.9"
services:
app:
container_name: project-app
build: .
ports:
- "3000:3000"
- "8000:8000"
- "6006:6006"
depends_on:
- mysql
- dynamodb
networks:
- mysql-network
- dynamodb-network
command: /bin/sh -c "while true; do sleep 3600; done" # keep container running
mysql:
container_name: project-mysql
image: mysql:8.1.0
restart: unless-stopped
ports:
- "3306:3306"
environment:
MYSQL_ROOT_PASSWORD: mysql
MYSQL_DATABASE: db
MYSQL_USER: user
MYSQL_PASSWORD: password
TZ: "Asia/Tokyo"
networks:
- mysql-network
dynamodb:
container_name: project-dynamodb
image: amazon/dynamodb-local:2.0.0
restart: unless-stopped
ports:
- "8010:8000"
volumes:
- ./dynamodb_data/:/data
networks:
- dynamodb-network
command: ["-jar", "DynamoDBLocal.jar", "-sharedDb", "-dbPath", "/data"]
dynamodb-admin:
container_name: project-dynamodb-admin
image: aaronshaf/dynamodb-admin:4.6.1
environment:
- DYNAMO_ENDPOINT=http://dynamodb:8000
ports:
- 8001:8001
depends_on:
- dynamodb
networks:
- dynamodb-network
networks:
mysql-network:
driver: bridge
dynamodb-network:
driver: bridge
各サービスの説明をしていきます。
app
app
は devcontainer
を起動した時に利用するコンテナを想定しています。
Next.js で 3000, Nest.js で 8000, Next.js で利用する Storybook で 6006 のポートを利用するためにポートを開けておきます。
depends_on
に後述のサービス mysql
, dynamodb
を指定します。 networks
にこちらも後述のサービス mysql
, dynamodb
に接続するため mysql-network
, dynamodb-network
を指定します。これにより devcontainer
の中から接続することができるようになります。
docker-compose
(docker
全般?) は command
として例えばサーバを起動するなどのことを行わないと勝手に container が閉じてしまいます。これでは devcontainer
として利用ができなくなるので、 command
として 60 分間 sleep するということを永遠に繰り返すようにしています。
app:
container_name: project-app
build: .
ports:
- "3000:3000"
- "8000:8000"
- "6006:6006"
depends_on:
- mysql
- dynamodb
networks:
- mysql-network
- dynamodb-network
- project_fixed_address_network
command: /bin/sh -c "while true; do sleep 3600; done" # keep container running
build
で参照している dockerfile
は以下のようになっており TypeScript を利用するために必要なソフトウェアなどをインストールしています。あと珍しいのは dood を行うために docker
をインストールしている点と最後の COPY . .
でしょうか?
app
を利用する時に devcontainer
側の mount
がうまくワークしなかったためこちらで COPY
を行うようにしています。
dood を行う必要がなければもちろん docker はインストールしなくてかまいません。
# Use the official Node.js image as a parent image
FROM node:20-bookworm-slim
# Install dependencies
RUN apt-get update && apt-get install -y --no-install-recommends \
curl=7.88.1-10+deb12u4 \
git=1:2.39.2-1.1 \
ssh=1:9.2p1-2+deb12u1 \
tree=2.1.0-1 \
zsh=5.9-4+b2 \
default-mysql-client=1.1.0 \
awscli=2.9.19-1 \
less=590-2 \
ca-certificates=20230311 \
gnupg=2.2.40-1.1 \
lsb-release=12.0-1 \
make=4.3-4.1 \
&& apt-get clean \
&& rm -rf /var/lib/apt/lists/*
# Install npm packages in global
RUN npm i -g \
prettier@3.0.0 \
@nestjs/cli@10.0.0 \
dotenv-cli@7.3.0 \
aws-cdk@2.114.1 \
eslint@8.55.0
# Install docker
SHELL ["/bin/bash", "-o", "pipefail", "-c"]
RUN curl -fsSL https://download.docker.com/linux/debian/gpg | gpg --dearmor -o /usr/share/keyrings/docker-archive-keyring.gpg \
&& echo \
"deb [arch=$(dpkg --print-architecture) signed-by=/usr/share/keyrings/docker-archive-keyring.gpg] https://download.docker.com/linux/debian \
$(lsb_release -cs) stable" | tee /etc/apt/sources.list.d/docker.list > /dev/null \
&& apt-get update \
&& apt-get install -y --no-install-recommends \
docker-ce=5:24.0.7-1~debian.12~bookworm \
docker-ce-cli=5:24.0.7-1~debian.12~bookworm \
containerd.io=1.6.26-1 \
&& apt-get clean \
&& rm -rf /var/lib/apt/lists/*
# Set the working directory in the container
WORKDIR /app
# Copy the rest of the application to the working directory
COPY . .
mysql
mysql 公式の docker image や公式の dockerhub で紹介されている environment を用いて以下のようにログイン時のパスワードなどを設定しています。
mysql:
container_name: project-mysql
image: mysql:8.1.0
restart: unless-stopped
ports:
- "3306:3306"
environment:
MYSQL_ROOT_PASSWORD: mysql
MYSQL_DATABASE: db
MYSQL_USER: user
MYSQL_PASSWORD: password
TZ: "Asia/Tokyo"
networks:
- mysql-network
これにより
mysql -h mysql -u root -pmysql db
と devcontainer
からログインできるようになります。 -h mysql
で接続できるのは networks
で設定しているからです。
今回ローカル PC で開発のために利用する前提なので簡素なパスワードにしていますが、もちろん本番環境ではより堅牢なパスワードにしてくださいね。
dynamoDB
続けて dynamoDB 側です。
dynamoDB は AWS から dynamodb-local というローカルで開発する時に利用するための docker image が配布されておりこれを利用することでローカルで DynamoDB の環境を構築することができます。
dynamodb のデフォルトポートは 8000 なのですが 私の環境ではポート 8000 は Nest.js で利用しているので 8010:8000
としてホスト PC からは 8010
で接続するようにしました (Nest.js 側を 8000 にしなければよかったとちょっと後悔しています)
dynamodb:
container_name: project-dynamodb
image: amazon/dynamodb-local:2.0.0
restart: unless-stopped
ports:
- "8010:8000"
volumes:
- ./dynamodb_data/:/data
networks:
- dynamodb-network
command: ["-jar", "DynamoDBLocal.jar", "-sharedDb", "-dbPath", "/data"]
以上の設定により devcontainer
から aws cli で接続をすることができます。
ただし、 dynamodb-local を利用する場合はダミーの AWS_ACCESS_KEY_ID
, AWS_SECRET_ACCESS_KEY
, AWS_REGION
(または AWS_DEFAULT_REGION
) をアサインする必要があるので注意してください。
(これは Nest.js などから接続する時もです)
unset AWS_PROFILE # AWS_PROFILE が設定されている場合そちらが優先されワークしないことがあります
export AWS_ACCESS_KEY_ID="AAAAAAAAAA"
export AWS_SECRET_ACCESS_KEY="BBBBBBBBBB"
export AWS_REGION="CCCCCCCCCC"
特に、間違って AWS_REGION=ap-north-east1
などがアサインされていると aws cli でそちらのリージョンに新規テーブルなどを作成してしまうので注意してください。
設定ができたら aws cli で例えば以下のように接続します。
aws dynamodb list-tables --endpoint-url http://dynamodb:8000
dynamodb-admin
dynamodb-local のデータをホスト PC からブラウザでデータを確認するためのサービス dynamodb-admin というものがありがたいことに有志の方によって開発されています。
(こちらを利用しているので実は前述の aws cli で接続しデータの確認などをすることはあまりありません)
dynamodb-admin:
container_name: project-dynamodb-admin
image: aaronshaf/dynamodb-admin:4.6.1
environment:
- DYNAMO_ENDPOINT=http://dynamodb:8000
ports:
- 8001:8001
depends_on:
- dynamodb
networks:
- dynamodb-network
サービスを起動するとブラウザの URL に http://localhost:8001 と入力することで以下のようなサイトを表示することができます。
(http://dynamodb:8000 ではないです。こちらは devcontaienr
からアクセスする時の URL です)
AWS の公式とは見た目は異なりますが無料で利用できるのなら十分だと思います。
networks
最後に service 同士を連携させるために networks を設定しています。
networks:
mysql-network:
driver: bridge
dynamodb-network:
driver: bridge
以上で docker-compose.yml の説明は終わります。
devcontainer.json
ディレクトリ構成は以下のようになってるものとして話を進めます。
> tree -La 2
.
├── .devcontainer
│ ├── devcontainer-template.json
│ └── devcontainer.json
├── Dockerfile
└── docker-compose.yml
devcontainer.json
では以下のように docker-compose.yml
とそのサービス app
を指定してください。
{
"name": "${localWorkspaceFolderBasename}",
"dockerComposeFile": ["../docker-compose.yml"],
"service": "app",
"workspaceFolder": "/workspace/${localWorkspaceFolderBasename}",
// skipping...
"mounts": [ "source=/Users/yamasakih/repositories/${localWorkspaceFolderBasename},target=/workspace/${localWorkspaceFolderBasename},type=bind,consistency=delegated",
"source=/var/run/docker.sock,target=/var/run/docker.sock,type=bind,consistency=delegated" # dood にしたいなら必要です。
]
}
mounts
では、マウントするディレクトリをリポジトリの直下を指定し書き換えてください。 例えばディレクトリ構成が /Users/yamasakih/dev/xxxxx
であるなら /Users/yamasakih/dev/${localWorkspaceFolderBasename}
に書き換えてください。
(${localWorkspaceFolderBasenam} = "xxxxx" になっているイメージです)
以上まで用意し VSCode で devcontainer
を起動すると app
サービスのコンテナ内に入っている状態で VSCode を利用することができます。
もちろん MySQL, DynamoDB に devcontainer
から接続できます。
💡 まとめ
- MySQL と DynamoDB を同時にローカルで利用できるようにしました
- devcontainer を利用してチームで簡単に環境を共有できるようにしました
Discussion