Skip to main content

第19章:ボリューム権限(UID/GID)とDBデータの守り方🗃️🛡️

この章はひとことで言うと―― **「DBデータの“宝箱”を、権限ミスで壊さない💥&消さない🧨」**ための回です😄✨


1) まず結論:DBデータは“基本 named volume”で守るのが最強💪🧱

Docker公式でも、コンテナが生成・利用する永続データは volume を推奨しています(ホストOS依存が減って、Dockerが管理できるから)(Docker Documentation) Composeでも、top-level volumes に named volume を定義して使い回すのが王道です(Docker Documentation)

なので迷ったらこう👇

  • DBのデータnamed volume(まずこれ)
  • ⚠️ bind mount(ホストのフォルダ直刺し) → “必要な時だけ”+“場所を選ぶ”

2) UID/GIDってなに?(超ざっくり)🪪👤

Linuxではファイルに「持ち主」がいて、持ち主は **UID(ユーザーID)/ GID(グループID)**で決まります👀 DBコンテナは、データフォルダに 書き込みできないと起動できません(初期化で詰む)😇💥

つまり…

「コンテナ内のプロセスのUID/GID」と「データフォルダの所有者」がズレると死ぬ これが“権限事故”の正体です🧯


3) Windows + Docker Desktopでハマりやすいポイント🪤🪟

bind mount で **Windows側のフォルダ(例: C:\〜)**をDBデータ置き場にすると、速度だけじゃなく権限・ファイルシステム特性でも事故りやすいです💣

Docker公式のWSLベストプラクティスでも、bind mountするデータはLinuxファイルシステム側(WSL内)に置くのが推奨されています(Docker Documentation) MicrosoftのWSL公式ドキュメントも、性能面ではWSL側のファイルシステムに置くのが速いと明言しています(Microsoft Learn)

さらに、WindowsフォルダをMySQLのデータディレクトリにマウントして初期化で権限エラーになる例も報告されています(まさに“権限・FS差”で詰むパターン)(GitHub)


4) 「消していいデータ/ダメなデータ」仕分け🧠📦

ここ、設計初心者ほど“いきなり全部同じ場所”に置きがちです😂

絶対消しちゃダメ😱🧊

  • DBの永続データ(例:Postgresのクラスタ、MySQLのdatadir)

消えても復元できる(けど面倒)😇

  • 生成物キャッシュ、テンポラリ、ログ(※ただし監査ログは別)

👉 DBデータは他と混ぜない(巻き添え削除が起きるから)🧯✨


5) DB別:正しい“マウント先”を間違えない📌(ここ超重要)

PostgreSQL:Postgres 18+ でマウント先が変わった⚠️

Docker公式(Docker Hubの説明)で、PostgreSQL 18 以降は PGDATA がバージョン別になり、VOLUME/var/lib/postgresql に変わったと明記されています(Docker Hub) さらに、PostgreSQL 17 以下は /var/lib/postgresql/data にマウントしないと永続化がズレて匿名ボリュームに書かれてしまう注意まで書かれています(Docker Hub)

つまり、“どこにマウントするか”をバージョンで変える必要があるってことです😵‍💫

MySQL:データ保存は「Docker管理」か「ホスト側で権限を責任持つ」か

MySQL公式イメージも「データの保存方法は複数あるが、ホストにディレクトリを作ってマウントするなら ディレクトリの存在・権限などをちゃんと面倒見てね」と説明しています(Docker Hub)


6) 実践:Composeで“事故りにくい”DB永続化テンプレ📦✨

A. Postgres 18+(おすすめ:まずこれ)🐘✅

  • named volume
  • マウント先は /var/lib/postgresql(18+の推奨)(Docker Hub)
  • イメージは major まで固定postgres:18 みたいに)←これで勝手に18へ上がる事故を防ぐ🧯
services:
db:
image: postgres:18
restart: unless-stopped
environment:
POSTGRES_PASSWORD: example-password
POSTGRES_DB: appdb
POSTGRES_USER: appuser
volumes:
- pgdata:/var/lib/postgresql

volumes:
pgdata:

B. Postgres 17以下を使うなら🐘🧷

  • マウント先は /var/lib/postgresql/data(17以下の重要注意)(Docker Hub)
services:
db:
image: postgres:17
restart: unless-stopped
environment:
POSTGRES_PASSWORD: example-password
volumes:
- pgdata:/var/lib/postgresql/data

