データ入りの DynamoDB Local Docker イメージを作る
データソースとして DynamoDB を使う場合、開発中は DynamoDB Local を使うことが多いのではないでしょうか。初期データの入った DynamoDB Local の Docker イメージをチームで共有したかったので、Docker の muilti-stage build でイメージを作ったという話です。
DynamoDB Local について
DynamoDB Local は、AWS が開発やテストの用途向けに提供している Amazon DynamoDB のローカル版です。Java で作られており、jar ファイルまたは Docker イメージの形で配布されています。
以下のような感じで起動して使用できます。
$ docker run --rm -p 8000:8000 amazon/dynamodb-local:latest ✘ 125 sc-48497-add-operation-id-to-material-stock-closing
Initializing DynamoDB Local with the following configuration:
Port: 8000
InMemory: true
DbPath: null
SharedDb: false
shouldDelayTransientStatuses: false
CorsParams: *
起動の際にいくつかのオプションが指定できますが、データ入りのイメージを作るにあたっては以下のオプションが関係します。
-dbPath (-inMemory)
DynamoDB Local の Docker イメージは、デフォルトでは -inMemory
オプションがついた状態で DynamoDB Local が起動します。 この場合、テーブルやアイテムが作成されてもファイルに永続化されず、Dynamo DB Local を終了すると全てのデータが消失します。
-dbPath
オプションでデータベースファイルの場所を指定すると、データベースファイルに永続化され、DynamoDB Local を終了してもデータが保持されるようになります。今回はこのオプションを使って初期データを DynamoDB Local にロードさせます。
-sharedDb
クライアントが DynamoDB に接続する際、AWS アクセスキーと AWS リージョンを指定して接続します。DynamoDB Local は、デフォルトではクライアントの AWS アクセスキー ID と AWS リージョンごとに異なるデータを提供する動きになります。つまり、ある AWS アクセスキー ID で接続したクライアントの作ったデータが、他の AWS アクセスキー ID からは見えません。-sharedDb
オプションを指定して起動すると、クライアントの AWS アクセスキー ID および AWS リージョンによらず、同一のデータを提供するようになります。
-sharedDb
オプションを指定しない場合、初期データを投入する際の AWS アクセスキー ID と利用する際の AWS アクセスキー ID が同一でなければならないのは不便です。そこで -sharedDb
オプションを指定します。
データ入りの DynamoDB Local イメージを作る
それではデータ入りの DynamoDB Local イメージを作ります。大まかな流れは以下のとおりです。
-
-sharedDb
と-dbPath
を指定した DynamoDB Local を起動する - 初期データを投入するプログラムを実行して DynamoDB Local にデータを入れると、
-dbPath
で指定した先にデータベースファイルができる - 上で作ったデータベースファイルを含む新しい DynamoDB Local Docker イメージを作る
これを実行する方法はいくつか考えられますが、Docker の multi-stage build を使用すると、docker build
を一度実行するだけで完了します。
初期データを投入するプログラムは何でも構いませんが、今回は説明を簡単にするため、以下のように仮定します (実際、私の状況は以下の通りでした)。
- 投入プログラムは Java で作られている (
import-data.jar
とする) - プログラムは
localhost:8000
を DynamoDB のエンドポイントとして動作する - プログラムは単独で実行可能な fat jar にパッケージングしている
ビルドに使う Dockerfile は以下のようなものです。
FROM amazoncorretto:11 as builder
USER root
RUN mkdir /app
COPY ./import-data.jar /app
COPY ./dynamodb-local-init.sh /
RUN yum install -y tar gzip \
&& curl -O https://s3-ap-northeast-1.amazonaws.com/dynamodb-local-tokyo/dynamodb_local_latest.tar.gz \
&& mkdir /dynamodb \
&& tar zxf dynamodb_local_latest.tar.gz -C /dynamodb \
&& mkdir /data
# このスクリプトが DynamoDB Local を起動して import-data.jar を実行します
RUN /dynamodb-local-init.sh
# ここまでがビルド用のイメージ (builder) で、ここからが配布用のイメージです
FROM amazon/dynamodb-local
# ビルド用のイメージから配布用のイメージにデータベースファイルをコピーしています
COPY data/ /data/
USER root
RUN chown -R dynamodblocal /data/
USER dynamodblocal
EXPOSE 8000
ENTRYPOINT ["java"]
CMD ["-jar", "DynamoDBLocal.jar", "-sharedDb", "-dbPath", "/data"]
#!/bin/bash
# DynamoDB Local を起動して PID を取得
java -jar -Djava.library.path=/dynamodb/DynamoDBLocal_lib /dynamodb/DynamoDBLocal.jar -sharedDb -dbPath /data &
echo $! >/tmp/dynamodb.pid
# 起動が終わるまで念のため待機
sleep 1
# データ投入プログラムを実行
java -jar /app/import-data.jar
# DynamoDB Local を停止
kill "$(cat /tmp/dynamodb.pid)"
ビルド用のイメージのベースとして amazoncorretto:11
を使っていますが、DynamoDB Local が動く環境であれば何でも良いです。最初はビルド用のイメージも amazon/dynamodb-local
をベースにしようとしたのですが、Java のバージョンが古かったので amazoncorretto:11
にしました。
イメージをビルドするには、上記の Dockerfile、dynamodb-local-init.sh、import-data.jar があるディレクトリで以下を実行するだけです。
$ docker build -t my-project/dynamodb-local:latest .
以上でデータ入りのイメージ my-project/dynamodb-local:latest
が完成します。
Discussion