目錄
- Volume 基本概念
- 為什麼需要 Volume
- Volume 的類型
- Volume 的架構
- Volume 使用方式
- Volume 實際應用
- Volume 常見問題
- Volume 備份與還原
- Volume 效能優化
- Volume 最佳實踐
Volume 基本概念
Volume 是什麼?
Volume = Docker 的資料持久化機制
= 獨立於 Container 生命週期的儲存
= 可以在 Container 間共享的資料
核心特點:
- Container 刪除後,Volume 資料仍保留
- 可以在多個 Container 間共享
- 由 Docker 統一管理
- 效能優於 Bind Mount
Volume vs Container 檔案系統
Container 檔案系統(臨時)
├─ 可讀寫層
├─ 資料隨 Container 消失
└─ 無法跨 Container 共享
Volume(持久化)
├─ 獨立儲存
├─ Container 刪除後保留
└─ 可以跨 Container 共享
為什麼需要 Volume
問題場景
# 啟動 MySQL Container
docker run -d --name db mysql
# 在 Container 中寫入資料
docker exec db mysql -e "CREATE DATABASE myapp;"
# 刪除 Container
docker rm -f db
# 重新啟動
docker run -d --name db mysql
# ❌ 資料消失了!
# Database 'myapp' 不存在
Volume 解決方案
# 使用 Volume
docker run -d \
--name db \
-v mysql-data:/var/lib/mysql \
mysql
# 寫入資料
docker exec db mysql -e "CREATE DATABASE myapp;"
# 刪除 Container
docker rm -f db
# 重新啟動(使用同一個 Volume)
docker run -d \
--name db \
-v mysql-data:/var/lib/mysql \
mysql
# ✅ 資料還在!
# Database 'myapp' 存在
Volume 的類型
三種 Volume 類型
1. Named Volume(具名 Volume)
docker run -v mydata:/app/data
2. Bind Mount(綁定掛載)
docker run -v /host/path:/container/path
3. Anonymous Volume(匿名 Volume)
docker run -v /app/data
類型對比
| 特性 | Named Volume | Bind Mount | Anonymous Volume |
|---|---|---|---|
| 管理方式 | Docker 管理 | 手動管理 | Docker 管理 |
| 路徑位置 | Docker 目錄 | 任意位置 | Docker 目錄 |
| 可移植性 | 高 | 低 | 高 |
| 效能 | 最佳 | 較好 | 最佳 |
| 跨平台 | 是 | 否 | 是 |
| 識別方式 | 名稱 | 完整路徑 | Volume ID |
| 生命週期 | 手動刪除 | 永久 | 隨 Container |
| 適用場景 | 生產環境 | 開發環境 | 臨時資料 |
Volume 的架構
Named Volume 架構
主機(Host)
├─ /var/lib/docker/volumes/
│ ├─ mydata/
│ │ └─ _data/ ← Volume 實際資料
│ │ ├─ file1.txt
│ │ └─ file2.txt
│ │
│ └─ mysql-data/
│ └─ _data/
│ └─ mysql/ ← MySQL 資料檔案
Container
└─ /app/data/ ← 掛載點
├─ file1.txt ← 對應 Volume 中的檔案
└─ file2.txt
Bind Mount 架構
主機(Host)
└─ /home/user/project/
├─ src/
│ └─ app.js
└─ config/
└─ config.json
Container
└─ /app/ ← 掛載點
├─ src/
│ └─ app.js ← 直接對應主機檔案
└─ config/
└─ config.json
三種類型的視覺對比
Named Volume
┌──────────────────────────────────────┐
│ Container: /app/data │
│ ↕ │
│ Docker Volume: mydata │
│ ↕ │
│ Host: /var/lib/docker/volumes/mydata │
└──────────────────────────────────────┘
Bind Mount
┌──────────────────────────────────────┐
│ Container: /app/src │
│ ↕ │
│ Host: /home/user/project/src │
└──────────────────────────────────────┘
Anonymous Volume
┌──────────────────────────────────────┐
│ Container: /app/temp │
│ ↕ │
│ Docker Volume: a1b2c3d4e5f6... │
│ ↕ │
│ Host: /var/lib/docker/volumes/a1b2.. │
└──────────────────────────────────────┘
Volume 使用方式
Named Volume
# 1. 創建 Volume
docker volume create mydata
# 2. 查看 Volume 列表
docker volume ls
# DRIVER VOLUME NAME
# local mydata
# 3. 查看 Volume 詳細資訊
docker volume inspect mydata
# Mountpoint: /var/lib/docker/volumes/mydata/_data
# 4. 使用 Volume
docker run -d \
--name app \
-v mydata:/app/data \
myapp
# 5. 查看 Volume 使用情況
docker ps --format "table {{.Names}}\t{{.Mounts}}"
# 6. 刪除 Volume(必須先停止使用的 Container)
docker rm -f app
docker volume rm mydata
# 7. 刪除所有未使用的 Volume
docker volume prune
Bind Mount
# 方式 1:使用 -v
docker run -d \
--name dev \
-v $(pwd)/src:/app/src \
-v $(pwd)/config:/app/config \
myapp
# 方式 2:使用 --mount(更明確)
docker run -d \
--name dev \
--mount type=bind,source=$(pwd)/src,target=/app/src \
--mount type=bind,source=$(pwd)/config,target=/app/config \
myapp
# 唯讀掛載
docker run -d \
--name app \
-v $(pwd)/config:/app/config:ro \
myapp
Anonymous Volume
# 創建匿名 Volume
docker run -d \
--name temp \
-v /app/cache \
myapp
# 查看 Anonymous Volume
docker volume ls
# DRIVER VOLUME NAME
# local a1b2c3d4e5f6...
# Container 停止後自動刪除 Volume
docker run -d \
--name temp \
--rm \
-v /app/cache \
myapp
Volume 指令速查
# 創建 Volume
docker volume create <name>
# 列出所有 Volume
docker volume ls
# 查看 Volume 詳細資訊
docker volume inspect <name>
# 刪除 Volume
docker volume rm <name>
# 刪除所有未使用的 Volume
docker volume prune
# 刪除特定 Volume(強制)
docker volume rm -f <name>
實戰範例
範例 1:MySQL 資料持久化
# 創建 Volume
docker volume create mysql-data
# 啟動 MySQL
docker run -d \
--name mysql \
-e MYSQL_ROOT_PASSWORD=secret \
-v mysql-data:/var/lib/mysql \
mysql:8
# 連接並創建資料
docker exec mysql mysql -uroot -psecret \
-e "CREATE DATABASE myapp; USE myapp; CREATE TABLE users (id INT, name VARCHAR(50));"
# 刪除 Container
docker rm -f mysql
# 重新啟動(資料仍在)
docker run -d \
--name mysql \
-e MYSQL_ROOT_PASSWORD=secret \
-v mysql-data:/var/lib/mysql \
mysql:8
# 驗證資料
docker exec mysql mysql -uroot -psecret \
-e "USE myapp; SHOW TABLES;"
# ✅ 'users' 表仍然存在
範例 2:PostgreSQL 資料持久化
# 創建 Volume
docker volume create postgres-data
# 啟動 PostgreSQL
docker run -d \
--name postgres \
-e POSTGRES_PASSWORD=secret \
-v postgres-data:/var/lib/postgresql/data \
postgres:15
# 資料持久化位置
# Container: /var/lib/postgresql/data
# Volume: postgres-data
Volume 實際應用
MongoDB
# 創建 Volume
docker volume create mongo-data
# 啟動 MongoDB
docker run -d \
--name mongo \
-v mongo-data:/data/db \
mongo:6
# 資料持久化位置
# Container: /data/db
# Volume: mongo-data
2. 開發環境(Bind Mount)
# Node.js 開發環境
docker run -d \
--name node-dev \
-v $(pwd):/app \
-v /app/node_modules \
-w /app \
-p 3000:3000 \
node:18 \
npm run dev
# 說明:
# -v $(pwd):/app ← 掛載專案目錄
# -v /app/node_modules ← 排除 node_modules(使用 Container 中的)
# -w /app ← 設定工作目錄
# -p 3000:3000 ← 映射 Port
# Python 開發環境
docker run -d \
--name python-dev \
-v $(pwd):/app \
-w /app \
-p 8000:8000 \
python:3.11 \
python -m http.server 8000
# 修改本機檔案 → Container 即時更新
3. 共享配置檔案
# 創建配置 Volume
docker volume create app-config
# 初始化配置檔案
docker run --rm \
-v app-config:/config \
alpine \
sh -c "echo 'API_URL=https://api.example.com' > /config/app.env"
# App 1 使用配置
docker run -d \
--name app1 \
-v app-config:/app/config:ro \
myapp
# App 2 使用相同配置
docker run -d \
--name app2 \
-v app-config:/app/config:ro \
myapp
# 配置集中管理,多個 Container 共享
4. 日誌收集
# 創建日誌 Volume
docker volume create app-logs
# 應用程式寫入日誌
docker run -d \
--name app \
-v app-logs:/var/log/app \
myapp
# 日誌收集器讀取日誌
docker run -d \
--name logstash \
-v app-logs:/logs:ro \
logstash
# 多個 Container 共享日誌目錄
5. 靜態網站部署
# 使用 Bind Mount 部署靜態網站
docker run -d \
--name nginx \
-v $(pwd)/html:/usr/share/nginx/html:ro \
-p 80:80 \
nginx
# 修改本機 HTML → 網站即時更新
Volume 常見問題
問題 1:Volume 資料找不到
# 查看 Volume 實際位置
docker volume inspect mydata
# "Mountpoint": "/var/lib/docker/volumes/mydata/_data"
# 進入 Volume 查看檔案
# macOS/Windows(Docker Desktop)
docker run --rm -v mydata:/data alpine ls -la /data
# Linux
sudo ls -la /var/lib/docker/volumes/mydata/_data
問題 2:權限問題
# ❌ 錯誤:Permission denied
docker run -v $(pwd):/app myapp
# Error: Permission denied
# ✅ 解決方案 1:指定使用者
docker run --user $(id -u):$(id -g) \
-v $(pwd):/app \
myapp
# ✅ 解決方案 2:在 Dockerfile 中設定權限
FROM node:18
RUN groupadd -r appuser && useradd -r -g appuser appuser
USER appuser
問題 3:檔案不同步
# 問題:修改本機檔案,Container 中看不到
# 檢查掛載點
docker inspect <container> | grep Mounts -A 20
# 確認路徑正確
docker run -v $(pwd):/app alpine ls -la /app
# macOS/Windows:確認 Docker Desktop 檔案共享設定
# Settings → Resources → File Sharing
問題 4:Volume 佔用空間過大
# 查看所有 Volume
docker volume ls
# 查看 Volume 大小
docker system df -v
# 刪除未使用的 Volume
docker volume prune
# 刪除特定 Volume
docker volume rm <name>
問題 5:Bind Mount 效能問題(macOS/Windows)
# ❌ 慢:大量小檔案(如 node_modules)
docker run -v $(pwd):/app myapp
# ✅ 快:排除 node_modules,使用 Volume
docker run \
-v $(pwd):/app \
-v /app/node_modules \
myapp
# 或使用 delegated/cached(macOS)
docker run -v $(pwd):/app:delegated myapp
Volume 備份與還原
備份 Volume
# 方法 1:使用 tar 備份
docker run --rm \
-v mydata:/data \
-v $(pwd):/backup \
alpine \
tar czf /backup/mydata-backup.tar.gz -C /data .
# 方法 2:使用臨時 Container
docker run --rm \
-v mydata:/source:ro \
-v $(pwd):/backup \
alpine \
sh -c "cd /source && tar czf /backup/backup-$(date +%Y%m%d).tar.gz ."
還原 Volume
# 創建新 Volume
docker volume create mydata-restore
# 還原資料
docker run --rm \
-v mydata-restore:/data \
-v $(pwd):/backup \
alpine \
tar xzf /backup/mydata-backup.tar.gz -C /data
# 使用還原的 Volume
docker run -d \
--name app \
-v mydata-restore:/app/data \
myapp
自動備份腳本
#!/bin/bash
# backup-volume.sh
VOLUME_NAME=$1
BACKUP_DIR="/backups"
DATE=$(date +%Y%m%d-%H%M%S)
BACKUP_FILE="$BACKUP_DIR/${VOLUME_NAME}-${DATE}.tar.gz"
docker run --rm \
-v $VOLUME_NAME:/data:ro \
-v $BACKUP_DIR:/backup \
alpine \
tar czf /backup/$(basename $BACKUP_FILE) -C /data .
echo "Backup completed: $BACKUP_FILE"
# 使用方式
# ./backup-volume.sh mysql-data
在 Container 間複製資料
# 從 Volume A 複製到 Volume B
docker run --rm \
-v volume-a:/source:ro \
-v volume-b:/dest \
alpine \
sh -c "cp -a /source/. /dest/"
Volume 效能優化
效能對比
Named Volume → 最快(原生 Docker 儲存)
Bind Mount → 較快(Linux)/ 較慢(macOS/Windows)
Anonymous Volume → 最快(原生 Docker 儲存)
Linux 效能
# Linux:所有類型效能都很好
# Named Volume 和 Bind Mount 效能接近
docker run -v mydata:/data myapp # 快
docker run -v /host/path:/data myapp # 快
macOS/Windows 效能優化
# ❌ 慢:大量檔案的 Bind Mount
docker run -v $(pwd):/app node:18 npm install
# ✅ 快:使用 delegated
docker run -v $(pwd):/app:delegated node:18 npm install
# ✅ 快:排除大量小檔案(如 node_modules)
docker run \
-v $(pwd):/app \
-v /app/node_modules \
node:18 npm install
# ✅ 最快:使用 Named Volume
docker volume create node-modules
docker run \
-v $(pwd):/app \
-v node-modules:/app/node_modules \
node:18 npm install
快取模式(macOS)
# consistent:強一致性(預設,最慢)
-v $(pwd):/app:consistent
# cached:主機 → Container 快取(較快)
-v $(pwd):/app:cached
# delegated:Container → 主機快取(最快)
-v $(pwd):/app:delegated
# 使用建議
# - 開發環境:delegated(程式碼修改)
# - 輸出檔案:cached(build 輸出)
# - 資料庫:consistent(資料一致性)
Volume 最佳實踐
1. 選擇適當的 Volume 類型
# ✅ 生產環境:使用 Named Volume
docker run -d -v mysql-data:/var/lib/mysql mysql
# ✅ 開發環境:使用 Bind Mount
docker run -d -v $(pwd):/app myapp
# ✅ 臨時資料:使用 Anonymous Volume
docker run -d -v /tmp myapp
2. 使用有意義的 Volume 名稱
# ❌ 不好
docker volume create vol1
# ✅ 好
docker volume create myapp-mysql-data
docker volume create myapp-uploads
docker volume create myapp-logs
3. Volume 生命週期管理
# 定期清理未使用的 Volume
docker volume prune
# 為重要 Volume 設定備份
# 參考「Volume 備份與還原」章節
# 使用 --rm 自動清理臨時 Volume
docker run --rm -v /tmp myapp
4. 權限管理
# 設定適當的使用者權限
docker run --user $(id -u):$(id -g) \
-v $(pwd):/app \
myapp
# 唯讀掛載(防止意外修改)
docker run -v config-data:/app/config:ro myapp
5. 使用 Docker Compose 管理 Volume
# docker-compose.yml
version: '3.8'
services:
db:
image: mysql:8
volumes:
- mysql-data:/var/lib/mysql
app:
build: .
volumes:
- ./src:/app/src # 開發環境
- app-logs:/app/logs # 日誌
- app-uploads:/app/uploads # 上傳檔案
volumes:
mysql-data:
driver: local
app-logs:
driver: local
app-uploads:
driver: local
6. 安全性考量
# 敏感資料使用 Volume(不要用 Bind Mount)
docker volume create secrets
docker run -v secrets:/secrets:ro myapp
# 不要在 Volume 中存放敏感配置
# 使用 Docker Secrets 或環境變數
# 限制 Volume 權限
docker run -v data:/data:ro myapp # 唯讀
7. 監控 Volume 使用情況
# 查看 Volume 使用空間
docker system df -v
# 定期檢查未使用的 Volume
docker volume ls -f dangling=true
# 設定 Volume 清理腳本
# 參考「Volume 備份與還原」章節的自動備份腳本
常見問題
Q1: Volume 和 Bind Mount 有什麼區別?
A:
- Named Volume:由 Docker 管理,跨平台,效能最佳,推薦生產環境
- Bind Mount:手動管理路徑,適合開發環境,macOS/Windows 效能較差
Q2: Volume 資料存在哪裡?
A: Linux 在 /var/lib/docker/volumes/,macOS/Windows 在 Docker Desktop 虛擬機中。使用 docker volume inspect 查看。
Q3: Container 刪除後 Volume 會消失嗎?
A: Named Volume 不會消失,需要手動刪除。Anonymous Volume 會隨 Container 刪除。
Q4: 如何備份 Volume?
A: 使用臨時 Container 將 Volume 打包成 tar 檔案:
docker run --rm -v mydata:/data -v $(pwd):/backup alpine \
tar czf /backup/backup.tar.gz -C /data .
總結
核心要點
- Volume 提供獨立於 Container 的持久化儲存
- 三種類型:Named Volume(推薦)、Bind Mount(開發)、Anonymous Volume(臨時)
- Named Volume 效能最佳,跨平台,由 Docker 統一管理
- 使用 Volume 實現資料庫持久化、配置共享、日誌收集
- 定期備份重要 Volume,使用 prune 清理未使用資源
快速參考
| 操作 | 指令 | 說明 |
|---|---|---|
| 創建 | docker volume create |
建立 Volume |
| 查看 | docker volume ls |
列出所有 |
| 刪除 | docker volume rm |
刪除指定 |
| 清理 | docker volume prune |
刪除未使用 |
| 使用 | -v name:/path |
掛載 Volume |
| 備份 | tar czf backup.tar.gz |
打包備份 |
建立日期:2025-11-10 最後更新:2025-11-18