Docker Volume 資料持久化:別讓容器重啟就丟失資料
Docker Volume 資料持久化:別讓容器重啟就丟失資料
Docker 容器的核心特性是「無狀態」——容器停止後,容器內的所有資料都會消失。對於資料庫、上傳的檔案、設定資料,這顯然不是我們想要的行為。Docker Volume 就是解決資料持久化問題的官方機制。
為什麼需要 Volume?
# 示範問題
docker run -d --name my-db postgres:16
docker exec my-db psql -U postgres -c "CREATE TABLE test (id serial, name text);"
docker exec my-db psql -U postgres -c "INSERT INTO test (name) VALUES ('hello');"
# 停止並移除容器
docker stop my-db && docker rm my-db
# 重新啟動
docker run -d --name my-db postgres:16
docker exec my-db psql -U postgres -c "SELECT * FROM test;"
# ERROR: relation "test" does not exist
# 資料消失了!Volume 的三種類型
1. Named Volume(命名卷,推薦)
由 Docker 管理,存儲在 Docker 的數據目錄中:
# 建立 Volume
docker volume create my-data
# 查看 Volume 列表
docker volume ls
# 查看 Volume 詳細資訊
docker volume inspect my-data
# 使用 Volume 啟動容器
docker run -d \
--name my-db \
-v my-data:/var/lib/postgresql/data \
postgres:16
# 容器移除後 Volume 仍然存在
docker rm -f my-db
docker volume ls # my-data 仍在
# 重新啟動,資料恢復
docker run -d \
--name my-db \
-v my-data:/var/lib/postgresql/data \
postgres:162. Bind Mount(綁定掛載)
將主機上的特定路徑掛載到容器:
# 將當前目錄掛載到容器
docker run -d \
--name my-app \
-v $(pwd)/data:/app/data \
my-app-image
# 適用於開發時同步程式碼
docker run -d \
--name dev-server \
-v $(pwd):/app \
-p 3000:3000 \
node:20 \
npm run dev3. tmpfs Mount(記憶體掛載)
資料存在記憶體中,容器停止後消失,適用於敏感資料:
docker run -d \
--name my-app \
--tmpfs /tmp:rw,size=100m \
my-app-imageDocker Compose 中的 Volume
# docker-compose.yml
version: '3.9'
services:
postgres:
image: postgres:16
environment:
POSTGRES_DB: myapp
POSTGRES_USER: admin
POSTGRES_PASSWORD: secret
volumes:
- postgres_data:/var/lib/postgresql/data
- ./init.sql:/docker-entrypoint-initdb.d/init.sql # 初始化腳本
ports:
- "5432:5432"
redis:
image: redis:7-alpine
volumes:
- redis_data:/data
command: redis-server --appendonly yes # 啟用持久化
minio:
image: minio/minio
command: server /data --console-address ":9001"
environment:
MINIO_ROOT_USER: minioadmin
MINIO_ROOT_PASSWORD: minioadmin
volumes:
- minio_data:/data
ports:
- "9000:9000"
- "9001:9001"
app:
build: .
volumes:
- ./uploads:/app/uploads # bind mount,方便直接存取上傳的檔案
- app_logs:/app/logs # named volume,日誌
depends_on:
- postgres
- redis
# 在最外層定義所有 named volumes
volumes:
postgres_data:
redis_data:
minio_data:
app_logs:Volume 備份與還原
備份
# 方法一:使用輔助容器備份
docker run --rm \
-v my-data:/source \
-v $(pwd)/backup:/backup \
alpine \
tar czf /backup/my-data-$(date +%Y%m%d).tar.gz -C /source .
# 方法二:PostgreSQL 備份
docker exec my-db pg_dump -U postgres myapp > backup.sql還原
# 從 tar 備份還原
docker run --rm \
-v my-data:/target \
-v $(pwd)/backup:/backup \
alpine \
tar xzf /backup/my-data-20240101.tar.gz -C /target
# 從 SQL 還原
cat backup.sql | docker exec -i my-db psql -U postgres myappVolume 清理
# 移除未使用的 Volume
docker volume prune
# 移除特定 Volume
docker volume rm my-data
# 查看 Volume 磁碟使用量
docker system df -v實際案例:完整開發環境
# docker-compose.dev.yml
version: '3.9'
services:
db:
image: postgres:16
volumes:
- db_data:/var/lib/postgresql/data
environment:
POSTGRES_PASSWORD: devpassword
POSTGRES_DB: myapp_dev
app:
build:
context: .
target: development
volumes:
- .:/app # 程式碼同步(bind mount)
- /app/node_modules # 避免覆蓋容器內的 node_modules
environment:
NODE_ENV: development
DATABASE_URL: postgresql://postgres:devpassword@db/myapp_dev
ports:
- "3000:3000"
command: npm run dev
depends_on:
- db
volumes:
db_data:注意 /app/node_modules 這個匿名 Volume 的技巧:它防止主機上的 node_modules(或不存在的情況)覆蓋容器內正確安裝的 node_modules。
最佳實踐
- 生產環境用 Named Volume,不要用 bind mount,因為路徑在不同主機上可能不同
- 定期備份重要 Volume,特別是資料庫
- 在 Compose 中顯式宣告 Volume,避免意外的匿名 Volume 堆積
- 善用
docker system df監控磁碟使用量 - 開發環境可以用 bind mount 同步程式碼,但要注意效能問題(特別是 macOS)
總結
Docker Volume 是容器化應用資料持久化的核心機制。Named Volume 適合生產環境的資料庫和檔案儲存;Bind Mount 適合開發時的程式碼同步。掌握 Volume 的備份還原流程,是確保生產環境資料安全的關鍵。
分享這篇文章