磁碟區
磁碟區是保存 Docker 容器產生和使用之資料的首選機制。雖然繫結掛載取決於主機的目錄結構和作業系統,但磁碟區則完全由 Docker 管理。磁碟區比繫結掛載有幾個優點:
- 磁碟區比繫結掛載更容易備份或遷移。
- 您可以使用 Docker CLI 命令或 Docker API 管理磁碟區。
- 磁碟區適用於 Linux 和 Windows 容器。
- 磁碟區可以在多個容器之間更安全地共享。
- 磁碟區驅動程式可讓您將磁碟區儲存在遠端主機或雲端提供商上、加密磁碟區的內容或新增其他功能。
- 新的磁碟區可以由容器預先填入其內容。
- Docker Desktop 上的磁碟區比 Mac 和 Windows 主機的繫結掛載效能高得多。
此外,磁碟區通常比在容器的可寫入層中保存資料更好,因為磁碟區不會增加使用它的容器的大小,而且磁碟區的內容存在於特定容器的生命週期之外。


如果您的容器產生非永久狀態資料,請考慮使用 tmpfs 掛載,以避免將資料永久儲存在任何地方,並透過避免寫入容器的可寫入層來提高容器的效能。
磁碟區使用 rprivate
繫結傳播,且繫結傳播無法針對磁碟區進行設定。
選擇 -v 或 --mount 旗標
一般來說,--mount
更明確且更詳細。最大的差異在於 -v
語法將所有選項組合在一個欄位中,而 --mount
語法則將它們分開。以下是每個旗標語法的比較。
如果您需要指定磁碟區驅動程式選項,則必須使用 --mount
。
-v
或--volume
:由三個欄位組成,以冒號 (:
) 分隔。這些欄位必須按正確的順序排列,而且每個欄位的含義並不立即可見。- 如果是具名磁碟區,則第一個欄位是磁碟區的名稱,並且在指定的zh-TW: 主機上是唯一的。如果是匿名磁碟區,則會省略第一個欄位。
- 第二個欄位是檔案或目錄在容器中掛載的路徑。
- 第三個欄位是選擇性的,它是由逗號分隔的選項清單,例如
ro
。這些選項將在下方討論。
--mount
:由多個鍵值對組成,以逗號分隔,每個鍵值對都包含一個<key>=<value>
元組。--mount
語法比-v
或--volume
更詳細,但鍵的順序並不重要,而且旗標的值更容易理解。- 掛載的
type
,可以是bind
、volume
或tmpfs
。本主題討論磁碟區,因此類型始終是volume
。 - 掛載的
source
。如果是具名磁碟區,則這是磁碟區的名稱。如果是匿名磁碟區,則會省略此欄位。可以指定為source
或src
。 destination
的值是檔案或目錄在容器中掛載的路徑。可以指定為destination
、dst
或target
。volume-subpath
選項採用磁碟區中子目錄的路徑來掛載到容器中。子目錄必須在將磁碟區掛載到容器之前存在於磁碟區中。請參閱掛載磁碟區子目錄。- 如果存在
readonly
選項,則會導致繫結掛載以唯讀方式掛載到容器中。可以指定為readonly
或ro
。 - 可以指定多次的
volume-opt
選項,採用由選項名稱及其值組成的鍵值對。
- 掛載的
警告
如果您的磁碟區驅動程式接受逗號分隔清單作為選項,則您必須從外部 CSV 解析器逸出該值。要逸出
volume-opt
,請用雙引號 ("
) 將其括起來,並用單引號 ('
) 將整個掛載參數括起來。例如,
local
驅動程式接受以逗號分隔的掛載選項列表作為o
參數。這個例子展示了正確的列表跳脫方式。$ docker service create \ --mount 'type=volume,src=<VOLUME-NAME>,dst=<CONTAINER-PATH>,volume-driver=local,volume-opt=type=nfs,volume-opt=device=<nfs-server>:<nfs-path>,"volume-opt=o=addr=<nfs-address>,vers=4,soft,timeo=180,bg,tcp,rw"' --name myservice \ <IMAGE>
以下範例盡可能同時顯示 --mount
和 -v
語法,並以 --mount
優先。
-v
和 --mount
行為之間的差異
與繫結掛載相反,所有磁碟區選項都適用於 --mount
和 -v
旗標。
與服務搭配使用的磁碟區僅支援 --mount
。
建立和管理磁碟區
與繫結掛載不同,您可以在任何容器範圍之外建立和管理磁碟區。
建立磁碟區
$ docker volume create my-vol
列出磁碟區
$ docker volume ls
local my-vol
檢查磁碟區
$ docker volume inspect my-vol
[
{
"Driver": "local",
"Labels": {},
"Mountpoint": "/var/lib/docker/volumes/my-vol/_data",
"Name": "my-vol",
"Options": {},
"Scope": "local"
}
]
移除磁碟區
$ docker volume rm my-vol
使用磁碟區啟動容器
如果您使用尚不存在的磁碟區啟動容器,Docker 會為您建立磁碟區。以下範例將磁碟區 myvol2
掛載到容器中的 /app/
。
以下 -v
和 --mount
範例產生相同的結果。除非您在執行第一個範例後移除 devtest
容器和 myvol2
磁碟區,否則您無法同時執行它們。
$ docker run -d \
--name devtest \
--mount source=myvol2,target=/app \
nginx:latest
$ docker run -d \
--name devtest \
-v myvol2:/app \
nginx:latest
使用 docker inspect devtest
來驗證 Docker 是否已建立磁碟區並正確掛載。尋找 Mounts
區段
"Mounts": [
{
"Type": "volume",
"Name": "myvol2",
"Source": "/var/lib/docker/volumes/myvol2/_data",
"Destination": "/app",
"Driver": "local",
"Mode": "",
"RW": true,
"Propagation": ""
}
],
這顯示掛載是一個磁碟區,顯示正確的來源和目標,並且掛載是可讀寫的。
停止容器並移除磁碟區。請注意,移除磁碟區是一個單獨的步驟。
$ docker container stop devtest
$ docker container rm devtest
$ docker volume rm myvol2
將磁碟區與 Docker Compose 搭配使用
以下範例顯示具有磁碟區的單個 Docker Compose 服務
services:
frontend:
image: node:lts
volumes:
- myapp:/home/node/app
volumes:
myapp:
第一次執行 docker compose up
會建立一個磁碟區。當您隨後執行命令時,Docker 會重複使用相同的磁碟區。
您可以使用 docker volume create
在 Compose 之外直接建立磁碟區,然後在 compose.yaml
中參考它,如下所示
services:
frontend:
image: node:lts
volumes:
- myapp:/home/node/app
volumes:
myapp:
external: true
有關將磁碟區與 Compose 搭配使用的更多資訊,請參閱 Compose 規格中的磁碟區區段。
使用磁碟區啟動服務
當您啟動服務並定義磁碟區時,每個服務容器都會使用自己的本地磁碟區。如果您使用 local
磁碟區驅動程式,則任何容器都無法共用此資料。但是,某些磁碟區驅動程式確實支援共用儲存。
以下範例啟動一個具有四個複本的 nginx
服務,每個複本都使用名為 myvol2
的本地磁碟區。
$ docker service create -d \
--replicas=4 \
--name devtest-service \
--mount source=myvol2,target=/app \
nginx:latest
使用 docker service ps devtest-service
來驗證服務是否正在執行
$ docker service ps devtest-service
ID NAME IMAGE NODE DESIRED STATE CURRENT STATE ERROR PORTS
4d7oz1j85wwn devtest-service.1 nginx:latest moby Running Running 14 seconds ago
您可以移除服務以停止正在執行的任務
$ docker service rm devtest-service
移除服務不會移除服務建立的任何磁碟區。移除磁碟區是一個單獨的步驟。
服務的語法差異
docker service create
命令不支援 -v
或 --volume
旗標。將磁碟區掛載到服務的容器中時,您必須使用 --mount
旗標。
使用容器填入磁碟區
如果您啟動一個建立新磁碟區的容器,且該容器在要掛載的目錄(例如 /app/
)中具有檔案或目錄,Docker 會將目錄的內容複製到磁碟區中。然後,容器會掛載並使用該磁碟區,而使用該磁碟區的其他容器也可以存取預先填入的內容。
為了說明這一點,以下範例啟動一個 nginx
容器,並使用容器的 /usr/share/nginx/html
目錄的內容填入新的磁碟區 nginx-vol
。這是 Nginx 儲存其預設 HTML 內容的位置。
--mount
和 -v
範例具有相同的最終結果。
$ docker run -d \
--name=nginxtest \
--mount source=nginx-vol,destination=/usr/share/nginx/html \
nginx:latest
$ docker run -d \
--name=nginxtest \
-v nginx-vol:/usr/share/nginx/html \
nginx:latest
執行這些範例中的任何一個之後,請執行以下命令來清除容器和磁碟區。請注意,移除磁碟區是一個單獨的步驟。
$ docker container stop nginxtest
$ docker container rm nginxtest
$ docker volume rm nginx-vol
使用唯讀磁碟區
對於某些開發應用程式,容器需要寫入繫結掛載,以便將變更傳播回 Docker 主機。在其他情況下,容器只需要對資料的讀取權限。多個容器可以掛載相同的磁碟區。您可以同時將單個磁碟區掛載為某些容器的 read-write
(讀寫),以及其他容器的 read-only
(唯讀)。
以下範例變更了上述範例。它透過在容器內的掛載點之後,將 ro
新增到選項列表(預設為空)中,將目錄掛載為唯讀磁碟區。如果存在多個選項,您可以使用逗號分隔它們。
--mount
和 -v
範例具有相同的結果。
$ docker run -d \
--name=nginxtest \
--mount source=nginx-vol,destination=/usr/share/nginx/html,readonly \
nginx:latest
$ docker run -d \
--name=nginxtest \
-v nginx-vol:/usr/share/nginx/html:ro \
nginx:latest
使用 docker inspect nginxtest
來驗證 Docker 是否已正確建立唯讀掛載。尋找 Mounts
區段
"Mounts": [
{
"Type": "volume",
"Name": "nginx-vol",
"Source": "/var/lib/docker/volumes/nginx-vol/_data",
"Destination": "/usr/share/nginx/html",
"Driver": "local",
"Mode": "",
"RW": false,
"Propagation": ""
}
],
停止並移除容器,然後移除磁碟區。移除磁碟區是一個單獨的步驟。
$ docker container stop nginxtest
$ docker container rm nginxtest
$ docker volume rm nginx-vol
掛載磁碟區子目錄
將磁碟區掛載到容器時,您可以使用 --mount
旗標的 volume-subpath
參數指定要使用的磁碟區子目錄。您指定的子目錄必須在嘗試將其掛載到容器之前存在於磁碟區中;如果它不存在,則掛載會失敗。
如果您只想與容器共用磁碟區的特定部分,則指定 volume-subpath
很有用。例如,假設您有多個容器正在執行,並且您想要將每個容器的日誌儲存在共用磁碟區中。您可以在共用磁碟區中為每個容器建立一個子目錄,然後將子目錄掛載到容器。
以下範例建立一個 logs
磁碟區,並在磁碟區中初始化子目錄 app1
和 app2
。然後,它啟動兩個容器,並將 logs
磁碟區的其中一個子目錄掛載到每個容器。此範例假設容器中的程序將其日誌寫入 /var/log/app1
和 /var/log/app2
。
$ docker volume create logs
$ docker run --rm \
--mount src=logs,dst=/logs \
alpine mkdir -p /logs/app1 /logs/app2
$ docker run -d \
--name=app1 \
--mount src=logs,dst=/var/log/app1/,volume-subpath=app1 \
app1:latest
$ docker run -d \
--name=app2 \
--mount src=logs,dst=/var/log/app2,volume-subpath=app2 \
app2:latest
使用此設定,容器會將其日誌寫入 logs
磁碟區的個別子目錄。容器無法存取其他容器的日誌。
在機器之間共享資料
構建容錯應用程式時,您可能需要將同一個服務的多個複本設定為可以存取相同的檔案。


