#Docker #Linux
Docker Volume 類型比較
1. Named Volumes (命名卷)
說明
Named Volumes 是由 Docker 管理的持久化儲存方案,資料儲存在 Docker 的管理目錄中(Linux 通常在 /var/lib/docker/volumes/)。這是最推薦的資料持久化方式。
特點
- ✅ 由 Docker 完全管理,不需要指定主機路徑
- ✅ 可以在多個容器間共享
- ✅ 支援 volume drivers,可擴展至遠端儲存
- ✅ 容易備份和遷移
- ✅ 在 Windows 和 Mac 上效能較好
Docker Compose 設定
services:
db:
image: postgres:15
volumes:
- postgres_data:/var/lib/postgresql/data
environment:
POSTGRES_PASSWORD: example
volumes:
postgres_data:
driver: local
# 可選:指定 driver options
driver_opts:
type: none
device: /path/on/host
o: bind
Docker 命令
# 建立基本 volume
docker volume create my_volume
# 建立 volume 並指定 driver
docker volume create --driver local my_volume
# 建立 volume 並設定 driver_opts (對應 docker-compose 的 driver_opts)
docker volume create \
--driver local \
--opt type=none \
--opt device=/path/on/host \
--opt o=bind \
postgres_data
# 使用短選項 -o (等同於 --opt)
docker volume create \
--driver local \
-o type=none \
-o device=/absolute/path/on/host \
-o o=bind \
my_volume
# NFS volume 範例
docker volume create \
--driver local \
-o type=nfs \
-o o=addr=192.168.1.100,rw \
-o device=:/path/to/nfs/share \
nfs_volume
# 使用 volume 啟動容器
docker run -d \
--name my_container \
-v my_volume:/app/data \
nginx:latest
# 查看所有 volumes
docker volume ls
# 查看 volume 詳細資訊(包含 driver_opts)
docker volume inspect my_volume
# 刪除 volume
docker volume rm my_volume
# 清理未使用的 volumes
docker volume prune
Volume SubPath (掛載子目錄)
Docker 支援使用 volume-subpath 參數來掛載 volume 內的特定子目錄,而不是整個 volume。這在多容器共享同一 volume 時特別有用。
重要限制
- 子目錄必須預先存在於 volume 中,否則掛載會失敗
- 只能使用
--mount語法,不支援-v簡短語法 - Docker Compose 目前官方文件未明確說明支援此功能
Docker 命令語法
--mount src=<volume-name>,dst=<container-path>,volume-subpath=<subdir>
完整範例
# 1. 建立 volume
docker volume create logs
# 2. 初始化子目錄結構(必須先建立)
docker run --rm \
--mount src=logs,dst=/logs \
alpine mkdir -p /logs/app1 /logs/app2
# 3. App1 只掛載 logs volume 的 app1 子目錄
docker run -d \
--name app1 \
--mount src=logs,dst=/var/log/app,volume-subpath=app1 \
myapp1:latest
# 4. App2 只掛載 logs volume 的 app2 子目錄
docker run -d \
--name app2 \
--mount src=logs,dst=/var/log/app,volume-subpath=app2 \
myapp2:latest
# 5. 查看整個 volume 的內容(用於管理)
docker run --rm \
--mount src=logs,dst=/logs \
alpine ls -lR /logs
實用範例
# 建立共享資料 volume
docker volume create shared_data
# 初始化多個應用的子目錄
docker run --rm \
--mount src=shared_data,dst=/data \
alpine sh -c "
mkdir -p /data/uploads/user1 /data/uploads/user2 &&
mkdir -p /data/cache/app1 /data/cache/app2 &&
chown -R 1000:1000 /data
"
# 上傳服務 - 使用 uploads/user1 子目錄
docker run -d \
--name upload_user1 \
--mount src=shared_data,dst=/app/uploads,volume-subpath=uploads/user1 \
upload_service:latest
# 快取服務 - 使用 cache/app1 子目錄
docker run -d \
--name cache_app1 \
--mount src=shared_data,dst=/app/cache,volume-subpath=cache/app1 \
cache_service:latest
Docker Compose (非官方支援,但可變通)
Docker Compose 目前沒有直接的 volume-subpath 語法,但可以使用以下變通方式:
# 方法 1: 使用 driver_opts 將 volume 綁定到主機子目錄
services:
app1:
image: myapp:latest
volumes:
- app1_logs:/var/log/app
app2:
image: myapp:latest
volumes:
- app2_logs:/var/log/app
volumes:
app1_logs:
driver: local
driver_opts:
type: none
device: /host/shared/logs/app1
o: bind
app2_logs:
driver: local
driver_opts:
type: none
device: /host/shared/logs/app2
o: bind
# 方法 2: 使用 init 容器 + 環境變數
services:
init:
image: alpine
volumes:
- shared_data:/data
command: mkdir -p /data/app1 /data/app2
restart: "no"
app1:
image: myapp:latest
depends_on:
- init
volumes:
- shared_data:/data
working_dir: /data/app1
environment:
DATA_PATH: /data/app1
app2:
image: myapp:latest
depends_on:
- init
volumes:
- shared_data:/data
working_dir: /data/app2
environment:
DATA_PATH: /data/app2
volumes:
shared_data:
使用場景
- 多容器共享單一 volume 時隔離資料
- 為每個容器維護獨立的日誌目錄
- 精細控制資料存取範圍
- 節省 volume 數量(一個 volume 多個用途)
使用場景
- 資料庫資料持久化(PostgreSQL, MySQL, MongoDB)
- 應用程式上傳的檔案儲存
- 需要在多個容器間共享的資料
- 生產環境的資料儲存
2. Bind Mounts (綁定掛載)
說明
Bind Mounts 將主機上的特定檔案或目錄直接掛載到容器中。提供了最直接的檔案系統存取,但依賴主機的檔案系統結構。
特點
- ✅ 可以直接存取和編輯主機檔案
- ✅ 適合開發環境的即時程式碼更新
- ✅ 可以掛載單一檔案或整個目錄
- ⚠️ 依賴主機的目錄結構
- ⚠️ 在 Windows/Mac 上效能可能較差
- ⚠️ 安全性較低(容器可以修改主機檔案)
Docker Compose 設定
services:
web:
image: node:18
working_dir: /app
volumes:
# 長語法(推薦)
- type: bind
source: ./src
target: /app
read_only: false
# 短語法
- ./config:/app/config:ro # :ro 表示唯讀
- ./logs:/app/logs
command: npm run dev
ports:
- "3000:3000"
nginx:
image: nginx:latest
volumes:
# 掛載設定檔
- ./nginx.conf:/etc/nginx/nginx.conf:ro
# 掛載靜態檔案
- ./public:/usr/share/nginx/html:ro
ports:
- "80:80"
Docker 命令
# 使用絕對路徑掛載
docker run -d \
--name dev_container \
-v /absolute/path/on/host:/app \
-v $(pwd)/config:/app/config:ro \
node:18
# 使用相對路徑(需要完整路徑)
docker run -d \
--name web \
-v "$(pwd)":/app \
-w /app \
nginx:latest
# 掛載單一檔案
docker run -d \
--name app \
-v $(pwd)/.env:/app/.env:ro \
myapp:latest
# 使用 --mount 語法(更明確,推薦)
docker run -d \
--name app \
--mount type=bind,source=$(pwd)/src,target=/app,readonly=false \
node:18
使用場景
- 開發環境的即時程式碼更新
- 掛載設定檔到容器
- 需要在主機上直接查看/編輯容器檔案
- CI/CD 建置過程中的檔案共享
3. Anonymous Volumes (匿名卷)
說明
Anonymous Volumes 是沒有指定名稱的 volume,由 Docker 自動產生隨機名稱。當容器被刪除時,通常也會一起被刪除(除非使用特定選項)。
特點
- ✅ 自動管理,無需手動建立
- ✅ 適合臨時資料儲存
- ⚠️ 難以追蹤和管理
- ⚠️ 容器刪除後可能遺留孤立 volumes
- ⚠️ 無法在容器間共享(每次都會建立新的)
Docker Compose 設定
services:
app:
image: node:18
volumes:
# 匿名 volume(不指定主機路徑或 volume 名稱)
- /app/node_modules
- /app/cache
working_dir: /app
command: npm start
db:
image: postgres:15
volumes:
# 結合 bind mount 和匿名 volume
- ./app:/app # bind mount
- /app/node_modules # 匿名 volume,避免覆蓋
environment:
POSTGRES_PASSWORD: example
Docker 命令
# 建立匿名 volume
docker run -d \
--name app \
-v /app/data \
nginx:latest
# 容器刪除時自動清理匿名 volume
docker run --rm \
-v /tmp/cache \
alpine:latest
# 查看容器的匿名 volumes
docker inspect app
# 範例:避免 node_modules 被覆蓋
docker run -d \
--name node_app \
-v $(pwd):/app \
-v /app/node_modules \
node:18
使用場景
- 保護容器內特定目錄不被 bind mount 覆蓋(如 node_modules)
- 臨時快取資料
- 不需要持久化的資料
- 開發環境的臨時檔案
4. tmpfs Mounts (臨時檔案系統掛載)
說明
tmpfs Mounts 將資料儲存在主機的記憶體中,不會寫入磁碟。當容器停止時,資料就會消失。只在 Linux 上可用。
特點
- ✅ 極快的讀寫速度(記憶體存取)
- ✅ 敏感資料不會寫入磁碟
- ✅ 容器停止後自動清理
- ⚠️ 資料不持久化
- ⚠️ 佔用主機記憶體
- ⚠️ 只支援 Linux
Docker Compose 設定
services:
web:
image: nginx:latest
tmpfs:
- /tmp
- /run
# 或使用長語法
volumes:
- type: tmpfs
target: /app/cache
tmpfs:
size: 100M # 限制大小為 100MB
mode: 1777 # 設定權限
app:
image: myapp:latest
volumes:
- type: tmpfs
target: /app/temp
tmpfs:
size: 50M
- data:/app/data # 結合 named volume
volumes:
data:
Docker 命令
# 基本使用
docker run -d \
--name app \
--tmpfs /tmp \
nginx:latest
# 使用 --mount 指定選項
docker run -d \
--name app \
--mount type=tmpfs,target=/app/cache,tmpfs-size=100M,tmpfs-mode=1770 \
myapp:latest
# 多個 tmpfs mounts
docker run -d \
--name app \
--tmpfs /tmp:rw,size=50M,mode=1777 \
--tmpfs /run:rw,size=10M \
nginx:latest
# 查看掛載資訊
docker inspect app | grep -A 10 Mounts
使用場景
- 敏感資料處理(密碼、金鑰等)
- 高速快取需求
- 臨時檔案處理
- Session 儲存
- 編譯過程的臨時檔案
Volume 類型比較表
| 特性 | Named Volume | Bind Mount | Anonymous Volume | tmpfs Mount |
|---|---|---|---|---|
| 持久化 | ✅ 是 | ✅ 是 | ✅ 是 | ❌ 否 |
| Docker 管理 | ✅ 是 | ❌ 否 | ✅ 是 | ❌ 否 |
| 主機路徑控制 | ❌ 否 | ✅ 是 | ❌ 否 | ❌ 否 |
| 容器間共享 | ✅ 容易 | ✅ 可以 | ❌ 困難 | ❌ 不可 |
| 效能(Linux) | 🟢 好 | 🟢 好 | 🟢 好 | 🟢 極佳 |
| 效能(Win/Mac) | 🟢 好 | 🟡 較差 | 🟢 好 | N/A |
| 備份容易度 | 🟢 容易 | 🟡 中等 | 🔴 困難 | N/A |
| 安全性 | 🟢 高 | 🟡 中等 | 🟢 高 | 🟢 高 |
| 使用複雜度 | 🟢 簡單 | 🟡 中等 | 🟢 簡單 | 🟢 簡單 |
| 生產環境 | ✅ 推薦 | ⚠️ 謹慎 | ❌ 不推薦 | ✅ 特定場景 |
實用技巧與最佳實踐
1. Volume 備份與還原
# 備份 named volume
docker run --rm \
-v my_volume:/source:ro \
-v $(pwd):/backup \
alpine tar czf /backup/backup.tar.gz -C /source .
# 還原 volume
docker run --rm \
-v my_volume:/target \
-v $(pwd):/backup \
alpine tar xzf /backup/backup.tar.gz -C /target
2. 複製 Volume 資料
# 從一個 volume 複製到另一個
docker run --rm \
-v old_volume:/from:ro \
-v new_volume:/to \
alpine sh -c "cd /from && cp -av . /to"
3. 組合使用範例
services:
app:
image: node:18
volumes:
# Bind mount: 開發時即時更新程式碼
- ./src:/app/src
# Named volume: 持久化上傳檔案
- uploads:/app/uploads
# Anonymous volume: 保護 node_modules
- /app/node_modules
# tmpfs: 高速快取
tmpfs:
- /app/cache:size=100M
db:
image: postgres:15
volumes:
# Named volume: 資料庫資料持久化
- db_data:/var/lib/postgresql/data
environment:
POSTGRES_PASSWORD: example
volumes:
uploads:
db_data:
4. 清理未使用的 Volumes
# 清理所有未使用的 volumes
docker volume prune -f
# 清理特定 volume
docker volume rm volume_name
# 查看 volume 使用情況
docker system df -v
5. 使用 Volume SubPath 實現多租戶資料隔離
# 實際場景:多個微服務共享一個資料 volume,但各自有獨立空間
# 建立共享 volume
docker volume create microservices_data
# 初始化子目錄結構
docker run --rm \
--mount src=microservices_data,dst=/data \
alpine sh -c "
mkdir -p /data/{auth,user,order}/{uploads,cache,logs} &&
mkdir -p /data/shared/{config,templates} &&
chown -R 1000:1000 /data
"
# 認證服務 - 只能存取 auth 子目錄
docker run -d \
--name auth_service \
--mount src=microservices_data,dst=/app/data,volume-subpath=auth \
--mount src=microservices_data,dst=/app/shared,volume-subpath=shared,readonly \
auth:latest
# 使用者服務 - 只能存取 user 子目錄
docker run -d \
--name user_service \
--mount src=microservices_data,dst=/app/data,volume-subpath=user \
--mount src=microservices_data,dst=/app/shared,volume-subpath=shared,readonly \
user:latest
# 訂單服務 - 只能存取 order 子目錄
docker run -d \
--name order_service \
--mount src=microservices_data,dst=/app/data,volume-subpath=order \
--mount src=microservices_data,dst=/app/shared,volume-subpath=shared,readonly \
order:latest
# 管理容器 - 可以存取完整 volume(用於維護)
docker run --rm -it \
--mount src=microservices_data,dst=/data \
alpine sh
# 備份特定服務的資料
docker run --rm \
--mount src=microservices_data,dst=/data,volume-subpath=auth \
-v $(pwd)/backups:/backup \
alpine tar czf /backup/auth-$(date +%Y%m%d).tar.gz -C /data .
選擇建議
使用 Named Volumes 當
- 生產環境的資料持久化
- 需要簡單的備份和遷移
- 資料需要在容器間共享
- 使用 Windows 或 Mac 進行開發
使用 Bind Mounts 當
- 開發環境需要即時程式碼更新
- 需要精確控制檔案位置
- 設定檔需要頻繁修改
- 與主機工具整合(如 IDE)
使用 Anonymous Volumes 當
- 保護特定目錄不被覆蓋
- 臨時資料儲存
- 不需要跨容器共享
使用 tmpfs Mounts 當
- 處理敏感資料
- 需要極高的 I/O 效能
- 臨時快取或 session 儲存
- 資料不需要持久化