Docker Volume bind mount
容器一刪,寫進它「可寫層」的東西就沒了。要留住資料,得把資料放到容器之外。這頁把四種落點講清楚。撥下面四種模式,看資料實際落在哪、容器刪掉還在不在:
不掛載時資料在容器可寫層
容器在唯讀映像層之上有一層「可寫層」。沒掛載時,寫進去的檔案都落在這層,走 copy-on-write(CoW):改一個既有檔案時,先把整個檔案從唯讀層複製到可寫層,再改副本。
- 改一個 1 GB 檔案的一個 byte,也要先整檔複製,寫入密集會明顯變慢。
- 可寫層跟著容器生命週期,
docker rm 就全沒。
所以資料庫、需要保留的資料、大量 I/O 的工作負載,都不該只待在容器可寫層。
三種掛載比較
| 維度 | Volume | Bind mount | tmpfs |
|---|
| 定義 | Docker 管理的具名儲存區 | 主機路徑直接映射進容器 | 存於主機記憶體,不落磁碟 |
| 資料存哪 | /var/lib/docker/volumes/<name>/_data | 你指定的主機路徑 | 主機 RAM |
| 容器刪後資料在? | 在 | 在(主機上) | 不在 |
| 跨容器共享 | 可 | 可 | 不可 |
| 效能(Linux) | 等同主機檔案系統原生 | 等同主機原生 | 最快(RAM I/O) |
| 適用 | 資料庫、持久化資料、備份遷移 | 開發同步程式碼、注入設定檔 | 敏感憑證、暫存快取(僅限 Linux) |
具名 volume 的實體位置
Linux 上:
docker volume inspect my-vol
# "Mountpoint": "/var/lib/docker/volumes/my-vol/_data"
WSL 2 後端下,這條路徑在 docker-desktop-data 這個 WSL 虛擬機裡,不在 Windows 檔案系統,從檔案總管直接點不進去。要讀 volume 內容:
docker run --rm -v my-vol:/data alpine ls /data # 用容器掛上去看
bind mount:-v 與 --mount
兩種語法做同一件事,但 --mount 語義明確、官方建議優先:
# -v:簡短,但歧義多
docker run -v /host/data:/app/data:ro app
# --mount:明確指定 type,杜絕歧義
docker run --mount type=bind,source=/host/data,target=/app/data,readonly app
| 行為 | --mount type=bind | -v |
|---|
| 主機路徑不存在 | 報錯,拒絕執行 | 自動建一個空目錄 |
相對路徑(./data) | 當 bind mount | 可能被當成具名 volume 名稱 |
-v 的相對路徑雷:-v mydata:/app/data(無斜線開頭)會被當成「建一個叫 mydata 的具名 volume」,不是 bind mount。要確定是 bind mount,用絕對路徑或明確的 --mount type=bind。
匿名 volume 與 Dockerfile VOLUME 的雷
-v 只給容器路徑、不給名稱,會建一個隨機 UUID 的匿名 volume。Dockerfile 的 VOLUME 指令在 docker run 時也會自動建匿名 volume 掛到那個路徑。
FROM node:20
WORKDIR /app
COPY . .
RUN npm install # node_modules 裝進映像層
VOLUME /app # 雷:run 時匿名 volume 掛上 /app,遮蔽掉 node_modules
docker run 時匿名 volume 掛到 /app,遮蔽掉容器層裡 npm install 裝好的 node_modules,應用就跑不起來。對策:VOLUME 別宣告在會被遮蔽的路徑,或乾脆不用 VOLUME,改在 docker run / Compose 顯式掛載。
容器不帶 --rm 刪掉後,匿名 volume 會殘留成 dangling volume,用 docker volume prune 清。
docker volume 指令
docker volume create my-vol
docker volume ls
docker volume inspect my-vol # 看 Mountpoint
docker volume rm my-vol
docker volume prune # 清未使用的 volume(預設只清匿名)
WSL 2 的掛載效能(重要)
高 I/O 的資料(程式碼、node_modules、資料庫檔)要放在 WSL 2 的 Linux 檔案系統再 bind mount,不要從 /mnt/c(Windows 路徑)掛載:
docker run -v ~/my-project:/sources app # 正確:WSL 2 Linux 檔案系統
docker run -v /mnt/c/Users/me/project:/sources app # 避免:跨 OS 邊界,慢
官方說明:從 Windows 檔案系統 bind mount 效能明顯較差,而且 inotify 事件只在 Linux 檔案系統上有效,掛 /mnt/c 會讓 hot reload(Vite、webpack、nodemon)收不到檔案變更而失效。高 I/O 場景優先用具名 volume 或從 WSL 2 Linux 側出發的 bind mount。
接下來
- 效能設定:
docker-desktop-data VHDX 怎麼看大小、搬移。
- Docker Compose:在 compose.yaml 裡掛 volume 與 bind mount。
官方參考:docs.docker.com/engine/storage