Docker ボリュームとバインド マウント: コンテナ データを正しい方法で保持する

  1. ホーム
  2. ブログ
  3. DevOps

DevOps

Docker ボリュームとバインド マウント: コンテナ データを正しい方法で保持する

コンテナを削除すると、より安全な場所に保管しない限り、そのデータも一緒に消えてしまいます。ボリューム、バインド マウント、tmpfs の違い、それぞれをいつ使用するか、重要なものをバックアップする方法について説明します。

読了目安9分
Docker ボリュームとバインド マウント: コンテナ データを正しい方法で永続化する

ポイント

  • コンテナーの書き込み可能レイヤーはコンテナーとともに削除されるため、重要なデータはマウントする必要があります。
  • 名前付きボリュームは Docker によって管理され、データベースおよび運用データには通常選択されます。
  • バインド マウントはホスト フォルダーをマップするため、開発中のライブ コードに最適です。
  • docker compose down -v はボリュームを削除するため、慎重に使用し、テスト済みのバックアップを保管してください。

コンテナ内でデータベースを起動し、データを追加し、コンテナを削除して、新しいコンテナを起動します。データが消えてしまいました。ほとんどの人がこの教訓を苦労して学びます。 Docker ボリューム とバインド マウントは、1 つのコンテナの存続期間を超えてデータを維持するために存在します。

このガイドでは、それぞれの仕組みと選び方について説明します。ここでのコマンドとファイルは、文書化された Docker の動作に基づいた標準的な例であり、この記事では実行しませんでしたので、最初に使い捨てデータで試してください。詳細は、Docker のバージョン間および Docker Desktop 間で異なる場合があります。コンテナーを初めて使用する場合は、初心者向けの Docker チュートリアルから始めてください。

コンテナデータが消える理由

Docker イメージは読み取り専用レイヤーで構成されます。コンテナーが起動すると、Docker はその上に書き込み可能な薄いレイヤーを追加し、変更はそこに反映されます。このレイヤーは停止して再起動しても残りますが、コンテナーが削除されると削除されます。

docker run -d --name db -e POSTGRES_PASSWORD=devonly postgres:17
# ... create tables and add data ...
docker rm -f db
docker run -d --name db -e POSTGRES_PASSWORD=devonly postgres:17
# The data you added is not there

これは設計によるもので、コンテナーを自由に置き換えることができます。つまり、保持する必要があるものはすべてコンテナの外に存在する必要があります。それには次の 3 つの方法があります。

種類 保存場所 コンテナ撤去は生き残れるのか?
名前付きボリューム Dockerが管理する領域 はい
バインドマウント 選択したホスト パス はい
tmpfs マウント ホストメモリ いいえ

Docker ボリュームとバインド マウントを並べて比較する

アスペクト 名前付きボリューム バインドマウント
管理者 ドッカー あなた
場所 Docker のストレージ領域 ホスト上の任意のパス
ホストフォルダーに依存しますか? いいえ はい
ホストからの編集 デザイン的にぎこちない 簡単、変更はすぐに反映されます
画像から空のターゲットが事前に入力されていますか? はい いいえ、ホストパスによって隠蔽されます
Docker CLI コマンド はい、docker volume いいえ
リモートストレージ用のドライバー はい いいえ
こんな方に最適 データベース、生産データ 開発中のソースコード

名前付きボリューム

ボリュームは、Docker によって作成および管理されるストレージです。名前で参照するので、物理的にどこに存在するかを気にする必要はありません。

docker volume create pgdata

docker run -d --name db \
  -e POSTGRES_PASSWORD=devonly \
  -v pgdata:/var/lib/postgresql/data \
  postgres:17

現在、データベース ファイルは pgdata に存在します。コンテナを削除し、同じボリュームで新しいコンテナを起動しても、データはそのまま残ります。 Linux では、ボリュームは通常 /var/lib/docker/volumes/ の下にありますが、これらのファイルを直接編集しないでください。 Docker Desktop では、これらは通常のフォルダーではなく、仮想マシン内に存在します。

