言語を切り替える
テーマを切り替える

Docker ボリューム実戦ガイド:5 つの事例でコンテナのデータ消失を解決

ターミナルの最終出力は「Database import completed successfully」。4 時間かけてようやく 2 万件のテストデータを MySQL コンテナにインポートし終え、API テストも無事にパスしました。

翌朝起きて、習慣的に docker ps を実行しました。しかし、コンテナの状態は空っぽです。「昨晩、起動し忘れたのだろうか」と急いで docker ps -a で全コンテナを確認しても見当たりません。そこでようやく、寝る前にディスク容量を空けようと docker system prune -a を何気なく実行したことを思い出しました。

すべて消えてしまったのです。2 万件のテストデータと 4 時間の作業が、一瞬にして完全にゼロになりました。

4 時間
データ消失
2 万件のテストデータと 4 時間の作業が、完全にゼロになりました

Docker を使い始めてまだ 3 週間。コンテナの起動速度や環境の分離性というメリットしか知らず、「コンテナ自体はデータの保存に向いていない」というアキレス腱を知りませんでした。コンテナを削除すればデータも消え、再起動すれば設定ファイルは初期状態に戻ってしまいます。

この記事では、5 つの実践事例を通して、Docker Volume(データボリューム)を使ってデータをコンテナから「解放」する方法を分かりやすく解説します。これで、コンテナの生死によって大切なデータが消え去ることはなくなります。

コンテナデータ消失の真実

なぜコンテナを消すとデータも消えるのか?

Docker はレイヤー(層)構造のファイルシステムを使っています。ミルクレープを想像してください。下の層は「イメージ層」(読み取り専用、全コンテナで共有)で、一番上が「コンテナ層」(書き込み可能、各コンテナ専用)です。あなたがコンテナ内で作成したファイル、変更した設定、インポートしたデータは、すべてこの一番上の層に書き込まれます。

重要なのはここです:コンテナを削除すると、この書き込み可能な層も一緒に破棄されます。

信じられないなら、試してみましょう:

# Alpine コンテナを起動してファイルを書き込む
docker run -it --name test-container alpine sh
# コンテナ内で実行
echo "重要データ" > /tmp/data.txt
exit

# コンテナを削除
docker rm test-container

# データを探してみる
docker run -it --name test-container alpine sh
cat /tmp/data.txt  # エラー:No such file or directory

データが消える瞬間、警告は一切ありません。

この設計は理にかなっています。コンテナは本来「ステートレス(状態を持たない)アプリケーション」のために設計されました。Nginx や API サーバーを考えてみてください。再起動しても毎回同じ状態で立ち上がるべきです。しかし、データベース、Redis、ファイルアップロードサービスはどうでしょうか?これらはデータを保持し続けなければなりません。

Docker 公式の解決策が Volume(データボリューム) です。データをコンテナの外に出し、コンテナの生死とデータの存続を完全に切り離します。

Volume とは何か?どうやってデータを救うのか

Volume の本質:Docker の「外付け HDD」

Volume はコンテナに「外付けハードディスク」を繋ぐようなものです。データはコンテナ内ではなく、ホストマシンの特定のディレクトリに書き込まれ、それがコンテナ内部のパスに「マウント(接続)」されます。コンテナからは /var/lib/mysql に見えますが、実際のデータはホストの /var/lib/docker/volumes/mysql-data/_data にあります。

コンテナを削除しても?大丈夫、データはホストに残っています。新しいコンテナを起動して同じ Volume をマウントすれば、データはそのまま戻ってきます。

Docker には 3 種類のマウント方式があり、初心者が一番混乱するポイントです:

マウントタイプデータ保存場所適用シナリオ管理方法
VolumeDocker 管理ディレクトリ(/var/lib/docker/volumes/)データベース永続化、本番データDocker コマンドで統合管理
Bind Mountホストの任意のパス開発時のコードマウント、設定ファイルパスを手動管理
tmpfsメモリ一時データ、機密情報(ディスクに残さない)コンテナ停止で消去

正直、最初は Volume と Bind Mount の違いが分かりませんでした。「どっちもホストのディレクトリを繋ぐんでしょ?」と。しかし落とし穴がありました。Bind Mount で MySQL のデータディレクトリをマウントしていた時、うっかりホスト側のディレクトリを削除してしまい、MySQL コンテナが崩壊しました。

