iT邦幫忙

2025 iThome 鐵人賽

DAY 6
0
Cloud Native

從 Docker 到 K8s:我的 30 天雲原生筆記系列 第 6

Day 6: 管理容器資料:深入 Volumes 與 Bind Mounts

  • 分享至 

  • xImage
  •  

哈囉,大家好!歡迎來到 Docker 的第六天!

在昨天的 Day 5 中,我們已經學會了如何透過 Dockerfile 來建置一個客製化的 Image。

但接著會遇到一個很現實、也極度重要的問題:當應用程式在容器中產生資料(例如日誌、使用者上傳的檔案、資料庫內容),容器刪掉後,這些資料會不會跟著消失?

答案是:預設情況下,會的!

今天,我們就要來正面對決這個問題,透過 Docker 提供的兩種最核心的資料管理方式,確保我們的資料安全無虞:

  1. Volume (卷)
  2. Bind Mount (綁定掛載)

Part 1:問題的根源 — 為什麼容器內的檔案會消失?

要解決問題,得先理解問題的根源。容器預設的檔案系統是短暫的 (ephemeral)

當你基於一個 Image 啟動一個容器時,Docker 的運作模式是這樣的:

https://ithelp.ithome.com.tw/upload/images/20250913/20178656RkheFgWr8M.png

如圖所示,Docker 會在 Image 原本那一疊唯讀的圖層之上,再疊加一個輕薄的可寫層 (Writable Layer)。所有在容器運行期間發生的檔案變更——無論是新增檔案、更新資料庫、寫入日誌——都只存在於這個可寫層中。

這個設計非常巧妙,它確保了底下的 Image 永遠保持乾淨、不可變。但是,這也帶來了一個致命的後果:

一旦該容器被刪除 (docker rm),這個可寫層也會跟著一起被永久銷毀 → 資料全都不見了!

這對於任何需要保存狀態的應用程式來說,都是不可接受的。所以我們需要一個方式,讓資料可以「活在容器外面」,將其生命週期與容器脫鉤,才能長久保存。

Part 2:資料持久化的首選 — Volume (卷)

為了解決上述問題,Docker 官方給出的最佳實踐,就是使用 Volume (卷)

官方文件說得很清楚:

Volumes are the preferred mechanism for persisting data generated by and used by Docker containers.
(對於持久化由 Docker 容器產生和使用的資料,Volume 是首選的機制。)

你可以把 Volume 想成:「一個由 Docker 幫你代管的、專為容器設計的外接式硬碟。」

它的特色如下:

  • 由 Docker 管理:你只需要為 Volume 取一個名字,Docker 會自動在主機的一個特定目錄下 (在 Linux 上通常是 /var/lib/docker/volumes/) 幫你建立並管理它。我們不需要關心它到底存在哪裡,只需要透過名稱來使用它即可。
  • 獨立於容器:這是最關鍵的一點。容器被刪除後,由 Docker 管理的 Volume 依然會被保留下來,裡面的資料完好無損。
  • 跨平台與高效能:Docker 會處理好在不同作業系統(Windows, macOS, Linux)上的實現細節,確保 Volume 的 I/O 效能最佳化。

https://ithelp.ithome.com.tw/upload/images/20250913/20178656B4eV5FuMme.png

實戰演練:用 Volume 保存 PostgreSQL 資料

讓我們來看看如何為一個資料庫容器掛載 Volume。

# -v 或 --volume 參數用來掛載 Volume
# 格式是 <Volume名稱>:<容器內的路徑>
docker run -d --name my-postgres \\
  -v pg-data:/var/lib/postgresql/data \\
  -e POSTGRES_PASSWORD=mysecretpassword \\
  postgres:14-alpine

這條指令執行時,Docker 會檢查是否存在一個名為 pg-data 的 Volume。如果沒有,它會自動建立一個,然後將這個 Volume 掛載到容器內部的 /var/lib/postgresql/data 目錄(這是 PostgreSQL 預設的資料儲存路徑)。

現在,即使你執行 docker stop my-postgresdocker rm my-postgrespg-data 這個 Volume 依然靜靜地躺在 Docker 的管理區,等待下一個容器來使用它。

Part 3:開發者最愛 — Bind Mount (綁定掛載)

