🦔

Docker Commitの落とし穴: ボリュームマウントされたデータがイメージに保存されない理由と対策

2022/10/22に公開

Dockerを使っていると、コンテナの状態を新しいイメージとして保存したい場面が多々あります。その際に便利なコマンドがdocker commitです。しかし、docker commitを使っても期待通りにデータが保存されないことがあります。この記事では、私が経験した問題とその原因、そして解決策について詳しく説明します。

docker commit コマンドの基本

まず、docker commitコマンドは、起動中のコンテナのファイルシステムの状態を新しいイメージとして保存するためのものです。基本的な使い方は以下の通りです。

docker commit [OPTIONS] CONTAINER [REPOSITORY[:TAG]]
# or
docker container commit [OPTIONS] CONTAINER [REPOSITORY[:TAG]]

詳細な使い方は公式ドキュメントを参照してください。

問題の発生

私のユースケースでは、開発環境のDBコンテナの状態を新しいイメージに保存する必要がありました。具体的には、DBコンテナ内でSQLを実行してデータベースに変更を加えた後、その状態をdocker commitで保存しようとしました。
しかし、docker commitで作成した新しいイメージからコンテナを起動すると、SQLで追加・変更したデータが存在しないという問題が発生しました。

原因の究明

この問題の原因は非常にシンプルでした。docker commitコマンドは、ボリュームマウントされたデータをイメージに含めないという仕様があったのです。

公式ドキュメントの記述

公式ドキュメントには以下のように記載されています。
The commit operation will not include any data contained in volumes mounted inside the container.
つまり、コンテナ内でボリュームマウントされたデータは、docker commit操作によって新しいイメージに含まれないのです。

ボリュームマウントの仕組み

Dockerのイメージは、Dockerのファイルシステムの情報のみを持ちます。バインドマウント(bind mount)やボリューム(volume)は、その違いが曖昧になることがありますが、共通しているのは「外部的なストレージ・ボリューム」であるという点です。

バインドマウントの具体例

以下のようなdocker-compose.ymlファイルでバインドマウントを利用している場合を考えます。

docker-compose.yml
services:
  db:
    volumes:
      - /path/to/mount/on_host:/mount/target/on_container

この設定では、コンテナ内の/mount/target/on_containerディレクトリには、ホストの/path/to/mount/on_hostディレクトリがマウントされます。この状態でdocker commitを実行しても、マウントされた外部のストレージはイメージに含まれません。

解決策

この問題を解決するためには、いくつかの方法があります。

データをコンテナ内にコピー

ボリュームマウントされたデータを一時的にコンテナ内の別のディレクトリにコピーし、その状態でdocker commitを実行する方法です。

docker cp /mount/target/on_container /path/to/copy
docker commit CONTAINER_ID new_image_name

Dockerfileを利用

もう一つの方法は、Dockerfileを使ってイメージを作成する方法です。Dockerfileを使うことで、データのコピーや設定を自動化できます。
マウントする方法ではなく、Dockerfile で COPY してはじめからイメージに必要なファイルを保存しておけば、コンテナ起動時にそのファイルを参照出来ます。
私のケースだとこの方法を使って、DBのファイルをイメージにコピーして、DBコンテナが起動する時点で、データが入っている状態を再現することが出来ました。

Dockerfile
FROM base_image
COPY /path/to/mount/on_host /mount/target/on_container

まとめ

docker commitコマンドは便利ですが、ボリュームマウントされたデータがイメージに含まれないという仕様に注意が必要でした。docker commit ってあんまり使っているひといないですが、参考になれば幸いです。私は今後は docker commit 使いません(多分)

Discussion