【Docker】ボリュームでデータを永続化する

Docker

こんにちは、かつコーチです。

「MySQLコンテナを docker rm したら、せっかく登録したデータが全部消えてしまった」という経験はありませんか。

コンテナは「使い捨てにできる身軽さ」がメリットの1つですが、そのせいでデータベースのようにデータを保持し続けたいものまで一緒に消えてしまうと困ります。

この記事では、コンテナを削除してもデータを残す仕組みであるボリュームの基本と、実際の使い方を解説します。

ボリュームとは?

外部倉庫に荷物を預けるイメージ

ボリューム(コンテナの外部にデータを保存する仕組みです)は、引っ越し用の身軽な段ボール箱(コンテナ)とは別に、大事な荷物だけを外部倉庫に預けておくイメージで捉えると理解しやすいです。

コンテナ自体は「使い終わったら気軽に処分できる箱」として扱いたい一方、データベースのデータファイルのような大事な荷物は、箱を処分しても倉庫に残り続けてほしいですよね。

Dockerでは、この「外部倉庫」の役割をボリュームが担います。

ボリュームはDockerが管理する専用の保存領域で、コンテナのライフサイクル(作成・削除)とは切り離して存在し続けます。

なぜボリュームが必要なのか

コンテナ内のファイルシステムは、コンテナを削除すると一緒に消えてしまうエフェメラル(一時的、揮発性という意味です)な性質を持っています。

これはコンテナの設計上「使い捨てにしやすい」というメリットの裏返しでもあるのですが、データベースやアップロードされたファイルの保存先など、消えては困るデータには不向きです。

そこでコンテナ本体とは別に、ボリュームという形でデータの置き場所を用意し、コンテナが入れ替わってもデータだけは引き継げるようにします。

基本の使い方

docker volume createでボリュームを作る

まずは、明示的にボリュームを作成するコマンドから見ていきます。

docker volume create my-db-data

作成したボリュームの一覧は、以下で確認できます。

docker volume ls

詳細情報(実際にホスト上のどこに保存されているかなど)は inspect で確認できます。

docker volume inspect my-db-data

docker runで-vオプションを使う

作成したボリュームは、コンテナ起動時に -v(または --mount)オプションでマウントします。

docker run -d \
  --name my-mysql \
  -e MYSQL_ROOT_PASSWORD=example \
  -v my-db-data:/var/lib/mysql \
  mysql:8.0

-v my-db-data:/var/lib/mysql の部分は、「ホスト側のボリューム名(またはパス):コンテナ内のパス」という形式です。

MySQLがデータを保存する /var/lib/mysql にボリュームをマウントしておくことで、コンテナを削除してもデータはボリューム側に残り続けます。

docker rm -f my-mysql

docker run -d \
  --name my-mysql \
  -e MYSQL_ROOT_PASSWORD=example \
  -v my-db-data:/var/lib/mysql \
  mysql:8.0

同じボリュームを指定して再起動すれば、以前登録したデータがそのまま復元されます。

bind mountとの違い

似たような機能にbind mount(ホストの特定ディレクトリを直接コンテナにマウントする方法です)があります。

docker run -d \
  --name my-app \
  -v $(pwd)/src:/app/src \
  my-app:1.0

ボリュームとbind mountの違いは、次のように整理できます。

項目ボリュームbind mount
管理Dockerが管理ホストのパスを直接指定
保存場所Docker管理領域(通常は非公開)指定したホストのディレクトリ
主な用途DBデータなど永続化したいデータ開発中のソースコードのライブマウント
可搬性高い(環境に依存しにくい)低い(ホストのパス構成に依存する)

「データベースの永続化にはボリューム」「開発中にソースコードを即座に反映させたいときはbind mount」というように、目的に応じて使い分けるのが基本方針です。

よくあるつまずきポイント・エラー対処

コンテナを削除したらDBデータが消えた

実際に私が開発初期にやってしまった失敗が、ボリュームを指定せずにDBコンテナを起動していたことです。

❌ Before:ボリュームなしでMySQLコンテナを起動する

docker run -d \
  --name my-mysql \
  -e MYSQL_ROOT_PASSWORD=example \
  mysql:8.0

このまま動作確認用のテストデータを登録し、コンテナのバージョンを上げるつもりで docker rm -f my-mysql を実行したところ、登録したデータがすべて消えてしまいました。

-v オプションを付けていなかったので、データはコンテナ内部のファイルシステムにしか存在しておらず、コンテナの削除と一緒に失われたのです。

✅ After:必ずボリュームをマウントしてから運用を始める

docker volume create my-db-data

docker run -d \
  --name my-mysql \
  -e MYSQL_ROOT_PASSWORD=example \
  -v my-db-data:/var/lib/mysql \
  mysql:8.0

この一件以来、私はDB系のコンテナを起動する前に「このデータはボリュームで永続化する必要があるか」を必ず確認するようにしています。

「動作確認用だから」と油断せず、最初からボリュームを付けて起動しておくのが安全です。

応用・一歩先の使い方

docker-composeでのボリューム定義への橋渡し

複数のコンテナを扱う docker-compose では、ボリュームを volumes: セクションでまとめて宣言できます。

# docker-compose.yml
services:
  db:
    image: mysql:8.0
    environment:
      MYSQL_ROOT_PASSWORD: example
    volumes:
      - my-db-data:/var/lib/mysql

volumes:
  my-db-data:

docker run-v オプションと考え方は同じで、コンテナが増えてもYAMLとして構成をコード管理できるのが利点です。

docker-composeの詳しい使い方は、次のシリーズで扱います。

まとめ

この記事のポイント

  • ボリュームは、コンテナを削除してもデータを残すための「外部倉庫」のような仕組み
  • docker volume create で作成し、docker run -v ボリューム名:コンテナ内パス でマウントする
  • ボリュームは永続化用途、bind mountは開発中のライブ反映用途と使い分ける
  • DB系コンテナは、動作確認段階からボリュームを付けて起動する習慣をつける

次に読むべき記事

  • マルチステージビルドでイメージを軽量化する
  • Dockerネットワークの基本:コンテナ同士をつなぐ

タグ: Docker, 中級者向け, データ永続化

タイトルとURLをコピーしました