卷(volumes)是 Docker 容器生產和使用持久化數據的首選機制。綁定掛載(bind mounts)依賴於主機的目錄結構,卷(volumes)徹底由 Docker 管理。卷與綁定掛載相比有幾個優點:html
此外,與將數據持久化到容器的可寫層相比,卷一般是更好的選擇,由於卷不會增長使用它的容器的大小,並且卷的內容存在於給定容器的生命週期以外。node
若是容器生成非持久性狀態數據,請考慮使用 tmpfs 掛載(tmpfs mount)以免將數據永久存儲在任何位置,並經過避免寫入容器的可寫層來提升容器的性能。nginx
卷使用 rprivate
綁定傳播,而且綁定傳播對於卷是不可配置的。docker
最初,-v
或 --volume
標記用於獨立容器,--mount
標記用於集羣服務。可是,從 Docker 17.06 開始,您也能夠將 --mount
用於獨立容器。一般,--mount
標記表達更加明確和冗長。最大的區別是 -v
語法將全部選項組合在一個字段中,而 --mount
語法將選項分離。下面是每一個標記的語法比較。ubuntu
新用戶推薦使用
--mount
語法,它比--volume
語法更簡單。安全
若是須要指定卷驅動程序選項,則必須使用 --mount
。bash
-v
或 --volume
: 由三個字段組成,以冒號(:)分隔。字段必須按照正確的順序排列,且每一個字段的含義不夠直觀明顯。
ro
。這些選項會在本文下面討論。--mount
:由多個鍵-值對組成,以逗號分隔,每一個鍵-值對由一個 <key>=<value>
元組組成。--mount
語法比 -v
或 --volume
更冗長,可是鍵的順序並不重要,標記的值也更容易理解。
type
),能夠是 bind
、volume
或者 tmpfs
。本主題討論卷(volume),所以類型(type
)始終爲卷(volume
)。source
),對於命名卷,這是卷的名稱。對於匿名卷,此字段被省略。能夠用 source
或者 src
來指定。destination
),將容器中文件或目錄掛載的路徑做爲其值。能夠用 destination
、dst
或者 target
來指定。readonly
選項(若是存在),則會將綁定掛載以只讀形式掛載到容器中。volume-opt
選項,能夠被指定屢次,接受由選項名及其值組成的鍵-值對。從外部 CSV 解析器轉義值服務器
若是卷驅動程序接受以逗號分隔的列表做爲選項,則必須從外部 CSV 解析器轉義該值。要轉義
volume-opt
, 請使用雙引號(")將其括起來,並使用單引號(')將整個掛載參數括起來。app例如,本地(
local
)驅動程序在參數o
中接受以逗號分隔的列表做爲掛載選項。下面這個例子展現了轉義列表的正確寫法。ssh$ 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 # 輸出結果: DRIVER VOLUME NAME local my-vol
檢查卷:
$ docker volume inspect my-vol # 輸出結果: [ { "CreatedAt": "2020-07-04T07:06:47Z", "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/
中。
下面的 --mount
和 -v
示例會產生相同的結果。除非在運行第一個示例以後刪除了 devtest
容器和 myvol2
卷,不然不能同時運行它們。
--mount
:
$ docker run -d \ --name devtest \ --mount source=myvol2,target=/app \ nginx:latest
-v
:
$ docker run -d \ --name devtest \ -v myvol2:/app \ nginx:latest
使用 docker inspect devtest
驗證卷的建立和掛載是否正確。查看 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
啓動服務並定義卷時,每一個服務容器都使用本身的本地卷。 若是使用本地(local
)卷驅動程序,則沒有任何容器能夠共享此數據,但某些卷驅動程序確實支持共享存儲。Docker for AWS 和 Docker for Azure 都支持使用 Cloudstor 插件的持久存儲。
下面的示例使用四個副本啓動 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/
)中有文件或目錄,那麼該目錄的內容將複製到新卷中。而後容器掛載並使用該卷,使用該卷的其餘容器也能夠訪問預填充的內容。
爲了說明這一點,這個例子啓動了一個 nginx
容器,並用容器的 /usr/share/nginx/html
目錄中的內容填充新的卷 nginx-vol
,這個目錄是 Nginx 存儲默認的 HTML 內容的地方。
下面的 --mount
和 -v
示例具備相同的最終結果。
--mount
:
$ docker run -d \ --name=nginxtest \ --mount source=nginx-vol,destination=/usr/share/nginx/html \ nginx:latest
-v
:
$ 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 主機。在其餘時候,容器只須要對數據進行讀訪問。記住,多個容器能夠掛載相同的卷,而且能夠對其中一些容器以讀寫方式掛載,而對其餘容器以只讀方式掛載。
這個示例修改了上面的示例,可是經過在容器內的掛載點以後的選項列表(默認爲空)中添加 ro
,將目錄掛載爲只讀卷。當有多個選項時,使用逗號分隔它們。
下面 --mount
和 -v
示例有相同的結果。
--mount
:
$ docker run -d \ --name=nginxtest \ --mount source=nginx-vol,destination=/usr/share/nginx/html,readonly \ nginx:latest
-v
:
$ docker run -d \ --name=nginxtest \ -v nginx-vol:/usr/share/nginx/html:ro \ nginx:latest
使用 docker inspect nginxtest
驗證是否正確建立了只讀掛載。查看 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
在構建故障容錯的應用程序時,您可能須要配置同一服務的多個副本,以訪問相同的文件。
在開發應用程序時,有幾種方法能夠實現這一點。一種方法是向您的應用程序添加邏輯,在雲對象存儲系統(如 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 \ --volume-driver vieux/sshfs \ --mount src=sshvolume,target=/app,volume-opt=sshcmd=test@node2:/home/test,volume-opt=password=testpassword \ nginx:latest
此示例顯示如何在建立服務時建立 NFS 卷。本例使用 10.0.0.10
做爲 NFS 服務器,使用 /var/docker-nfs
做爲 NFS 服務器上的出口目錄。請注意,指定的卷驅動程序是 local
。
$ 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
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=10.0.0.10,rw,nfsvers=4,async"' \ nginx:latest
卷對於備份、還原和遷移很是有用。使用 --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
。要自動刪除匿名卷,請使用 --rm
選項。例如,這個命令建立一個匿名的 /foo
卷。當容器被刪除時,Docker 引擎會刪除 /foo
卷,但不會刪除 awesome
卷。
$ docker run --rm -v /foo -v awesome:/bar busybox top
要刪除全部未使用的卷並釋放空間,請執行如下操做:
$ docker volume prune