Volume は Docker が完全に管理するため、パスや権限、バックアップ戦略を気にする必要がありません。データがどこにあるか知りたい? docker volume inspect で分かります。データを移行したい? docker volume コマンドで OK です。これが、公式が Bind Mount より Volume を推奨する理由です。

Volume データの実体はどこ?

Linux システムでは、すべての Volume はデフォルトでここにあります:

/var/lib/docker/volumes/<ボリューム名>/_data/

Mac や Windows ユーザーは探さないでください。Docker Desktop は仮想マシン内で動いているので、ホストからは直接見えません(docker volume inspect で確認は可能です)。

5 つの事例でマスターする Volume の核心

理論はここまで。実際に手を動かしましょう。これら 5 つの事例を試せば、基礎から実戦まで完全に理解できます。


事例 1:最初の名前付き Volume を作成する

まずは一番簡単な、空の Volume 作成から。

# my-data という名前の Volume を作成
docker volume create my-data

# すべての Volume を表示
docker volume ls

# Volume の詳細を確認
docker volume inspect my-data

期待される出力(inspect コマンド):

[
    {
        "CreatedAt": "2025-12-17T12:00:00Z",
        "Driver": "local",
        "Mountpoint": "/var/lib/docker/volumes/my-data/_data",
        "Name": "my-data"
    }
]

Mountpoint が見えますか?これがデータが実際に保存される場所です。


事例 2:Nginx 静的サイトの永続化

シナリオ:静的サイトを開発中。コードを変えるたびに Nginx コンテナを再起動したいが、アップロードした画像やログが消えるのは困る。

解決策:Nginx の /usr/share/nginx/html を Volume にマウントします。

# コンテンツ保存用 Volume を作成
docker volume create nginx-html

# Nginx コンテナを起動し、Volume をマウント
docker run -d \
  --name my-nginx \
  -p 8080:80 \
  -v nginx-html:/usr/share/nginx/html \
  nginx:latest

# コンテナに入ってテストページを作成
docker exec my-nginx bash -c 'echo "<h1>Hello Docker Volume!</h1>" > /usr/share/nginx/html/index.html'

# アクセス確認(ブラウザで http://localhost:8080 または curl)
curl http://localhost:8080

ここでコンテナを削除します:

docker rm -f my-nginx

新しいコンテナを起動し、同じ Volume をマウントします:

docker run -d \
  --name my-nginx-v2 \
  -p 8080:80 \
  -v nginx-html:/usr/share/nginx/html \
  nginx:latest

# 再度アクセス。内容は残っている!
curl http://localhost:8080

データは消えていません。これが Volume の魔法です。


事例 3:MySQL データの永続化(実戦級)

これが最も一般的なニーズです。MySQL をコンテナ化するなら、データ永続化は必須です。

# MySQL 専用 Volume を作成
docker volume create mysql-data

# MySQL コンテナを起動
docker run -d \
  --name mysql-demo \
  -e MYSQL_ROOT_PASSWORD=my-secret-pw \
  -e MYSQL_DATABASE=testdb \
  -p 3306:3306 \
  -v mysql-data:/var/lib/mysql \
  mysql:8.0

# 起動待ち(約 10 秒)
sleep 10

# MySQL に接続し、テストテーブルを作成
docker exec -it mysql-demo mysql -uroot -pmy-secret-pw testdb -e "
CREATE TABLE users (
  id INT PRIMARY KEY AUTO_INCREMENT,
  name VARCHAR(50)
);
INSERT INTO users (name) VALUES ('Alice'), ('Bob');
"

# データ確認
docker exec -it mysql-demo mysql -uroot -pmy-secret-pw testdb -e "SELECT * FROM users;"

コンテナを削除します(誤削除のシミュレーション):

docker rm -f mysql-demo

再起動して同じ Volume をマウント:

docker run -d \
  --name mysql-demo-v2 \
  -e MYSQL_ROOT_PASSWORD=my-secret-pw \
  -p 3306:3306 \
  -v mysql-data:/var/lib/mysql \
  mysql:8.0

# 起動待ち
sleep 10

# データはまだある!
docker exec -it mysql-demo-v2 mysql -uroot -pmy-secret-pw testdb -e "SELECT * FROM users;"