コンテナ内のパスはイメージによって異なるため、イメージのドキュメントを確認してください。間違ったパスにマウントすることは典型的な間違いです。すべてが機能しているように見えますが、データはまだコンテナー層に書き込まれています。イメージの新しいメジャー バージョンでもこのパスが変更される可能性があるため、アップグレードする前にリリース ノートをお読みください。

名前付きボリュームが存在しない場合、Docker は自動的に名前付きボリュームを作成します。名前を付けずに作成された 匿名ボリューム も機能しますが、長いランダムな ID が付与されるため、簡単に追跡できなくなります。ボリュームには必ず名前を付けてください。

バインドマウント

バインド マウントは、特定のホスト パスをコンテナに直接マッピングします。双方が同じファイルを即座に認識します。これにより、エディターでの編集が再構築せずに実行中のコンテナーに反映されるため、開発に最適になります。

docker run -d --name web \
  -p 8080:80 \
  -v "$(pwd)/site:/usr/share/nginx/html:ro" \
  nginx:1.27

site/ でファイルを編集し、ブラウザを更新すると、変更が表示されます。 :ro はコンテナ内のマウントを読み取り専用にします。これは、コンテナがそこに書き込む必要がない場合に良い習慣です。

バインド マウントにはいくつかのトレードオフがあります。

  • それらはあなたをホストに結び付けます。 パスは各マシンに存在する必要があるため、セットアップの移植性は低くなります。
  • 画像のコンテンツを隠します。 /app の上にマウントすると、画像に含まれていたものはすべて見えなくなります。よくある例は node_modules が行方不明になることです。
  • ホストを公開します。書き込み可能なマウントを持つコンテナは、実際のホスト ファイルを変更または削除できます。リスクを十分に理解していない限り、/ や Docker ソケットのような機密性の高いパスをマウントしないでください。
  • パフォーマンスは変動する可能性があります。 macOS および Windows の Docker Desktop では、ファイル共有が仮想化の境界を越えるため、Linux よりも遅くなる可能性があります。

tmpfs マウント

tmpfs マウントはホストのメモリ内に存在し、コンテナ層に書き込まれることはありません。コンテナーが停止すると消えるため、一時ファイル、キャッシュ、および短期間の機密データに適しています。

docker run -d --tmpfs /app/cache:size=64m myapp:1.0

tmpfs は Linux ホストで使用できます。また、データの保持を気にしない使い捨てのテスト環境でデータベースを高速化することもできます。

-v それとも –mount?

どちらのフラグも機能します。 --mount は長いですが、より明示的であり、多くの人がスクリプトで使用することを好みます。

# Short form
docker run -v pgdata:/var/lib/postgresql/data postgres:17

# Explicit form
docker run --mount type=volume,source=pgdata,target=/var/lib/postgresql/data postgres:17

# Bind mount, read-only
docker run --mount type=bind,source="$(pwd)"/site,target=/usr/share/nginx/html,readonly nginx:1.27

意味のある違いが 1 つあります。 -v を使用すると、欠落しているホスト パスが空のフォルダーとして作成され、タイプミスを隠すことができます。 --mount とバインド タイプを使用すると、Docker は代わりにエラーを報告します。また、-v では、左側がタイプを決定します。名前はボリュームを意味し、パスはバインド マウントを意味します。したがって、-v data:/x と -v ./data:/x はまったく異なることを行います。

Docker Compose のボリューム

実際のプロジェクトのほとんどは、Compose ファイルでストレージを宣言します。これは両方の種類を使用し、それぞれが適切な役割を果たします。

services:
  web:
    build: .
    ports:
      - "3000:3000"
    volumes:
      - ./src:/app/src      # bind mount: live code
    depends_on:
      - db

  db:
    image: postgres:17
    environment:
      POSTGRES_PASSWORD: devonly
    volumes:
      - pgdata:/var/lib/postgresql/data   # named volume: data