volumes:
pgdata:

C. MySQL(基本は named volume でOK)🐬✅

services:
db:
image: mysql:8.4
restart: unless-stopped
environment:
MYSQL_ROOT_PASSWORD: example-root
MYSQL_DATABASE: appdb
MYSQL_USER: appuser
MYSQL_PASSWORD: example-pass
volumes:
- mysqldata:/var/lib/mysql

volumes:
mysqldata:

7) “権限が合ってるか”をその場で確認する🔍👀

動いてるDBコンテナに入って、**データディレクトリの所有者(数字)**を見るのが早いです🏃‍♂️💨

例:Postgres(コンテナ名が db の場合)

docker compose exec db sh -lc "ls -ldn /var/lib/postgresql /var/lib/postgresql/* 2>/dev/null || true"
  • ls -ldnUID/GIDを数字で表示してくれます(名前解決に依存しない)👍

8) bind mountしたい場合の“安全なやり方”🧰🧷

「DBの実データをホスト側ツールで直接触りたい」みたいな理由で bind mount したくなる時、あります😅 その場合の鉄則👇

✅ 置き場所は “WSL内のLinuxファイルシステム”にする

Docker公式のWSLベストプラクティスがこの方針です(Docker Documentation) (性能も安定性も良くなる)

✅ コンテナ内ユーザーのUID/GIDを“調べてから”合わせる

DBイメージによって微妙に違うことがあるので、決め打ちより「確認→合わせる」が安全です🧯

例:Postgresの postgres ユーザーのUID/GIDを確認

docker run --rm postgres:18 sh -lc "id -u postgres; id -g postgres"

出てきた数字が仮に 999999 だったら、WSL側でフォルダを作って所有者を合わせる👇

mkdir -p ~/docker-data/postgres18
sudo chown -R 999:999 ~/docker-data/postgres18

9) “任意UIDで動かす”は最終手段(でも公式の逃げ道はある)🧪🧯

「自分のUIDでDBを動かしたい!」ってやると、初期化の initdb が“そのUIDが /etc/passwd に存在しない”と失敗するケースがあります😇 Docker HubのPostgres公式説明でも、数値UIDだけだと initdb がユーザーを引けず失敗する例と、回避策(nss_wrapper / /etc/passwd のbind mount / 初期化とchown分離)が載っています(Docker Hub)

なのでこの章のおすすめ方針は👇

  • ✅ まずは 公式のデフォルト運用(named volume)
  • ⚠️ どうしても必要になったら、公式の回避策を“そのまま”使う(自己流にしない)🧯

10) 演習(15分)⏱️📝

演習1:安全テンプレでDBを立てる🎮

  1. 上の「Postgres 18+」Composeをコピペ

  2. 起動👇

    docker compose up -d
  3. データが volume に載ってるか確認👇

    docker volume ls
    docker volume inspect <ボリューム名>

演習2:うっかり消し事故を防ぐ🧨→🧯

  • docker compose downボリュームは消さない
  • ⚠️ docker compose down -vボリュームを消す(=DB全消し) 😱

自分のチーム/自分ルールとして、-v は封印コマンドにしておくのが安全です🔒✨


11) AI拡張を使う人の“最重要チェック”🤖✅

GitHub Copilot や OpenAI 系のAIツールにComposeを書かせると、たまにこういう事故が混ざります😂

  • 「Postgresのマウント先が古いまま」→ 18+で起動失敗/データ迷子
  • 「image: postgres(バージョン固定なし)」→ いつの間にかメジャーが上がる
  • 「bind mount を C:\… にしてる」→ 権限・FS差でハマる

AIの出力は、最低でもここだけ目視チェック👀✨

  • DBイメージは major 固定
  • マウント先はそのDB/バージョンの推奨(Postgres 18+は特に)(Docker Hub)
  • DBデータはまず named volume(Docker Documentation)

まとめ🎉

  • DBデータは named volume が基本(最小事故ルート)(Docker Documentation)
  • bind mount するなら WSL内に置く(公式推奨)(Docker Documentation)
  • Postgresは 17以下と18+でマウント先が違うのが超重要ポイント(Docker Hub)
  • MySQLもホスト側に置くなら 権限は自分が責任持つ(Docker Hub)

次の章(第20章)は「configs / env / files の整理術」だから、**“設定と秘密とただの値”を事故らず仕分ける🧰✨**流れで繋げるとめちゃ気持ちいいです😄