Docker的數據管理(volume/bind mount/tmpfs)

Docker提供了三種不一樣的方式用於將宿主的數據掛載到容器中:volumes,bind mounts,tmpfs volumes。當你不知道該選擇哪一種方式時,記住,volumes老是正確的選擇。html

volumes是Docker數據持久化機制。bind mounts依賴主機目錄結構,volumes徹底由Docker管理。Volumes有如下優勢:
  • Volumes更容易備份和移植。
  • 能夠經過Docker CLI或API進行管理
  • Volumes能夠無區別的工做中Windows和Linux下。
  • 多個容器共享Volumes更安全。
  • Volume驅動能夠容許你把數據存儲到遠程主機或者雲端,而且加密數據內容,以及添加額外功能。
  • 一個新的數據內容能夠由容器預填充。
並且,volumes不會增長容器的大小,生命週期獨立與容器。
 

 
若是你的容器產生不須要持久化數據,請使用tmpfs mount方式,能夠避免容器的寫入層數據寫入。

 

雖然咱們能夠在docker容器中保存寫入的數據,但仍是有這樣幾個不足:node

  1. 容器中的數據會隨着容器的中止運行而消失, 並且當其餘的進程須要這些數據時,很難將這些數據從容器中提取出來;
  2. 容器的數據寫入層是緊密地對應着他的宿主操做系統的,數據不能容易的被遷移到其餘地方;
  3. 要將數據寫入到容器的數據寫入層,須要一個特定的存儲驅動,利用linux內核構建一個統一的文件系統,來管理宿主和容器的文件系統。這層額外的虛擬化顯然會下降性能。爲了不性能降低,docker使用data volumes的方式,直接對宿主文件系統進行寫操做。

選擇正確的掛載類型

不管選擇哪一種掛載方式,在容器內部看來,數據就是數據,並無什麼不一樣。主機的數據在容器的文件系統中總被顯示爲目錄或文件。如何簡單的理解這三種掛載方式的不一樣之處呢,咱們能夠理解爲在這三種方式下,容器內的數據在宿主機中存放的位置不一樣,見下圖:
 
  1. Volumes方式下:容器內的數據被存放到宿主機(linux)一個特定的目錄下(/var/lib/docker/volumes/)。這個目錄只有Docker能夠管理,其餘進程不能修改。若是想持久保存容器的應用數據,Volumes是Docker推薦的掛載方式。
  2. Bind mounts方式下:容器內的數據被存放到宿主機文件系統的任意位置,甚至存放到一些重要的系統目錄或文件中。除了Docker以外的進程也能夠任意對他們進行修改;
  3. tmpfs方式下:容器的數據只會存放到宿主機的內存中,不會被寫到宿主機的文件系統中,所以不能持久保存容器的應用數據。

詳細介紹三種掛載方式

Volumes: 
  • 由Docker進程建立和管理。能夠經過命令docker volume create來建立一個指定的卷,也能夠由Docker進程在建立容器或服務的過程當中來建立;
  • 當你爲一個容器建立一個volume時,這個volume將會被存儲到宿主機的一個目錄下。當你掛載這個volume到一個容器中時,就是在掛載這個目錄到容器中。這和bind mount的工做機制很類似,固然,除了volume是被Docker所管理並與宿主機其餘核心功能隔離以外。
  • 一個volume能夠被同時掛載到多個容器中。當沒有任何容器在使用這個volume的時候,這個volume也仍然能夠被Docker進程所使用,而不是自動被刪除。固然,你可使用命令手動刪除volume:docker volume prune
  • 當你掛載一個volume時,能夠選擇爲他命名(named),也能夠不命名(anonymous). 若是不命名的話,當這個volume首次被掛載到一個容器中時,Docker進程會分配給它一個隨機的名字,以保證在宿主機操做系統中這個volume的名字惟一。除了名字以外,命名和不命名的volume沒有區別。
  • Volume也支持使用volume drivers,以幫助你將數據保存到遠程主機或雲上。
Bind mounts:
  • 在docker的早期版本中就存在的功能,與volumes相比,他的功能比較侷限。當使用bind mounts時,宿主機的目錄或文件被掛載到容器中。容器將按照掛載目錄或文件的絕對路徑來使用或修改宿主機的中的數據。宿主機中的目錄或文件不須要預先存在,在須要的時候會自動建立。使用Bind mounts在性能上是很是好的,但這依賴於宿主機有一個目錄妥善結構化的文件系統。若是你要建立一個新的Docker應用,咱們仍推薦使用named volume的方式,由於你沒法經過Docker CLI來管理bind mounts。(警告:bind mounts是一把雙刃劍,由於使用bind mounts的容器能夠在經過容器內部的進程對主機文件系統進行修改,包括建立,修改和刪除重要的系統文件和目錄,這個功能雖然很強大,但顯然也會形成安全方面的影響,包括影響到宿主機上Docker之外的進程)