volumes:
  pgdata:

名前付きボリュームは、最上位の volumes セクションで宣言する必要があります。 Compose は、実際の名前の前にプロジェクト名を付けます。完全なチュートリアルについては、Docker Compose チュートリアルを参照してください。

ヒント: docker compose down は名前付きボリュームを保持しますが、docker compose down -v はそれらをデータとともに削除します。 -v を含むスクリプトとシェル履歴には特に注意してください。

便利なボリュームコマンド

コマンド 何をするのか
ドッカーボリューム ls ボリュームのリストを表示します
docker ボリューム作成名 ボリュームを作成します
docker ボリューム検査名 場所を含む詳細を表示します
docker ボリューム rm 名 ボリュームとそのデータを削除します
ドッカーボリュームプルーン 未使用のボリュームを削除します
ドッカーシステム df -v ボリュームを含むディスク使用量を表示します

これは元に戻すことができないため、prune で削除される内容を確認してから確認してください。現在コンテナが使用していないボリュームには、重要なデータがまだ保持されている可能性があります。

ボリュームのバックアップと復元

ボリュームとホスト フォルダーの両方をマウントする短期間のコンテナーを実行することで、ボリュームをバックアップできます。

# Back up
docker run --rm \
  -v pgdata:/data:ro \
  -v "$(pwd)":/backup \
  alpine tar czf /backup/pgdata.tar.gz -C /data .

# Restore into a new volume
docker volume create pgdata_restored
docker run --rm \
  -v pgdata_restored:/data \
  -v "$(pwd)":/backup \
  alpine tar xzf /backup/pgdata.tar.gz -C /data

ライブデータベースの場合、このようにファイルをコピーすると、不整合な状態がキャプチャされる可能性があります。最初にコンテナを停止するか、PostgreSQL の pg_dump などのデータベース独自のツールを使用することをお勧めします。また、復元したことのないバックアップは単なる希望にすぎないため、復元をテストしてください。

ファイル権限

「許可が拒否されました」はマウントに関する最も一般的な問題です。ファイルは Linux 上で数値のユーザー ID とグループ ID を保持するため、コンテナーがユーザー 1000 として実行され、ホスト フォルダーが別のユーザーに属している場合、書き込みは失敗します。これを修正するいくつかの方法:

  • 一致するユーザーでコンテナを実行します: docker run --user "$(id -u):$(id -g)" ...
  • Dockerfile のベスト プラクティス で説明されているように、イメージに正しい所有権を設定します。
  • 新しいボリュームは最初に使用されるときにイメージのフォルダーの所有権を引き継ぐため、データには名前付きボリュームを優先します。
  • SELinux を使用するシステムでは、バインド マウントに :z または :Z ラベルが必要な場合があります。

Linux コマンド のガイドで説明されているように、chmod 777 の誘惑を避けてください。

どれを使用するべきですか?

状況 使用する
データベースデータ 名前付きボリューム
ソースコードのライブ編集 バインドマウント
リポジトリからの構成ファイル 読み取り専用バインドマウント
コンテナ間でのデータの共有 名前付きボリューム
一時キャッシュまたはスクラッチ ファイル tmpfs
使い捨てテストデータベース tmpfs、またはマウントなし
本番環境のアプリケーションコード イメージに組み込む

最後の行が重要です。運用環境では、コードはイメージに含まれるため、テストしたものが実行されます。クラスターでは、永続ボリュームを介してデータ ストレージが再び異なる動作をします。これについては、広範な Kubernetes ドキュメントで説明されています。私たちのDocker 対 Kubernetesガイドでは、この 2 つがどのように関係するかを説明しています。

