使用 Docker 時,經常需要備份存儲在 中的數據,或者出於測試目的將數據複製到另一個卷中。

雖然可以考慮使用 docker cp 命令,但此命令僅支持在 容器的檔案系統 和主機之間進行複製,因此無法直接訪問 Docker 管理的卷。

本文將介紹複製 Docker 卷的正確方法,不僅僅是列出命令,還會聚焦於 ‘為什麼’需要使用這種方式 的原理。理解這一原理後,即使不記住命令,也能在需要時自然地加以應用。

核心原理相當簡單。

操作 Docker 卷的最安全和最‘Docker 風格’的方法是利用可以訪問該卷的‘臨時容器’作為橋接。


1. 將現有卷複製到新卷 (Volume-to-Volume)



這是最常見的場景。您可能想將運行中的 db_data 卷複製到測試用的 db_data_test 卷。

🤔 為什麼要使用臨時容器?

Docker 卷存儲在主機檔案系統中的某個地方(如 /var/lib/docker/volumes/...),但 Docker 守護進程管理這一路徑。直接訪問此路徑並使用 cp 命令並不推薦,並且可能導致權限問題或數據一致性問題。

相反,我們將運行一個同時掛載兩個卷的臨時容器。

  1. 容器將原始卷source_volume)掛載到 /from 路徑。

  2. 容器將目標卷new_volume)掛載到 /to 路徑。

  3. 容器啟動後立即執行簡單的 Linux 命令(cptar),將 /from 的所有數據複製到 /to

  4. 命令結束後,容器會自動被銷毀(--rm 參數)。

這個容器只用作數據複製的‘工具’。

🚀 如何:命令示例

以下是將 source_data 卷的數據複製到 target_data 卷的示例。

  1. 創建測試用卷(可選)
docker volume create source_data
docker volume create target_data
# (假設 source_data 中已有數據。)
  1. 利用臨時容器進行複製
docker run --rm \
       -v source_data:/from \
       -v target_data:/to \
       alpine \
       sh -c "cp -a /from/. /to/"

💡 命令解說

  • docker run --rm: --rm 標誌表示容器在完成任務並退出時立即刪除容器。這對於臨時任務是必須的。

  • -v source_data:/from: 將 source_data 卷掛載到容器內的 /from 目錄中。

  • -v target_data:/to: 將 target_data 卷掛載到容器內的 /to 目錄中。

  • alpine: 使用包含基本工具(如 cpsh)且體積極小的 alpine Linux 映像。

  • sh -c "...": 在 alpine 容器啟動時要執行的命令。

  • cp -a /from/. /to/:

    • -a (archive): 此標誌是核心。與單純複製 cp -r 不同,這會保留所有屬性,如所有權、權限、時間戳等。在處理敏感數據如數據庫文件時非常重要。

    • /from/.: 意味著 /from 中的所有內容(包括隱藏文件),而不是 /from 目錄。


2. 將卷數據複製到主機檔案系統(備份)

當您希望將卷的數據備份到本地機器或伺服器的某個特定目錄如 .tar 文件時使用。

🤔 為什麼:如何工作?

原理與第一條相同。但目標不再是‘Docker 卷’,而是‘主機目錄’。

Docker 支持將主機的特定目錄掛載到容器中的綁定掛載(Bind Mount) 功能。

  1. 容器將 /data 路徑掛載為原始卷source_volume)。

  2. 容器將 /backup 路徑掛載為主機的特定目錄$(pwd)/backup)。

  3. 容器將 /data 的內容複製(或壓縮)到 /backup 目錄。

  4. 這項操作發生在容器內部,但由於 /backup 與實際主機目錄相連,因此結果將保留在主機上。

🚀 如何:命令示例

source_data 卷的數據複製到當前位置($(pwd))的 backup 目錄。

# 在主機上創建備份目錄
mkdir -p $(pwd)/backup

docker run --rm \
       -v source_data:/data:ro \
       -v $(pwd)/backup:/backup \
       alpine \
       cp -a /data/. /backup/

💡 命令解說

  • -v source_data:/data:ro: 添加了 :ro(只讀)標誌。由於備份只需讀取數據,因此建議 以只讀方式掛載,以防止意外修改原始卷。

  • -v $(pwd)/backup:/backup: 與 source_data(卷名)不同,/ 開頭或包含 $(pwd)(當前路徑)的絕對/相對路徑指的是主機目錄


3. 核心複製技巧 (Tips)



技巧 1: 使用 tar 進行高效複製(壓縮備份)

使用 tar 而不是 cp 命令有多個好處。特別是當將數據打包為存檔文件(.tar.gz)時非常有用。

Volume-to-Volume(使用 tar)

可能比 cp 更快,特別是當文件較多時更為高效。

docker run --rm \
       -v source_data:/from \
       -v target_data:/to \
       alpine \
       sh -c "cd /from && tar -cf - . | (cd /to && tar -xf -)"
  • cd /from && tar -cf - .: 轉到 /from,並將當前目錄(.)的內容打包為 tar,發送到 標準輸出(-而不是文件。

  • | (cd /to && tar -xf -): 通過管道(|)接收標準輸出,然後在 /to 目錄解壓 tar

Volume-to-Host(壓縮備份)

將 source_data 卷的內容壓縮為 backup.tar.gz 文件並儲存到主機上。

docker run --rm \
       -v source_data:/data:ro \
       -v $(pwd):/backup \
       alpine \
       tar -czf /backup/backup.tar.gz -C /data .
  • tar -czf /backup/backup.tar.gz ...: c(創建),z(gzip 壓縮),f(文件)創建 /backup/backup.tar.gz 文件。

  • -C /data .: 此部分很重要。首先將工作目錄更改為 /data,然後將其內部的所有內容進行壓縮。這樣,tar 文件內部將不包含多餘的 /data 路徑。

技巧 2: 將主機檔案恢復到卷中

恢復與備份相反,遵循相同的原理僅需反轉 cp 的方向。

# 將 $(pwd)/backup 目錄中的數據恢復到 new_data 卷中
docker run --rm \
       -v new_data:/data \
       -v $(pwd)/backup:/backup:ro \
       alpine \
       cp -a /backup/. /data/

總結

處理 Docker 卷的核心在於“使用容器作為工具”的思維方式。與其直接操縱主機上的卷文件,不如啟動一個同時掛載所需卷和目錄的臨時容器,然後在其中安全執行 cptar 等標準 Linux 命令。

只要記住這一原理,您就能自由地在任何情況下複製、備份和恢復卷數據。