哈囉,大家好!歡迎來到 Docker 的第六天!
在昨天的 Day 5 中,我們已經學會了如何透過 Dockerfile
來建置一個客製化的 Image。
但接著會遇到一個很現實、也極度重要的問題:當應用程式在容器中產生資料(例如日誌、使用者上傳的檔案、資料庫內容),容器刪掉後,這些資料會不會跟著消失?
答案是:預設情況下,會的!
今天,我們就要來正面對決這個問題,透過 Docker 提供的兩種最核心的資料管理方式,確保我們的資料安全無虞:
要解決問題,得先理解問題的根源。容器預設的檔案系統是短暫的 (ephemeral)。
當你基於一個 Image 啟動一個容器時,Docker 的運作模式是這樣的:
如圖所示,Docker 會在 Image 原本那一疊唯讀的圖層之上,再疊加一個輕薄的可寫層 (Writable Layer)。所有在容器運行期間發生的檔案變更——無論是新增檔案、更新資料庫、寫入日誌——都只存在於這個可寫層中。
這個設計非常巧妙,它確保了底下的 Image 永遠保持乾淨、不可變。但是,這也帶來了一個致命的後果:
一旦該容器被刪除 (docker rm),這個可寫層也會跟著一起被永久銷毀 → 資料全都不見了!
這對於任何需要保存狀態的應用程式來說,都是不可接受的。所以我們需要一個方式,讓資料可以「活在容器外面」,將其生命週期與容器脫鉤,才能長久保存。
為了解決上述問題,Docker 官方給出的最佳實踐,就是使用 Volume (卷)。
官方文件說得很清楚:
Volumes are the preferred mechanism for persisting data generated by and used by Docker containers.
(對於持久化由 Docker 容器產生和使用的資料,Volume 是首選的機制。)
你可以把 Volume 想成:「一個由 Docker 幫你代管的、專為容器設計的外接式硬碟。」
它的特色如下:
/var/lib/docker/volumes/
) 幫你建立並管理它。我們不需要關心它到底存在哪裡,只需要透過名稱來使用它即可。讓我們來看看如何為一個資料庫容器掛載 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-postgres
和 docker rm my-postgres
,pg-data
這個 Volume 依然靜靜地躺在 Docker 的管理區,等待下一個容器來使用它。
另一種將主機檔案掛載進容器的方式是 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.
(一個綁定掛載涉及將主機上的一個檔案或目錄,掛載到容器中。該檔案或目錄由其在主機上的絕對路徑來引用。)
它的特色如下:
# -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
目錄。這樣你在電腦上改程式碼,存檔後,容器馬上就能看到變化。
特性 | Volume (卷) | Bind Mount (綁定掛載) |
---|---|---|
管理者 | Docker | 使用者 |
主機位置 | Docker 的指定區域 | 使用者自訂的任意路徑 |
主要用途 | 生產環境的資料持久化 | 開發環境的程式碼同步 |
初始化 | Volume 空時,可自動複製 Image 內容 | 主機內容會直接覆蓋容器路徑 |
簡單選擇原則:
除了 Volume 和 Bind Mount,Docker 還有第三種掛載方式:tmpfs 掛載。
它不會將資料存在硬碟上,而是直接放在主機的記憶體 (RAM) 裡。
(先知道有這個選項就好,不用急著用)
今天,我們掌握了管理容器儲存資料的技能:
學會這個技巧後,你就能充滿信心地建構「有狀態 (Stateful)」的應用程式,再也不怕容器刪掉就造成資料遺失。然而,當應用越來越複雜(例如一個 Node.js 容器 + 一個 PostgreSQL 容器),我們會發現 docker run
指令變得超長超難記,還要手動處理容器之間的網路連線...
明天的我們要來學習 Docker Compose,讓你告別冗長的指令,用一個 compose.yaml
檔案,定義和管理你的多容器應用。明天見 !