よくある間違い

  • 間違ったパスにマウントしています。 データはまだコンテナ層に存在しており、後で消えます。
  • 気軽に down -v 実行しています。 これにより、名前付きボリュームが削除されます。
  • -v での相対パスの使用。 -v data:/x のような形式では、フォルダー マッピングではなくボリュームが作成されます。
  • 書き込み可能なバインド マウントにシークレットを配置します。 シークレットを読み取り専用でマウントするか、シークレット機能を使用します。
  • 2 つのデータベース コンテナが 1 つのボリュームを指すようにします。 これにより、データが破損する可能性があります。
  • バックアップがありません。 ボリュームはバックアップではありません。同じディスク上に存在します。

まとめ

経験則は短く、データには名前付きボリューム、編集中のコードにはバインド マウント、存続すべきではないものには tmpfs を使用します。使い捨てデータベースで試してください。名前付きボリュームを作成し、行を追加し、コンテナーを削除して、新しいボリュームを開始し、行が残っていることを確認します。そして、必要になる前にバックアップと復元を練習してください。

よくある質問

Docker ボリュームとバインド マウントの違いは何ですか?

ボリュームは Docker によって管理され、独自の領域に保存されます。バインド マウントは、制御する特定のホスト パスをコンテナに直接マッピングします。

コンテナを停止するとデータは削除されますか?

いいえ。書き込み可能層のデータは、停止および再起動後も存続します。コンテナーがボリュームまたはバインド マウントに保存されていない限り、コンテナーが削除されると、この情報は失われます。

Docker ボリュームは Docker Compose ダウン後も保持されますか?

はい、名前付きボリュームは docker compose down 後も残ります。 -v フラグを追加すると、それらに含まれるデータも含めて削除されます。

Docker ボリュームはどこに保存されますか?

Linux では、通常は /var/lib/docker/volumes の下にあります。 Docker Desktop では、仮想マシン内に存在します。 docker volume Inspection を使用して場所を確認します。

複数のコンテナでボリュームを共有できますか?

はい、複数のコンテナが 1 つのボリュームをマウントできます。アプリケーションは同時アクセスを安全に処理する必要があり、データベースは通常、この方法でデータ ファイルを共有すべきではありません。

学び続ける

Stack Quoraと連携する

テスト、WordPress、または SEO についてサポートが必要ですか?

私たちは、チームがより優れたソフトウェアを出荷し、サイトを成長させるのを支援します。あなたが取り組んでいることを教えてください。明確な次のステップを提案します。

読み続けてください

詳しいガイドはこちら テスト、AI、最新の開発

この記事は気に入りましたか?トピックを選択して、最新のチュートリアルに直接アクセスしてください。

人工知能

AI 幻覚の説明: 言語モデルが物事をでっち上げる理由とそれを軽減する方法

AI 幻覚について説明しました。幻覚とは何か、言語モデルが幻覚を生成する理由、一般的な種類、グラウンディングとプロンプトで幻覚を軽減する方法、そして私たちが実行した簡単なチェックです。

記事を読む →
DevOps

環境変数の説明: .env ファイル、シークレット、および設定が正しく行われている

実行した Python の例を使用して環境変数について説明します。環境変数の読み取りと設定、すべての値が文字列である理由、.env ファイル、プロセスの継承、シークレット、検証について説明します。

記事を読む →
ソフトウェア開発

API レート制限の説明: アルゴリズム、ヘッダー、および 429 エラーの処理

API レート制限については、実行したシミュレーションで説明します。トークン バケット、固定ウィンドウ、スライディング ウィンドウ、429 応答、レート制限ヘッダー、バックオフによる再試行、およびテスト制限です。

記事を読む →
テスト自動化

Python でのモッキング:unittest.mock、patch、およびテストを嘘にする間違い

Python でのunittest.mockによるモック、テスト済み: モックとreturn_value、side_effect、名前が使用されている場所のパッチ、仕様と自動仕様、日付のモック、およびよくある間違い。

記事を読む →
ソフトウェアテスト

コードカバレッジの説明: 回線カバレッジとブランチカバレッジ、および 100% の実際の意味

実際のcoverage.pyの実行でコードカバレッジを説明: 行、分岐、条件のカバレッジ、レポートの読み取り、100%のカバレッジでもバグを見逃す可能性がある理由、および賢明なターゲット。