開發應用程式時,有幾種方法可以實現此目標。一種方法是在您的應用程式中新增邏輯,以將檔案儲存在雲端物件儲存系統(例如 Amazon S3)上。另一種方法是使用支援將檔案寫入外部儲存系統(例如 NFS 或 Amazon S3)的驅動程式來建立磁碟區。
磁碟區驅動程式允許您從應用程式邏輯中抽象化底層儲存系統。例如,如果您的服務使用具有 NFS 驅動程式的磁碟區,則您可以更新服務以使用不同的驅動程式。例如,將資料儲存在雲端中,而無需更改應用程式邏輯。
使用磁碟區驅動程式
當您使用 docker volume create
建立磁碟區時,或者當您啟動使用尚未建立的磁碟區的容器時,您可以指定磁碟區驅動程式。以下範例使用 vieux/sshfs
磁碟區驅動程式,首先在建立獨立磁碟區時使用,然後在啟動建立新磁碟區的容器時使用。
初始設定
以下範例假設您有兩個節點,第一個節點是 Docker 主機,並且可以使用 SSH 連線到第二個節點。
在 Docker 主機上,安裝 vieux/sshfs
外掛程式
$ docker plugin install --grant-all-permissions vieux/sshfs
使用磁碟區驅動程式建立磁碟區
此範例指定了 SSH 密碼,但如果兩個主機已設定共用金鑰,則可以排除密碼。每個磁碟區驅動程式可能有零個或多個可設定選項,您可以使用 -o
旗標指定每個選項。
$ docker volume create --driver vieux/sshfs \
-o sshcmd=test@node2:/home/test \
-o password=testpassword \
sshvolume
啟動使用磁碟區驅動程式建立磁碟區的容器
以下範例指定了 SSH 密碼。但是,如果兩個主機已設定共用金鑰,則可以排除密碼。每個磁碟區驅動程式可能都有零個或多個可組態選項。
注意事項
如果磁碟區驅動程式要求您傳遞任何選項,您必須使用
--mount
旗標來掛載磁碟區,而不是使用-v
。
$ docker run -d \
--name sshfs-container \
--mount type=volume,volume-driver=vieux/sshfs,src=sshvolume,target=/app,volume-opt=sshcmd=test@node2:/home/test,volume-opt=password=testpassword \
nginx:latest
建立使用 NFS 磁碟區的服務
以下範例顯示如何在建立服務時建立 NFS 磁碟區。它使用 10.0.0.10
作為 NFS 伺服器,並使用 /var/docker-nfs
作為 NFS 伺服器上的匯出目錄。請注意,指定的磁碟區驅動程式是 local
。
NFSv3
$ docker service create -d \
--name nfs-service \
--mount 'type=volume,source=nfsvolume,target=/app,volume-driver=local,volume-opt=type=nfs,volume-opt=device=:/var/docker-nfs,volume-opt=o=addr=10.0.0.10' \
nginx:latest
NFSv4
$ docker service create -d \
--name nfs-service \
--mount 'type=volume,source=nfsvolume,target=/app,volume-driver=local,volume-opt=type=nfs,volume-opt=device=:/var/docker-nfs,"volume-opt=o=addr=10.0.0.10,rw,nfsvers=4,async"' \
nginx:latest
建立 CIFS/Samba 磁碟區
您可以在 Docker 中直接掛載 Samba 共享,而無需在主機上設定掛載點。
$ docker volume create \
--driver local \
--opt type=cifs \
--opt device=//uxxxxx.your-server.de/backup \
--opt o=addr=uxxxxx.your-server.de,username=uxxxxxxx,password=*****,file_mode=0777,dir_mode=0777 \
--name cif-volume
如果您指定主機名稱而不是 IP,則需要 addr
選項。這讓 Docker 可以執行主機名稱查詢。
區塊儲存裝置
您可以將區塊儲存裝置(例如外接硬碟或硬碟分割區)掛載到容器。以下範例顯示如何建立和使用檔案作為區塊儲存裝置,以及如何將區塊裝置掛載為容器磁碟區。
重要
以下程序僅為範例。這裡說明的解決方案不建議作為一般做法。除非您對自己的操作充滿信心,否則請勿嘗試此方法。
區塊裝置掛載的運作方式
在底層,使用 local
儲存驅動程式的 --mount
旗標會呼叫 Linux 的 mount
系統呼叫,並將您傳遞給它的選項原封不動地轉發。Docker 並未在 Linux 核心支援的原生掛載功能之上實作任何額外功能。
如果您熟悉 Linux 的 mount
指令,您可以將 --mount
選項視為以下列方式轉發到 mount
指令
$ mount -t <mount.volume-opt.type> <mount.volume-opt.device> <mount.dst> -o <mount.volume-opts.o>
為了進一步說明,請考慮以下 mount
指令範例。此指令將 /dev/loop5
裝置掛載到系統上的 /external-drive
路徑。
$ mount -t ext4 /dev/loop5 /external-drive
從正在執行的容器的角度來看,以下 docker run
指令達到了類似的結果。使用此 --mount
選項執行容器,其設定掛載的方式與您從先前範例執行 mount
指令的方式相同。
$ docker run \
--mount='type=volume,dst=/external-drive,volume-driver=local,volume-opt=device=/dev/loop5,volume-opt=type=ext4'
您無法直接在容器內執行 mount
指令,因為容器無法存取 /dev/loop5
裝置。這就是 docker run
指令使用 --mount
選項的原因。
範例:在容器中掛載區塊裝置
以下步驟建立 ext4
檔案系統並將其掛載到容器中。您的系統的檔案系統支援取決於您正在使用的 Linux 核心版本。
建立檔案並配置一些空間給它
$ fallocate -l 1G disk.raw
在
disk.raw
檔案上建置檔案系統$ mkfs.ext4 disk.raw
建立迴圈裝置
$ losetup -f --show disk.raw /dev/loop5
注意事項
losetup
建立一個暫時的迴圈裝置,該裝置會在系統重新啟動後移除,或使用losetup -d
手動移除。執行將迴圈裝置掛載為磁碟區的容器
$ docker run -it --rm \ --mount='type=volume,dst=/external-drive,volume-driver=local,volume-opt=device=/dev/loop5,volume-opt=type=ext4' \ ubuntu bash
當容器啟動時,路徑
/external-drive
會將主機檔案系統中的disk.raw
檔案作為區塊裝置掛載。完成後,且裝置已從容器卸載,請卸載迴圈裝置以從主機系統中移除裝置
$ losetup -d /dev/loop5
備份、還原或遷移資料磁碟區
磁碟區適用於備份、還原和遷移。使用 --volumes-from
旗標建立掛載該磁碟區的新容器。
備份磁碟區
例如,建立一個名為 dbstore
的新容器
$ docker run -v /dbdata --name dbstore ubuntu /bin/bash
在下一個指令中
- 啟動一個新容器並從
dbstore
容器掛載磁碟區 - 將本機主機目錄掛載為
/backup
- 傳遞將
dbdata
磁碟區內容打包到/backup
目錄中backup.tar
檔案的指令。
$ docker run --rm --volumes-from dbstore -v $(pwd):/backup ubuntu tar cvf /backup/backup.tar /dbdata
當指令完成且容器停止時,它會建立 dbdata
磁碟區的備份。
從備份還原磁碟區
使用剛建立的備份,您可以將其還原到同一個容器,或還原到您在其他地方建立的另一個容器。
例如,建立一個名為 dbstore2
的新容器
$ docker run -v /dbdata --name dbstore2 ubuntu /bin/bash
然後,在新容器的資料磁碟區中解壓縮備份檔案
$ docker run --rm --volumes-from dbstore2 -v $(pwd):/backup ubuntu bash -c "cd /dbdata && tar xvf /backup/backup.tar --strip 1"
您可以使用上述技巧,利用您慣用的工具自動化備份、遷移和還原測試。
移除磁碟區
刪除容器後,Docker 資料磁碟區會持續存在。有兩種类型的磁碟區需要考慮
- 具名磁碟區具有來自容器外部的特定來源,例如,
awesome:/bar
。 - 匿名磁碟區沒有特定來源。因此,當容器被刪除時,您可以指示 Docker Engine 守护程序將其刪除。
移除匿名磁碟區
要自動移除匿名磁碟區,請使用 --rm
選項。例如,此指令會建立一個匿名的 /foo
磁碟區。當您移除容器時,Docker Engine 會移除 /foo
磁碟區,但不會移除 awesome
磁碟區。
$ docker run --rm -v /foo -v awesome:/bar busybox top
注意事項
如果另一個容器使用
--volumes-from
綁定磁碟區,則會*複製*磁碟區定義,並且在移除第一個容器後,匿名磁碟區也會保留。
移除所有磁碟區
要移除所有未使用的磁碟區並釋放空間
$ docker volume prune
後續步驟
- 瞭解更多關於 繫結掛載 的資訊。
- 瞭解更多關於 tmpfs 掛載 的資訊。
- 瞭解更多關於 儲存驅動程式 的資訊。
- 瞭解更多關於 第三方磁碟區驅動程式外掛 的資訊。