データを永続化する - docker volume / bind mount
データ永続化の基本。Docker が管理する volume と、ホスト側の任意パスを使う bind mount の違い、`:ro` / `:z` / `:Z` オプション、パーミッション問題の対処を整理する。
概念図
構文
docker volume COMMAND
# COMMAND: create, ls, inspect, rm, prune
docker run -v NAME:/path IMAGE # named volume
docker run -v /host/path:/container IMAGE # bind mount実例
名前付きボリュームを作成
docker volume create pgdata名前付きボリュームで Postgres のデータを永続化
docker run -v pgdata:/var/lib/postgresql/data -e POSTGRES_PASSWORD=x postgres:16カレントディレクトリを読み取り専用で bind mount
docker run -v "$(pwd)":/app:ro node:20 node /app/index.jsvolume と bind mount
名前付き volume は Docker が管理する領域(Linux では /var/lib/docker/volumes/<name>/_data)に実体が置かれる。
docker volume create、docker volume ls、docker volume rm で管理し、--volumes-from で他コンテナから共有することもできる。
本番でデータベースの永続化に使うなら第一候補。
bind mount はホストの任意のパスをコンテナの任意のパスにマウントする。
-v /home/user/app:/app や -v "$(pwd)":/app のように書く。
ホスト側の編集が即座にコンテナに反映されるため、開発時のソース同期に最適。
一方、ホストのディレクトリ構造やパーミッションに依存するため、本番や他環境に持ち込むと壊れやすい。
docker volume create pgdata
docker run -d --name db -v pgdata:/var/lib/postgresql/data postgres:16
# bind mount for dev
docker run --rm -v "$(pwd)":/app -w /app node:20 npm test`:ro` / `:z` / `:Z` オプション
マウント指定の末尾にオプションを付けられる。
:ro(read-only)はコンテナ側から書き込みを禁止する。
設定ファイルや静的アセットを渡すときは必ず付ける。
書き込み禁止にしておけばコンテナ内のプロセスが誤って上書きする事故を防げる。
:z と :Z は SELinux が有効な環境(RHEL / Fedora / Rocky / 一部の CentOS Stream など)で必要になる。
:z は共有ラベル(複数コンテナから読み書き可)、:Z はプライベートラベル(そのコンテナ専用)を付与する。
SELinux 有効な環境で bind mount して Permission denied が出たら、ほぼこれで解決する。
Ubuntu / Debian デフォルトや Docker Desktop では不要。
docker run --rm -v "$(pwd)/nginx.conf":/etc/nginx/nginx.conf:ro nginx
# SELinux host
docker run -v /srv/data:/data:Z myappデータ永続化のパターン
データベースの永続化では名前付き volume がほぼ唯一の正解。
bind mount はホスト OS のファイルシステム(特に macOS / Windows)とデータベースの書き込みパターンの相性が悪く、性能低下やファイル破損の原因になる。
バックアップは docker run --rm -v pgdata:/data -v "$(pwd)":/backup alpine tar czf /backup/pg.tgz /data のような使い捨てコンテナで取得する。
ログやキャッシュはそもそも永続化が必要かを見直す。
ログは stdout に流して log driver に任せる、キャッシュは名前付き volume にして prune で明示的に消す、などの整理ができれば、コンテナの使い捨て性が保たれる。
UID / GID のズレで書き込めない場合は、Dockerfile で USER 1000:1000 を指定するか、docker run --user "$(id -u):$(id -g)" でホストのユーザーに揃える。
# backup a named volume
docker run --rm \
-v pgdata:/data \
-v "$(pwd)":/backup \
alpine tar czf /backup/pg-$(date +%F).tgz -C /data .関連トピック
docker run- イメージから新しいコンテナを起動するコマンド。`-d` でバックグラウンド化、`-p` でポート公開、`-v` でボリュームマウント、`--name` で名前付けなど、日常的に使うオプションを押さえておく。 docker network- コンテナのネットワーク管理。bridge / host / none / user-defined の 4 種類を理解し、user-defined bridge でコンテナ名による名前解決を使うのが基本。 docker images / docker system prune- ローカルのイメージ一覧と、使われていないリソースの一括削除。ビルドを繰り返していると数十 GB に膨らむので、定期的に掃除する。 