ポイント:MySQL のデータディレクトリは /var/lib/mysql です。ここを必ずマウントしてください。データベースによってパスは異なります(Redis は /data、PostgreSQL は /var/lib/postgresql/data)。


事例 4:Redis 永続化設定

Redis はデフォルトでデータをメモリに保存しますが、ディスク(RDB または AOF)への永続化も可能です。

# Redis データ用 Volume 作成
docker volume create redis-data

# Redis 起動(AOF 永続化を有効化)
docker run -d \
  --name redis-demo \
  -p 6379:6379 \
  -v redis-data:/data \
  redis:latest redis-server --appendonly yes
  # --appendonly yes で AOF 永続化を有効化

# データを書き込む
docker exec -it redis-demo redis-cli SET mykey "Hello Redis Volume"

# 読み込む
docker exec -it redis-demo redis-cli GET mykey

コンテナ削除:

docker rm -f redis-demo

再起動:

docker run -d \
  --name redis-demo-v2 \
  -p 6379:6379 \
  -v redis-data:/data \
  redis:latest redis-server --appendonly yes

# データは残存
docker exec -it redis-demo-v2 redis-cli GET mykey

注意--appendonly yes パラメータが必要です。そうしないと Redis はメモリにしかデータを保存せず、コンテナ再起動後もデータが消えます。


事例 5:複数コンテナでの Volume 共有

シナリオ:Nginx コンテナが静的ファイルを提供し、別のアプリコンテナがログを生成する。2 つのコンテナで同じ Volume を共有します。

# 共有 Volume 作成
docker volume create shared-logs

# アプリコンテナ起動(ログ書き込み役)
docker run -d \
  --name app-writer \
  -v shared-logs:/logs \
  alpine sh -c "while true; do echo $(date) >> /logs/app.log; sleep 2; done"

# Nginx コンテナ起動(ログ読み込み役)
docker run -d \
  --name log-reader \
  -p 8080:80 \
  -v shared-logs:/usr/share/nginx/html:ro \
  nginx:latest
  # :ro は読み取り専用(read-only)。Nginx が誤ってログを変更するのを防ぐ

# 数秒待つ(app-writer がログを書き込むまで)
sleep 5

# ログファイルにアクセス(ブラウザで http://localhost:8080/app.log)
curl http://localhost:8080/app.log

ポイント

  1. 1 つの Volume を複数のコンテナで同時にマウントできる
  2. :ro サフィックスで読み取り専用モードを設定でき、セキュリティが向上する
  3. 本番環境では「ログ収集コンテナ + アプリコンテナ」構成などでよく使われる

Volume 管理コマンド

5 つの事例を終えて、「どうやって Volume を確認・削除・掃除するの?」と思ったでしょう。
完全な管理コマンドの早見表です:

# 1. Volume を作成
docker volume create <ボリューム>

# 2. すべての Volume を一覧表示
docker volume ls

# 3. Volume の詳細を確認(マウントパスを含む)
docker volume inspect <ボリューム>

# 4. 指定した Volume を削除
docker volume rm <ボリューム>
# 注意:Volume がコンテナで使用中の場合はエラーになります

# 5. 未使用の Volume をすべて削除(ディスク容量の解放)
docker volume prune
# 確認プロンプトが表示されます。y で続行

# 6. 未使用 Volume を強制削除(確認なし)
docker volume prune -f

よくある問題:Volume 削除時に “volume is in use” と表示される

これは Volume を使用中のコンテナが存在するためです。対処法:

# どのコンテナが使用中か確認
docker ps -a --filter volume=<ボリューム>

# コンテナを停止・削除
docker rm -f <コンテナ>

# 再度 Volume を削除
docker volume rm <ボリューム>

ディスク使用量の確認

Volume がどれくらいディスク容量を使っているか知りたい時:

# Linux / Mac ユーザー
docker volume inspect <ボリューム> --format '{{ .Mountpoint }}' | xargs du -sh

# 出力例:512M    /var/lib/docker/volumes/mysql-data/_data

Bind Mount vs Volume:どっちを使うべき?

初心者が最も迷うポイントです。私も最初は Bind Mount ばかり使って失敗しました。

シンプルに覚えましょう:本番データなら Volume、開発コードなら Bind Mount

