Dockerの正しい使い方ではないのでしょうが、開発環境では便利なシーンがありそうな「DBをデータごとまるっとコンテナ化する」アイデアを紹介します。
背景
- 機能開発と不具合修正を並行するためにDBの現行バージョンと次期バージョンを何度も切り替えたり、マイグレーションツールの検証のために何回もDBをクリーンな状態に戻したり、といったケースで可能な限り高速にDBをある時点の状態に切り替えたい
- DBの環境構築手順が十分に自動化されていないようなプロジェクトであっても、一度がんばって構築すれば、その時点のDBをスナップショットとしてあとで何度でも使いまわせるようにしたい
課題
- 一見すると、PostgreSQLの 公式Dockerイメージ を使ってDB構築し、気に入った状態になったら再利用できるよう
docker commit
でイメージ化しておけばよさそうです。しかし、実際にはDBのデータ領域/var/lib/postgresql/data
はVOLUME
指定されており、イメージ化の対象からは除外されてしまいます(=再度docker run
したときにDBは初期状態に戻ってしまう)
解決策
VOLUME
指定のないPostgreSQLイメージからコンテナを起動することで、DBのデータ領域も含めてある時点のスナップショットを完全に丸ごとDockerイメージ化できるようにします。
-
PostgreSQL公式イメージの
Dockerfile
を改変して、VOLUME
指定を除外する$ git clone https://github.com/docker-library/postgres $ cd ./postgres/9.6/ $ vi Dockerfile $ git diff
@@ -131,7 +131,7 @@ RUN mkdir -p /var/run/postgresql && chown -R postgres:postgres /var/run/postgres ENV PATH $PATH:/usr/lib/postgresql/$PG_MAJOR/bin ENV PGDATA /var/lib/postgresql/data RUN mkdir -p "$PGDATA" && chown -R postgres:postgres "$PGDATA" && chmod 777 "$PGDATA" # this 777 will be replaced by 700 at runtime (allows semi-arbitrary "--user" values) -VOLUME /var/lib/postgresql/data +#VOLUME /var/lib/postgresql/data COPY docker-entrypoint.sh /usr/local/bin/ RUN ln -s usr/local/bin/docker-entrypoint.sh / # backwards compat
-
Dockerイメージをビルドする
$ docker build -t postgres-embed:9.6 .
-
改変したDockerイメージからDBを起動する
$ docker run -d --rm -p 5432:5432 —-name=temp-db postgres-embed:9.6
-
DBを初期セットアップする
- マイグレーションツールで自動構築するなり、SQLを1つずつ実行して手動構築するなりお任せ
-
新しいDockerイメージとしてDBの状態を保存する
$ docker commit temp-db my-awesome-db:1.0 $ docker images my-awesome-db REPOSITORY TAG IMAGE ID CREATED SIZE my-awesome-db 1.0 55f54dadb483 5 seconds ago 273MB
-
イメージ作成用の実行中コンテナを停止する
$ docker stop temp-db
-
作成したDockerイメージから爆速でDBを起動する(必要になるたび)
$ docker run -d --rm -p 5432:5432 --name=awesome-db my-awesome-db:1.0
まとめ
VOLUME
指定をもたないPostgreSQLイメージからコンテナを起動することで、コンテナ起動中にDBに発生したデータ修正も含めて丸ごと docker commit
でDockerイメージ化するアイデアを紹介しました。コンテナに状態をもたせないという定石からは外れてしまうものの、VirtualBoxなどのVMで実現した場合よりも圧倒的に速く、頻繁にDBを構築し直さなければならない現場では役に立つかもしれません。