Docker 基礎知識 - 使用卷(volume)管理應用程序數據

卷(volumes)是 Docker 容器生產和使用持久化數據的首選機制。綁定掛載(bind mounts)依賴於主機的目錄結構,卷(volumes)徹底由 Docker 管理。卷與綁定掛載相比有幾個優點:html

  • 卷比綁定掛載更容易備份或遷移。
  • 您可使用 Docker CLI 命令或 Docker API 來管理卷。
  • 卷能夠在 Linux 和 Windows 容器上工做。
  • 卷能夠更安全地在多個容器之間共享。
  • 卷驅動程序容許您在遠程主機或雲提供商上存儲卷、加密卷的內容或添加其餘功能。
  • 新卷的內容能夠由容器預先填充。(New volumes can have their content pre-populated by a container.)

此外,與將數據持久化到容器的可寫層相比,卷一般是更好的選擇,由於卷不會增長使用它的容器的大小,並且卷的內容存在於給定容器的生命週期以外。node

docker-types-of-mounts-volume

若是容器生成非持久性狀態數據,請考慮使用 tmpfs 掛載(tmpfs mount)以免將數據永久存儲在任何位置,並經過避免寫入容器的可寫層來提升容器的性能。nginx

卷使用 rprivate 綁定傳播,而且綁定傳播對於卷是不可配置的。docker

選擇 -v 或 --mount 標記

最初,-v--volume 標記用於獨立容器,--mount 標記用於集羣服務。可是,從 Docker 17.06 開始,您也能夠將 --mount 用於獨立容器。一般,--mount 標記表達更加明確和冗長。最大的區別是 -v 語法將全部選項組合在一個字段中,而 --mount 語法將選項分離。下面是每一個標記的語法比較。ubuntu

新用戶推薦使用 --mount 語法,它比 --volume 語法更簡單。安全

若是須要指定卷驅動程序選項,則必須使用 --mountbash

  • -v--volume: 由三個字段組成,以冒號(:)分隔。字段必須按照正確的順序排列,且每一個字段的含義不夠直觀明顯。
    • 對於命名卷,第一個字段是卷的名稱,在給定的主機上是唯一的。對於匿名卷,省略第一個字段。
    • 第二個字段是容器中文件或目錄掛載的路徑。
    • 第三個字段是可選的,是一個逗號分隔的選項列表,好比 ro。這些選項會在本文下面討論。
  • --mount:由多個鍵-值對組成,以逗號分隔,每一個鍵-值對由一個 <key>=<value> 元組組成。--mount 語法比 -v--volume 更冗長,可是鍵的順序並不重要,標記的值也更容易理解。
    • 掛載的類型(type),能夠是 bindvolume 或者 tmpfs。本主題討論卷(volume),所以類型(type)始終爲卷(volume)。
    • 掛載的源(source),對於命名卷,這是卷的名稱。對於匿名卷,此字段被省略。能夠用 source 或者 src 來指定。
    • 目標(destination),將容器中文件或目錄掛載的路徑做爲其值。能夠用 destinationdst 或者 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

在機器之間共享數據

在構建故障容錯的應用程序時,您可能須要配置同一服務的多個副本,以訪問相同的文件。

volumes-shared-storage

在開發應用程序時,有幾種方法能夠實現這一點。一種方法是向您的應用程序添加邏輯,在雲對象存儲系統(如 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 卷的服務

此示例顯示如何在建立服務時建立 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=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
  • 匿名卷沒有特定的源,所以當容器被刪除時,通知 Docker 引擎守護進程刪除它們。

刪除匿名卷

要自動刪除匿名卷,請使用 --rm 選項。例如,這個命令建立一個匿名的 /foo 卷。當容器被刪除時,Docker 引擎會刪除 /foo 卷,但不會刪除 awesome 卷。

$ docker run --rm -v /foo -v awesome:/bar busybox top

刪除全部卷

要刪除全部未使用的卷並釋放空間,請執行如下操做:

$ docker volume prune

做者 : Docker 官網
譯者 : 技術譯民
出品 : 技術譯站
連接 : 英文原文

相關文章
相關標籤/搜索