シナリオ推奨方式理由
MySQL / PostgreSQL データベースVolumeDocker 管理、バックアップ容易、高性能
Redis / MongoDB 永続化Volume同上
ログファイル、アップロードファイルVolumeデータ安全、コンテナ削除の影響なし
開発時のソースコードBind Mountコード変更が即反映、コンテナ再起動不要
設定ファイル(nginx.conf)Bind Mount設定変更が容易、テストが速い
一時データ、キャッシュtmpfs最高性能、ディスクを消費しない

構文比較

# Volume 方式(データ永続化向け)
docker run -v my-volume:/data redis:latest

# Bind Mount 方式(開発環境向け)
docker run -v /Users/me/code:/app node:latest

# 新構文 --mount(より明確、本番環境推奨)
docker run --mount type=volume,source=my-volume,target=/data redis:latest
docker run --mount type=bind,source=/Users/me/code,target=/app node:latest

意思決定ツリー

新しい要件で迷ったら、3 つの質問を自分に問いかけてください:

  1. データを長期保存する必要がある?
    はい → Volume;いいえ → tmpfs

  2. ホスト側で直接ファイルを編集する必要がある?
    はい → Bind Mount;いいえ → Volume

  3. 本番環境か開発環境か?
    本番 → Volume;開発 → Bind Mount

実例比較

私の開発環境:

# 開発時:コードは Bind Mount、データベースは Volume
docker run -d \
  --name dev-app \
  -v $(pwd)/src:/app/src \          # Bind Mount:コード変更が即反映
  -v app-uploads:/app/uploads \     # Volume:ユーザーアップロードファイル
  -v postgres-data:/var/lib/postgresql/data \  # Volume:データベースデータ
  my-app:dev

私の本番環境:

# 本番時:すべて Volume
docker run -d \
  --name prod-app \
  -v app-uploads:/app/uploads \
  -v postgres-data:/var/lib/postgresql/data \
  my-app:latest
# コードはイメージにビルド済みなのでマウント不要

よくある質問とベストプラクティス

FAQ:私が踏んだ落とし穴と解決策

Q1: Volume のデータは消えますか?
消えません。手動で docker volume rm を実行しない限り、データは残ります。ホストマシンを再起動してもデータは保持されます。

ただし注意:docker system prune -a --volumes は未使用の Volume をすべて削除します。慎重に使ってください!


Q2: コンテナ起動時に Volume が存在しないとどうなりますか?
Docker が自動的に作成します。試してみてください:

# 事前に docker volume create しなくても、そのまま実行できる
docker run -d -v auto-created-volume:/data alpine
# auto-created-volume という名前の Volume が自動作成される

ただし、明示的に作成した方がデータの所在が分かりやすいので、手動作成を推奨します。


Q3: Volume データはどうバックアップしますか?
公式推奨の方法:

# 一時コンテナで Volume データをアーカイブ
docker run --rm \
  -v mysql-data:/source \
  -v $(pwd):/backup \
  alpine tar -czf /backup/mysql-backup.tar.gz -C /source .

# 復元時
docker run --rm \
  -v mysql-data:/target \
  -v $(pwd):/backup \
  alpine tar -xzf /backup/mysql-backup.tar.gz -C /target

Q4: Volume を別のホスト間で移行できますか?
可能ですが、手動操作が必要です:

  1. 元のホストで:上記の方法で Volume データをアーカイブ
  2. .tar.gz ファイルを新しいホストに転送
  3. 新しいホストで:Volume を作成し、データを展開

より高度な方法として、NFS やクラウドストレージを Volume Driver として使う方法もあります。


Q5: 匿名 Volume とは?どうクリーンアップしますか?
Volume 名を指定しないと、Docker は匿名 Volume を作成します:

docker run -d -v /data alpine  # a1b2c3d4... のようなランダム名が付く

匿名 Volume は管理が難しく、ディスク容量を圧迫しやすい。クリーンアップ方法:

docker volume prune  # 未使用 Volume をすべて削除(匿名 Volume を含む)

ベストプラクティス:常に命名 Volume を使いましょう。