記事を読む →
データベースとSQL

SQL における DELETE、TRUNCATE、DROP: 違い、ロールバック、およびそれぞれをいつ使用するか

DELETE、TRUNCATE、DROP について、テスト済み SQL を使用して説明します。それぞれの削除内容、ロールバック、トリガー、ID リセット、速度、PostgreSQL、MySQL、SQL Server、SQLite の違いについて説明します。

記事を読む →
データベースとSQL

SQL ビューの説明: 作成、使用、落とし穴の回避、例を示します

SQL ビューについて、実行したクエリとともに説明しました。ビューの作成、ライブ結果、列の非表示、パフォーマンス、更新可能なビューと具体化されたビュー、壊れた依存関係、ベスト プラクティスについて説明します。

記事を読む →
ソフトウェア開発

TypeScript インターフェイスと型: 実際の違い、コンパイラでテスト

TypeScript インターフェイスと型、実際のコンパイラでチェック: 両方でできること、片方だけでできること、宣言のマージ、拡張と交差、および従うべき簡単なルール。

記事を読む →
ソフトウェア開発

Python *args と **kwargs の説明: 柔軟な関数と明確な例

Python の *args と **kwargs について、実行したコードで説明しました。パッキングとアンパッキング、パラメーターの順序、キーワードのみの引数と位置のみの引数、デコレーター、一般的なエラーです。

記事を読む →
ソフトウェア開発

Python Lambda 関数: 構文、実際の用途、および使用すべきでない場合

Python のラムダ関数について、実行したコードとともに説明します。構文、キーによるソート、マップとフィルター、クロージャー、遅延バインディング トラップ、通常の def がより適切な選択である場合。

記事を読む →
人工知能

AIエージェントとは何ですか?シンプルなエージェント ループを実行できる仕組み

AIエージェントとは何ですか?エージェント ループ、ツール、メモリ、ガードレール、実行した小さな Python ループ、実際のリスク、およびシンプルなチャットボットがより良い選択である場合についてのわかりやすいガイドです。

記事を読む →
DevOps

モニタリングと可観測性: ログ、メトリクス、トレースによる本当の違い

モニタリングと可観測性について説明: 既知および未知の障害、ログ、メトリクスとトレース、チェックアウト インシデントのウォークスルー、ゴールデン シグナル、OpenTelemetry、および便利なアラート。

記事を読む →
DevOps

Docker ボリュームとバインド マウント: コンテナ データを正しい方法で保持する

Docker ボリュームとバインド マウントについて説明します。コンテナ データが消える理由、名前付きボリューム、バインド マウント、tmpfs、Compose の例、バックアップ、アクセス許可、およびそれぞれをいつ使用するかについて説明します。

記事を読む →
テスト自動化

TDD と BDD: 主な違い、1 つの機能が両方の方法で構築され、それぞれをいつ使用するか

TDD と BDD は、両方の方法で構築された 1 つの割引機能で説明されています。実行したコードによるレッド-グリーン-リファクタリング、Given-When-Then シナリオ、ツール、トレードオフ、およびそれぞれをいつ使用するかです。

記事を読む →
ソフトウェア開発

Git mergeとrebaseの違い:例と使い分け

Git mergeとrebaseの違いを、実際のログ出力、比較表、rebaseの黄金律、安全なチームワークフローで解説します。

記事を読む →
ソフトウェア開発

Pythonのリスト内包表記:構文・例・使うべきでない場面

Pythonのリスト内包表記を解説:構文、フィルタ、if-else、ネストしたループ、実測した処理時間、そして通常のforループの方が良い場面。

記事を読む →
データベースとSQL

SQL JOINを例で解説(Inner・Left・Right・Full)

サンプルのテーブルとクエリでSQL JOINを順に解説。INNER、LEFT、RIGHT、FULL、CROSS、SELFに加え、よくある間違いとパフォーマンスのコツも紹介します。

記事を読む →