8.1 資料卷
8.1.1 為什麼需要資料卷
容器的儲存層有一個關鍵問題:容器刪除後,資料就沒了。
flowchart LR
Run[容器執行] --> Write[寫入資料]
Write --> Delete[容器刪除]
Delete -->|資料都在容器 writable 層| Lost[DATA LOST! ❌]
資料卷 (Volume) 解決了這個問題,它的生命週期獨立於容器。
8.1.2 資料卷的屬性
| 屬性 | 說明 |
|---|---|
| 持久化 | 容器刪除後資料仍然保留 |
| 共享 | 多個容器可以掛載同一個資料卷 |
| 即時生效 | 對資料卷的修改立即可見 |
| 不影響映象 | 資料卷中的資料不會打包進映象 |
| 效能更好 | 繞過 UnionFS,直接讀寫 |
8.1.3 資料卷 vs 容器儲存層
容器儲存層:不推薦儲存重要資料
graph TD
subgraph Container [容器]
Writable[容器儲存層
Writable] Image[映象層
ReadOnly] Writable --- Image end Lifecycle[生命週期 = 容器生命週期] -.-> Container Delete[容器刪除] -->|導致| DataLost[資料丟失 ❌]
Writable] Image[映象層
ReadOnly] Writable --- Image end Lifecycle[生命週期 = 容器生命週期] -.-> Container Delete[容器刪除] -->|導致| DataLost[資料丟失 ❌]
資料卷:推薦
graph TD
subgraph Container [容器]
AppDir["/app/data"]
end
subgraph Volume [資料卷 my-data]
Data[持久化資料]
end
AppDir == 掛載 ==> Volume
Delete[容器刪除] -.->|不會影響| Volume
8.1.4 資料卷基本操作
建立資料卷
$ docker volume create my-vol
列出所有資料卷
$ docker volume ls
DRIVER VOLUME NAME
local my-vol
local postgres_data
local redis_data
檢視資料卷詳情
$ docker volume inspect my-vol
[
{
"CreatedAt": "2026-01-15T10:00:00Z",
"Driver": "local",
"Labels": {},
"Mountpoint": "/var/lib/docker/volumes/my-vol/_data",
"Name": "my-vol",
"Options": {},
"Scope": "local"
}
]
關鍵字段:
Mountpoint:資料卷在宿主機上的實際儲存位置Driver:儲存驅動 (預設 local,也可以用第三方驅動)
8.1.5 掛載資料卷
方式一:--mount:推薦
$ docker run -d \
--name web \
--mount source=my-vol,target=/usr/share/nginx/html \
nginx
引數說明:
| 引數 | 說明 |
|---|---|
source |
資料卷名稱 (不存在會自動建立) |
target |
容器內掛載路徑 |
readonly |
可選,只讀掛載 |
方式二:-v:簡寫
$ docker run -d \
--name web \
-v my-vol:/usr/share/nginx/html \
nginx
格式:-v 資料卷名:容器路徑[:選項]
兩種方式對比
| 屬性 | --mount | -v |
|---|---|---|
| 語法 | 鍵值對,更清晰 | 冒號分隔,更簡潔 |
| 資料卷 (Volume) 掛載行為 | 卷不存在會自動建立,與 -v 結果一致 |
卷不存在會自動建立 |
| 繫結掛載 (Bind Mount) 行為 | ⭐宿主機路徑不存在會報錯,不會自動建立 | 宿主機路徑不存在會 自動建立為目錄 |
| 推薦程度 | ✅ 推薦 (更明確安全,避免誤建立) | 常用 (更簡潔) |
提示:官方更推薦使用
--mount。除了語法格式可讀性更好之外,最重要的行為差異發生在 繫結掛載 (Bind Mount) 時:如果掛載的宿主機源路徑尚未存在,-v會擅自將其自動建立為一個空目錄;而--mount則會嚴格檢查並直接報錯。這能有效避免因路徑拼寫錯誤而在宿主機上留下垃圾目錄(以及導致的容器訪問空目錄問題)。而對於本節的 資料卷 (Volume) 掛載而言,兩者在目標指定的卷不存在時皆會自動建立卷,產生的結果是 完全一致 的。
只讀掛載
## --mount 方式
$ docker run -d \
--mount source=my-vol,target=/data,readonly \
nginx
## -v 方式
$ docker run -d \
-v my-vol:/data:ro \
nginx
8.1.6 使用場景範例
場景一:資料庫持久化
## 建立資料卷
$ docker volume create postgres_data
## 啟動 PostgreSQL,資料儲存在資料卷中
$ docker run -d \
--name postgres \
-e POSTGRES_PASSWORD=secret \
-v postgres_data:/var/lib/postgresql/data \
postgres:16 # 確保與環境相容的 PostgreSQL 版本
## 即使刪除容器,資料仍然保留
$ docker rm -f postgres
## 重新啟動,資料還在
$ docker run -d \
--name postgres \
-e POSTGRES_PASSWORD=secret \
-v postgres_data:/var/lib/postgresql/data \
postgres:16 # 確保與環境相容的 PostgreSQL 版本
場景二:多容器共享資料
## 建立共享資料卷
$ docker volume create shared-data
## 容器 A 寫入資料
$ docker run -d --name writer \
-v shared-data:/data \
alpine sh -c "while true; do date >> /data/log.txt; sleep 5; done"
## 容器 B 讀取資料
$ docker run --rm \
-v shared-data:/data \
alpine cat /data/log.txt
場景三:設定檔案持久化
## 將 nginx 設定儲存在資料卷中
$ docker run -d \
-v nginx-config:/etc/nginx/conf.d \
-v nginx-logs:/var/log/nginx \
-p 80:80 \
nginx
8.1.7 資料卷管理
刪除資料卷
## 刪除指定資料卷
$ docker volume rm my-vol
## 刪除容器時同時刪除資料卷
$ docker rm -v container_name
清理未使用的資料卷
## 檢視未被任何容器使用的資料卷
$ docker volume ls -f dangling=true
## 刪除所有未使用的資料卷
$ docker volume prune
## 強制刪除(不提示確認)
$ docker volume prune -f
⚠️ 注意:資料卷不會自動垃圾回收。長期執行的系統應定期清理無用資料卷。
8.1.8 資料卷備份與恢復
備份資料卷
## 使用臨時容器掛載資料卷,打包備份
$ docker run --rm \
-v my-vol:/source:ro \
-v $(pwd):/backup \
alpine tar czf /backup/my-vol-backup.tar.gz -C /source .
原理:
- 建立臨時容器
- 掛載要備份的資料捲到
/source - 掛載當前目錄到
/backup - 使用 tar 打包
恢復資料卷
## 建立新資料卷
$ docker volume create my-vol-restored
## 解壓備份到新資料卷
$ docker run --rm \
-v my-vol-restored:/target \
-v $(pwd):/backup:ro \
alpine tar xzf /backup/my-vol-backup.tar.gz -C /target
備份指令碼範例
#!/bin/bash
## backup-volume.sh
VOLUME_NAME=$1
BACKUP_DIR=${2:-/backups}
TIMESTAMP=$(date +%Y%m%d_%H%M%S)
docker run --rm \
-v ${VOLUME_NAME}:/source:ro \
-v ${BACKUP_DIR}:/backup \
alpine tar czf /backup/${VOLUME_NAME}_${TIMESTAMP}.tar.gz -C /source .
echo "Backed up ${VOLUME_NAME} to ${BACKUP_DIR}/${VOLUME_NAME}_${TIMESTAMP}.tar.gz"
8.1.9 資料卷 vs 繫結掛載
Docker 有兩種主要的資料持久化方式:
| 屬性 | 資料卷 (Volume) | 繫結掛載 (Bind Mount) |
|---|---|---|
| 管理方式 | Docker 管理 | 使用者管理 |
| 儲存位置 | /var/lib/docker/volumes/ |
任意宿主機路徑 |
| 可移植性 | 更好 | 依賴宿主機路徑 |
| 適用場景 | 生產資料持久化 | 開發時同步程式碼 |
| 備份 | 需要工具 | 直接訪問檔案 |
## 資料卷
$ docker run -v mydata:/app/data nginx
## 繫結掛載
$ docker run -v /host/path:/app/data nginx
詳見繫結掛載章節。
8.1.10 常見問題
Q:如何知道容器使用了哪些資料卷?
$ docker inspect container_name --format '{{json .Mounts}}' | jq
Q:資料卷的資料在哪裡?
## 檢視資料卷詳情
$ docker volume inspect my-vol
## Mountpoint 欄位顯示實際路徑
"Mountpoint": "/var/lib/docker/volumes/my-vol/_data"
⚠️ 注意:不建議直接修改 Mountpoint 中的檔案,應透過容器操作。
Q:如何在不同機器間遷移資料卷?
- 在源機器備份:
docker run --rm -v mydata:/data -v $(pwd):/backup alpine tar czf /backup/data.tar.gz -C /data . - 傳輸 tar.gz 檔案
- 在目標機器恢復