另一種將主機檔案掛載進容器的方式是 Bind Mount

如果說 Volume 是「請 Docker 幫你管理的外接硬碟」,那 Bind Mount 就是:「直接把自己電腦的某個資料夾,借給容器使用。」

官方文件是這樣定義的:

a bind mount involves mounting a file or directory from the host machine into a container. The file or directory is referenced by its absolute path on the host machine.
(一個綁定掛載涉及將主機上的一個檔案或目錄,掛載到容器中。該檔案或目錄由其在主機上的絕對路徑來引用。)

它的特色如下:

  • 完全由使用者控制:你必須提供一個主機上已經存在的、絕對的路徑
  • 即時雙向同步:這是一個鏡像般的連結。你在本機用 VS Code 修改程式碼,容器內的檔案會立刻更新。反之,如果在容器內修改了這個檔案,你本機的檔案也會跟著變動。
  • 主要用在開發環境:正因為這種即時同步的特性,它非常適合用來掛載程式碼,實現熱重載 (Hot-Reload)。但 不建議用在生產環境,因為它會讓容器與主機的檔案系統結構產生緊密耦合,不夠穩定且難以維護。

實戰演練:同步程式碼到 Node.js 容器

# -v 參數同樣可用於 Bind Mount
# 格式是 <主機上的絕對路徑>:<容器內的路徑>
docker run -d -p 8080:3000 \
  --name my-dev-app \
  -v "$(pwd):/app" \
  your-docker-id/my-node-app:1.0

本機的專案目錄 ($(pwd) 會取得當前終端機所在位置的絕對路徑) 會直接同步到容器的 /app 目錄。這樣你在電腦上改程式碼,存檔後,容器馬上就能看到變化。

Part 4:一張圖看懂 Volume vs Bind Mount

https://ithelp.ithome.com.tw/upload/images/20250913/20178656Hn4SAH7uma.png

Part 5:如何選擇?

特性 Volume (卷) Bind Mount (綁定掛載)
管理者 Docker 使用者
主機位置 Docker 的指定區域 使用者自訂的任意路徑
主要用途 生產環境的資料持久化 開發環境的程式碼同步
初始化 Volume 空時,可自動複製 Image 內容 主機內容會直接覆蓋容器路徑

簡單選擇原則

  • 當你需要一個可靠的地方來保存應用程式產生的資料(資料庫、用戶上傳內容),請使用 Volume
  • 當你需要在開發時,將本機的程式碼即時同步到容器中進行測試,請使用 Bind Mount

Part 6:進階小知識 — tmpfs mounts

除了 Volume 和 Bind Mount,Docker 還有第三種掛載方式:tmpfs 掛載

它不會將資料存在硬碟上,而是直接放在主機的記憶體 (RAM) 裡。

  • 優點:讀寫速度快如閃電。
  • 缺點:非持久性。主機重啟或容器停止,資料就會永久消失
  • 用途:適合用來暫存一些不需要保存的、高度敏感的資訊(例如 session 資料或臨時密鑰),或者需要極高 I/O 效能的暫存檔。

(先知道有這個選項就好,不用急著用)

結論

今天,我們掌握了管理容器儲存資料的技能:

  • 容器內檔案系統是短暫的,刪掉容器資料就會不見。
  • Volume:由 Docker 管理,是生產環境資料持久化的最佳實踐。
  • Bind Mount:由使用者控制,是開發環境同步程式碼的方法。

學會這個技巧後,你就能充滿信心地建構「有狀態 (Stateful)」的應用程式,再也不怕容器刪掉就造成資料遺失。然而,當應用越來越複雜(例如一個 Node.js 容器 + 一個 PostgreSQL 容器),我們會發現 docker run 指令變得超長超難記,還要手動處理容器之間的網路連線...

明天的我們要來學習 Docker Compose,讓你告別冗長的指令,用一個 compose.yaml 檔案,定義和管理你的多容器應用。明天見 !


上一篇
Day 5: Dockerfile:為你的應用程式量身打造 Image
系列文
從 Docker 到 K8s:我的 30 天雲原生筆記6
圖片
  熱門推薦
圖片
{{ item.channelVendor }} | {{ item.webinarstarted }} |
{{ formatDate(item.duration) }}
直播中

尚未有邦友留言

立即登入留言