6 つのベストプラクティス(本番環境必須)

  1. 常に命名 Volume を使う

    # ✓ 良い習慣
    docker run -v mysql-data:/var/lib/mysql mysql:8.0
    
    # ✗ 悪い習慣
    docker run -v /var/lib/mysql mysql:8.0  # 匿名 Volume になる
  2. 重要データは定期的にバックアップ
    データベース Volume を毎日バックアップする cron ジョブを設定しましょう。データ消失の痛みは、一度味わえば十分です。

  3. Docker Compose で複雑なプロジェクトを管理

    # docker-compose.yml
    services:
      db:
        image: mysql:8.0
        volumes:
          - mysql-data:/var/lib/mysql
    
    volumes:
      mysql-data:
        driver: local
  4. 本番環境では -v より —mount を使う
    --mount 構文の方が明確で、エラー時のメッセージも分かりやすい:

    docker run --mount type=volume,source=mysql-data,target=/var/lib/mysql mysql:8.0
  5. 未使用 Volume を定期的にクリーンアップ
    月 1 回は実行しましょう:

    docker volume prune
  6. 機密データは暗号化 Volume を使う
    Volume にパスワードや鍵が含まれる場合、LUKS 暗号化パーティションなどの暗号化スキームを検討してください。

結論

冒頭のあの夜——当時 Docker Volume を知っていれば、たった 1 行のコマンドで済んだはずです:

docker run -d --name mysql-demo -v mysql-data:/var/lib/mysql mysql:8.0

データはコンテナと共に消えることなく、2 万件のテストデータと 4 時間の作業は、ホスト上で安全に守られたでしょう。

Docker コンテナは「ステートレス」——これが強みでもあり、限界でもあります。Volume はその限界を突破するために存在します。コンテナの軽快さと隔離性を享受しつつ、データを安心して保存できます。

この記事では 5 つの事例を通して、最初の Volume 作成から Nginx 静的サイトの永続化、MySQL・Redis の実戦シナリオ、複数コンテナでの Volume 共有までを解説しました。日常開発の 90% をカバーする内容です。

さあ、ターミナルを開いて最初の Volume を作成し、MySQL コンテナを起動してデータを書き込んでみましょう。コンテナを削除して再起動し、データが残っている瞬間——「データ永続化」の意味が体で理解できるはずです。

「午前 3 時のデータ消失」を二度と経験したくないなら、この記事をブックマークしておいてください。いつかあなたを救うかもしれません。

Docker ボリューム実戦の完全フロー

5 つの事例でコンテナのデータ消失を解決。基本概念から MySQL・Redis の永続化まで

⏱️ 目安時間: 30 分

  1. 1

    ステップ1: 問題の根源を理解する:コンテナでデータが消える理由

    問題の根源:
    • Docker コンテナはデータ保存に向いていません。削除するとデータも消えます
    • 再起動すると設定ファイルは初期状態に戻ります
    • コンテナ削除時、書き込み可能な層も一緒に破棄されます
    • これが Docker の「アキレス腱」です

    Docker のレイヤーファイルシステム:
    • 下層はイメージ層(読み取り専用、全コンテナで共有)
    • 上層はコンテナ層(書き込み可能、各コンテナ専用)
    • コンテナ内で作成したファイル、変更した設定、インポートしたデータはすべてこの上層に書き込まれます
    • コンテナ削除時、この書き込み可能な層も一緒に破棄されます
  2. 2

    ステップ2: 事例 1:最初の Volume を作成する

    Volume の作成:
    • docker volume create コマンドで Volume を作成
    • コマンド:docker volume create my-data
    • Volume は Docker が管理し、Docker データディレクトリに保存。本番環境向き

    Volume の使用:
    • コンテナ起動時に Volume をマウント:docker run -d -v my-data:/data alpine
    • データは Volume に保存され、コンテナを削除しても失われません

    Volume の確認:
    • docker volume ls で全 Volume を表示
    • docker volume inspect my-data で Volume の詳細を確認
  3. 3

    ステップ3: 事例 2〜5:Nginx・MySQL・Redis の永続化と複数コンテナ共有

    事例 2:Nginx 静的サイトの永続化
    • Volume をコンテナにマウント:docker run -d -v nginx-html:/usr/share/nginx/html nginx
    • 静的ファイルは Volume に保存され、コンテナを削除しても失われません

    事例 3:MySQL データの永続化
    • /var/lib/mysql に Volume をマウント:docker run -d -v mysql-data:/var/lib/mysql mysql:8.0
    • データベースデータは Volume に保存され、コンテナを削除しても失われません

    事例 4:Redis データの永続化
    • /data に Volume をマウント:docker run -d -v redis-data:/data redis
    • Redis データは Volume に保存され、コンテナを削除しても失われません

    事例 5:複数コンテナで Volume を共有
    • 複数コンテナが同じ Volume をマウント:
    docker run -d -v shared-data:/data container1
    docker run -d -v shared-data:/data container2
    • 複数コンテナでデータを共有可能
  4. 4

    ステップ4: Volume と Bind Mount の比較、ベストプラクティス

    Volume と Bind Mount の比較:

    Volume
    • Docker が管理し、Docker データディレクトリに保存
    • 本番環境向き。より安全で信頼性が高い

    Bind Mount
    • ホストマシンのディレクトリを直接マウント
    • 開発環境向き。設定が柔軟

    ベストプラクティス:
    • 本番環境では Volume を使用
    • 開発環境では Bind Mount も利用可能
    • Volume データを定期的にバックアップ:
    docker run --rm -v mysql-data:/data -v $(pwd):/backup alpine tar czf /backup/mysql-backup.tar.gz /data
    • 管理しやすい命名 Volume を使用。匿名 Volume は避ける
    • 未使用 Volume を定期的に削除:月 1 回 docker volume prune を実行