tmpfs mounts:
  • 在這種掛載方式下,容器內的應用數據將不會被持久的保存到硬盤上,其中的數據只能在某個容器的生存週期內被使用,或者用於保存一些不須要持久存儲,或一些敏感的數據信息。好比,在docker內部,swarm服務使用tmpfs方式來將secrets掛載到服務的容器中。(關於secrets,參考https://docs.docker.com/engine/swarm/secrets/)
Bind mounts和volumes均可以經過使用標誌-v或--volume來掛載到容器中,只是格式有些許不一樣。tmpfs可使用標誌--tmpfs進行掛載。然而,在Docker17.06及其以上版本中,咱們推薦使用--mount來對容器或服務進行這三種方式的掛載,由於這種格式更加清晰。

Volume的適用場景

  • 多個容器間須要共享數據。若是volume沒有手動被建立,它將會在首次掛載到某個容器以前被自動建立,當容器被中止或刪除時,這個volume不會隨之被刪除。多個容器能夠同時以rw或ro的方式掛載這個volume。只有手動指定刪除volume,它纔會被刪除。
  • 當宿主機並無專用於Docker的文件系統結構時。使用volume可使宿主機的配置與容器的運行解耦。
  • 當你但願將數據保存到遠程主機或雲上。
  • 當你但願在不一樣的宿主機直接備份/恢復/遷移數據時,volume是一個很好的選擇。你能夠中止運行使用volume的容器,而後直接備份volume所在的目錄便可,如/var/lib/docker/volumes/<volume-name>

bind mounts的適用場景

  • 將宿主機的系統配置文件共享給容器,這是Docker爲容器提供DNS配置的默認方式,即經過bind mounts的方式將宿主的的/etc/resolv.conf文件掛載到容器中。
  • 將宿主機開發環境中的源代碼或實驗結果共享給容器。例如:你在宿主機上進行一個項目Maven的測試,每次你在宿主機上對Maven項目進行了更改後,容器就能夠直接獲取更改後的結果
  • 當你能夠肯定宿主機的文件系統結構應該與容器內部徹底一致時。

tmpfs的適用場景

  • 當你出於安全緣由,或者容器性能優化的緣由(如須要寫入大量的不持久的狀態數據時),不須要容器的數據長久保存時可使用這種方式。

使用bind mounts和volumes的小Tips

  • 若是你使用volumes的方式掛載了一個空的volume到某個容器的一個非空目錄中,則這個非空目錄中已存在的內容會被拷貝到這個volume中。相似的,若是在啓動容器時指定了一個不存在的volume,一個空的volume會被自動建立;
  • 若是使用bind mounts的方式掛載,或者用volumes的方式掛載了一個非空的volume到容器的一個非空目錄中,則容器中這個非空目錄下的內容將暫時被掛載過來的volume中的內容所覆蓋(並未被刪除),當取消掛載後,容器中那個非空目錄中的文件仍然存在。就像在linux下的/mnt目錄下若是存在一些文件,在把USB掛載到/mnt時,在/mnt下就只能看到USB中的內容而看不見原先的文件,當取消USB掛載後,再進入/mnt就能夠看見原先的文件了。

選擇使用 -v仍是--mount

 
起初,-v或者--volume用於獨立容器,--mount用於swarm services。然而,從Docker 17.06開始,也但是使用--mount用於獨立容器。—mount命令更精準詳細。-v將選項進行了合併。使用--mount。
 
若是你須要制定volume驅動選項,你必須使用 --mount。
  • -v或者--volume:由3部分參數組成,使用「:」間隔。順序不能顛倒。
    • 第一個部分是volumes名字,在宿主機上具備惟一性。匿名卷名字系統給出。
    • 第二部分是掛載到容器裏的文件或文件夾路徑。
    • 第三部分是可選項列表分隔符,例如「or」,這些可選項在下面會討論。
  •     —mount:由多個鍵值對組成,<key>=<value>。—mount要比-v或者--volume命令更長,可是更容易理解。
    • type,能夠是bind,volume或者tmpfs。這篇文章主要討論volumes,因此type一直使用volume.
    • source,volumes的名字,匿名volume能夠省略。source可縮寫爲src.
    • destination,掛載到容器中的文件或目錄路徑。可也縮寫爲dst或者使用target。
    • readonly,指定掛載在容器中爲只讀。
    • volume-opt,可選屬性,能夠屢次使用。

-v和--mount的不一樣行爲

與bind mounts不一樣,對於—mount和-v全部的選項均可以使用。
當使用volumes服務時,只支持--mount.
 

建立和管理volumes

不像bind mount,你能夠在容器外建立和管理volumes。
 
建立一個volume:
$ docker volume create my-vol
 
顯示全部volumes
$ docker volume ls
local               my-vol
 
查看volumes
$ docker volume inspect my-vol
[
{
"Driver": "local",
        "Labels": {},
        "Mountpoint": "/var/lib/docker/volumes/my-vol/_data",
        "Name": "my-vol",
        "Options": {},
        "Scope": "local"
}
]
 
刪除一個volume:
$ docker volume rm my-vol
 
啓動一個帶volume的容器
若是你啓動一個帶有volume容器,volume尚未建立,Docker會爲你建立。下面的例子掛載myvol2到容器中的/app/下。
下面的例子-v和—mount結果是同樣的。
 
--mount:
$ docker run -d \
--name devtest \
--mount source=myvol2,target=/app \
  nginx:latest
 
-v:
$ docker run -d \
--name devtest \
-v myvol2:/app \
  nginx:latest
使用inspect查看掛載是否正確,查看Mounts部分:
"Mounts": [
{
"Type": "volume",
"Name": "myvol2",
"Source": "/var/lib/docker/volumes/myvol2/_data",
"Destination": "/app",
"Driver": "local",
"Mode": "",
"RW": true,
"Propagation": ""
}
],
能夠看出掛載正確,而且是可讀寫的。
 
中止容器而後刪除volume
$ docker container stop devtest
$ docker container rm devtest
$ docker volume rm myvol2
啓動一個帶有volumes服務
當你啓動服務定義一個volume,每一個服務可使用本身本地人volume.若是你使用local volume,容器不能分享數據,可是一些volume驅動支持分享存儲。Docker for AWS and Docker for Azure使用Cloudstor插件都支持持久化存儲。
下面的例子啓動4份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。
使用容器加載一個volume
 
和上面同樣,若是你啓動一個容器建立一個新的volume,在容器被掛載的目錄(/app/)中有文件或者文件夾,這個目錄中的內容會被拷貝到volume中。而後容器掛載使用volume,其餘容器使用這個volume也能夠訪問預加載內容。
爲了說明這個,這個例子啓動一個nginx容器而且加載一個新volume nginx-vol,裏面包括容器中/usr/share/nginx/html 目錄中的內容,裏面存儲的是nginx默認的HTML內容。
--mount and -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
使用只讀volume
 
對於一些開發應用,容器須要回寫數據到Docker主機。但有時容器只須要讀數據。請記住多個容器能夠掛載相同volume,一個掛載讀寫容器,也能夠掛載只讀容器,還能夠兩種同時掛載。
這個例子修改上面的例子,可是掛載的是隻讀容器,使用’or’分隔符處理選項列表,
--mount and -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)的volume。
Volume驅動容許你在應用中抽象下層的存儲系統。例如,若是你的服務使用NFS驅動volume,你可使用不一樣的驅動更新服務,就像存儲在雲中的數據,不須要修改應用邏輯。
使用volume驅動
當你使用docker volume create建立一個volume,或者當你啓動一個帶有沒建立volume的容器,你能夠指定volume驅動。下面例子使用vieux/sshfs volume驅動 ,首先建立一個獨立的volume,而後啓動一個建立新volume的容器。
 
初始化設置
這個例子假設你有兩個節點,第一個是Docker主機並且能夠鏈接到第二個的ssh.
在Docker主機中安裝vieux/sshfs插件:
$ docker plugin install --grant-all-permissions vieux/sshfs
 
使用volume驅動建立volume
這個樣例指定一個SSH密碼,可是若是兩個主機共享keys配置,你能夠省略密碼。每一個volume驅動能夠沒有或者更多配置選項,可使用-o標識。
$ docker volume create --driver vieux/sshfs \
-o sshcmd=test@node2:/home/test \
-o password=testpassword \
  sshvolume
 
test@node2:/home/test 爲遠程主機掛載點
 
啓動一個帶有使用volume驅動建立volume的容器
這個樣例指定一個SSH密碼,可是若是兩個主機共享keys配置,你能夠省略密碼。每一個volume驅動能夠沒有或者更多配置選項。若是volume驅動要穿可選參數,你必須使用—mount。
$ 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
相關文章
相關標籤/搜索