Skip to main content

第03章:事故る前に知る:マウントが「上書き」になる話🫠

この章はひとことで言うと… 「マウント=合体」じゃなくて、基本は“かぶせる(覆い隠す)” って感覚を作る章です🧠✨ これを知らないと、“昨日まで動いてたのに急に壊れた” が起きやすいです😇


3-1. まず結論:マウントすると「元の中身は見えなくなる」🫥

bind mount(ホストのフォルダをコンテナへ載せる)で、コンテナ側の既存フォルダにマウントすると そのフォルダに元から入ってたファイルは、マウント中は“隠れて”見えなくなります🫠 これが Docker 公式に明記されてます。(Docker Documentation)

しかも厄介なのが👇 「隠れてるだけ」だけど、コンテナの中から“取り外して元に戻す”みたいなことは基本できません(やるなら作り直し)💥(Docker Documentation)


3-2. 体験しよう:ファイルが“消えたように見える”ミニ実験🧪👀

やること:イメージの中に入ってたファイルが、bind mountで見えなくなるのを体験します。

Step A:デモ用イメージを作る📦

mkdir mount-accident-demo
cd mount-accident-demo

@'
FROM alpine:latest
RUN mkdir -p /app && echo "I am inside the IMAGE" > /app/in_image.txt
CMD ["sh", "-lc", "ls -la /app && echo '---' && cat /app/in_image.txt"]
'@ | Set-Content Dockerfile -Encoding UTF8

docker build -t mountdemo:1 .

Step B:マウントなしだと見える✅

docker run --rm mountdemo:1

期待:/app/in_image.txt が表示されます📄✨

Step C:空フォルダを /app に bind mount → “消える”😇

mkdir host-empty

docker run --rm --mount type=bind,source="$($PWD.Path)\host-empty",target=/app mountdemo:1

期待:/app空っぽ になります(=イメージ側の /app が隠れた)🫥

これが「マウントが上書き(に見える)」の正体です🫠 公式もこの挙動を “obscured(隠れる)” と説明してます。(Docker Documentation)


3-3. “volume”でも起きる?→ 起きる。でも挙動に差がある🧠

ここ、初心者が混乱しがちポイントです😂

  • bind mount:基本「覆い隠す」だけ(コンテナ側の元データは見えない)(Docker Documentation)

  • volume

    • すでに中身がある volumeをマウントすると、やっぱり覆い隠す🫥(Docker Documentation)
    • でも、空の volume を “元からファイルがあるコンテナのディレクトリ” にマウントすると、初回だけ中身が volume 側にコピーされるのがデフォルトです📦➡️📦(Docker Documentation)
    • コピーされたくないときは volume-nocopy があります🧷(Docker Documentation)

この「空 volume は最初にコピー」があるせいで、 “volume は隠れないっぽい?” みたいな誤解が起きます😇(実際は状況次第)


3-4. ありがちな事故シーン(TypeScript開発あるある)💥🧯

事故①:node_modules が“消えた”😱

よくある流れ👇

  1. イメージ作成時に npm ci して node_modules をコンテナに作った
  2. 開発で .:/app を bind mount
  3. ホスト側の .//app を丸ごと覆う
  4. 結果:コンテナ内の node_modules が見えず、Cannot find module ... 祭り🎆

👉 対策の基本:

  • 「アプリ本体」マウントと**「依存」**を分離する(依存は volume に逃がす)📦
  • もしくはホスト側にも node_modules を用意する(ただしOS差や重さで地獄になりやすい😇)

事故②:dist/(ビルド成果物)が見えなくなって「あれ?」🤔

イメージ内で dist/ を作っても、.:/app で覆うと ホストに dist/ が無い限り見えないです🫥 → つまり「ビルドしたのに動かない」って感じになります🫠

事故③:コンテナの重要フォルダを覆って即死💀

公式も“極端な例”として、/usr を bind mount で置き換えてコンテナが壊れる例を出してます😇(Docker Documentation) (やる人ほぼいないけど、“重要な場所にマウントすると壊れる”感覚づくりに大事)

事故④:--mount だとホスト側のフォルダが無いとエラー📛

--mount type=bindホスト側パスが無いとエラーになります。(Docker Documentation) 一方 -v だと勝手にディレクトリ作って進むことがあり、空フォルダができて“隠れ事故”が発生しやすいです🫠(Docker Documentation)

👉 なのでこの教材では --mount を優先がおすすめです(事故が早く発覚する)👍(Docker Documentation)


3-5. 事故を防ぐ「3つの鉄則」📌✨

鉄則1:マウント先は“空の場所”にする🧺

  • そのイメージに元から入ってる大事なファイルがある場所に、いきなり被せない🙅‍♂️

鉄則2:「依存」「生成物」「永続データ」を同じ場所に混ぜない🧃🍱

  • 例:/app に全部詰め込むと、マウントの1発で全部見えなくなりがち🫠
  • 分けると、事故の影響範囲が小さくなります👍

鉄則3:マウント状態を“確認してから”悩む🔎 「ファイル消えた!」の前に、まずこれ👇

  • docker inspect で Mounts を見る(どこがどこにマウントされてるか)🧠(Docker Documentation)

3-6. デバッグ手順:「どこが隠れてる?」を即特定する🕵️‍♂️

手順1:コンテナを起動(名前つける)🏷️

docker run -d --name mountcheck --mount type=bind,source="$($PWD.Path)\host-empty",target=/app mountdemo:1 sh -lc "sleep 9999"

手順2:マウントの事実を確認🔍

docker inspect mountcheck --format "{{json .Mounts}}"

公式も docker inspect の Mounts を見ろって言ってます✅(Docker Documentation)

手順3:中身を確認👀

docker exec -it mountcheck sh -lc "ls -la /app"

手順4:片付け🧹

docker rm -f mountcheck

3-7. AIに聞くなら:最短で原因に当てるプロンプト例🤖✨

「現象」→「構成」→「ログ」の順で渡すと当たりやすいです🎯 (秘密系は貼らないでね🔒)

原因候補を3つ出させる👇

Dockerでbind mountしたら、コンテナ内のファイルが消えたように見えます。
以下のコマンド/構成から、原因候補を優先度順に3つと、確認コマンドを提案して。

- 実行コマンド:
docker run ...(ここに貼る)
- 期待: (こうなるはず)
- 実際: (こうなった)

“隠れてるだけか?”を判定させる👇

これは「マウントが既存の内容をobscureしている」パターンかどうか判定して。
判定に必要な docker inspect の見るべき項目も教えて。

3-8. まとめ:この章で持ち帰る感覚🧠🎁

  • マウントは基本 “合体”じゃなくて“かぶせる” 🫥(Docker Documentation)
  • かぶせた結果、元の中身は 見えなくなる(戻すなら作り直しが基本)😇(Docker Documentation)
  • volume は 空なら初回コピーがある(ここが混乱ポイント)📦(Docker Documentation)
  • 迷ったら docker inspect の Mounts で事実確認🔎(Docker Documentation)

3-9. ミニ確認クイズ(1分)📝✨

  1. bind mount で /app に載せたら、イメージ内の /app はどうなる?🫥
  2. 「空の volume」を「中身があるディレクトリ」にマウントすると、初回に起きやすいことは?📦
  3. “ファイル消えた!”とき、最初に見るべきコマンドは?🔎

次の第4章では、この事故を避けやすい形で Compose で “データ箱(named volume)” を定義していきます📦🧩 「node_modules を volume に逃がす」みたいな鉄板パターンも、そこで気持ちよく整理しようね😎✨