FAQ

なぜコンテナのデータは消えるのですか?Docker コンテナはデータ保存に向いていませんか?
問題の根源:Docker コンテナはデータ保存に向いていません。コンテナを削除するとデータも消え、再起動すると設定は初期状態に戻ります。コンテナ削除時、書き込み可能な層も一緒に破棄されます。これが Docker の「アキレス腱」です。

Docker はレイヤーファイルシステムを使います。ミルクレープを想像してください:
• 下層はイメージ層(読み取り専用、全コンテナで共有)
• 上層はコンテナ層(書き込み可能、各コンテナ専用)
• コンテナ内で作成したファイル、変更した設定、インポートしたデータはすべてこの上層に書き込まれます
• コンテナ削除時、この書き込み可能な層も一緒に破棄されます
Docker Volume でデータ消失問題をどう解決しますか?
解決策:Docker Volume(データボリューム)でデータをコンテナから「解放」し、コンテナの生死に左右されないようにします。Volume は Docker が提供するデータ永続化の仕組みで、データはホストマシン上に保存されます。コンテナを削除してもデータは失われません。

Volume の作成:
• docker volume create コマンドで作成:docker volume create my-data
• Volume は Docker が管理し、Docker データディレクトリに保存。本番環境向き

Volume の使用:
• コンテナ起動時にマウント:docker run -d -v my-data:/data alpine
• データは Volume に保存され、コンテナを削除しても失われません
MySQL と Redis のデータ永続化はどう設定しますか?
MySQL データの永続化:
• /var/lib/mysql に Volume をマウント:docker run -d -v mysql-data:/var/lib/mysql mysql:8.0
• データベースデータは Volume に保存され、コンテナを削除しても失われません

Redis データの永続化:
• /data に Volume をマウント:docker run -d -v redis-data:/data redis
• Redis データは Volume に保存され、コンテナを削除しても失われません

永続化の確認:
• コンテナ削除後に再作成してもデータは残る
• docker volume inspect で Volume の場所を確認
• データはホストマシン上に保存される
Volume と Bind Mount の違いは?どちらを使うべきですか?
Volume と Bind Mount の比較:

Volume:
• Docker が管理し、Docker データディレクトリに保存
• 本番環境向き。より安全で信頼性が高い

Bind Mount:
• ホストマシンのディレクトリを直接マウント
• 開発環境向き。設定が柔軟

選択の目安:
• 本番環境では Volume(Docker 管理で安全・信頼性が高い)
• 開発環境では Bind Mount(ホストファイルに直接アクセスでき、デバッグが容易)

ベストプラクティス:
• 本番環境では Volume を使用
• 開発環境では Bind Mount も利用可能
• Volume データを定期的にバックアップ
• 命名 Volume を使用して管理しやすくする
• 匿名 Volume は避ける

5分で読めます · 公開日: 2025年12月17日 · 更新日: 2026年6月8日

関連記事

コメント

GitHubアカウントでログインしてコメントできます