在介紹VOLUME指令以前,咱們來看下以下場景需求:html
1)容器是基於鏡像建立的,最後的容器文件系統包括鏡像的只讀層+可寫層,容器中的進程操做的數據持久化都是保存在容器的可寫層上。一旦容器刪除後,這些數據就沒了,除非咱們人工備份下來(或者基於容器建立新的鏡像)。可否可讓容器進程持久化的數據保存在主機上呢?這樣即便容器刪除了,數據還在。linux
2)當咱們在開發一個web應用時,開發環境是在主機本地,但運行測試環境是放在docker容器上。web
這樣的話,我在主機上修改文件(如html,js等)後,須要再同步到容器中。這顯然比較麻煩。docker
3)多個容器運行一組相關聯的服務,若是他們要共享一些數據怎麼辦?數據庫
對於這些問題,咱們固然能想到各類解決方案。而docker自己提供了一種機制,能夠將主機上的某個目錄與容器的某個目錄(稱爲掛載點、或者叫卷)關聯起來,容器上的掛載點下的內容就是主機的這個目錄下的內容,這相似linux系統下mount的機制。 這樣的話,咱們修改主機上該目錄的內容時,不須要同步容器,對容器來講是當即生效的。 掛載點可讓多個容器共享。ubuntu
下面咱們來介紹具體的機制。bash
1、經過docker run命令測試
一、運行命令:docker run --name test -it -v /home/xqh/myimage:/data ubuntu /bin/bashspa
其中的 -v 標記 在容器中設置了一個掛載點 /data(就是容器中的一個目錄),並將主機上的 /home/xqh/myimage 目錄中的內容關聯到 /data下。3d
這樣在容器中對/data目錄下的操做,仍是在主機上對/home/xqh/myimage的操做,都是徹底實時同步的,由於這兩個目錄實際都是指向主機目錄。
二、運行命令:docker run --name test1 -it -v /data ubuntu /bin/bash
上面-v的標記只設置了容器的掛載點,並無指定關聯的主機目錄。這時docker會自動綁定主機上的一個目錄。經過docker inspect 命令能夠查看到。
xqh@ubuntu:~/myimage$ docker inspect test1 [ { "Id": "1fd6c2c4bc545163d8c5c5b02d60052ea41900a781a82c20a8f02059cb82c30c", ............................. "Mounts": [ { "Name": "0ab0aaf0d6ef391cb68b72bd8c43216a8f8ae9205f0ae941ef16ebe32dc9fc01", "Source": "/var/lib/docker/volumes/0ab0aaf0d6ef391cb68b72bd8c43216a8f8ae9205f0ae941ef16ebe32dc9fc01/_data", "Destination": "/data", "Driver": "local", "Mode": "", "RW": true } ], ...........................
上面 Mounts下的每條信息記錄了容器上一個掛載點的信息,"Destination" 值是容器的掛載點,"Source"值是對應的主機目錄。
能夠看出這種方式對應的主機目錄是自動建立的,其目的不是讓在主機上修改,而是讓多個容器共享。
2、經過dockerfile建立掛載點
上面介紹的經過docker run命令的-v標識建立的掛載點只能對建立的容器有效。
經過dockerfile的 VOLUME 指令能夠在鏡像中建立掛載點,這樣只要經過該鏡像建立的容器都有了掛載點。
還有一個區別是,經過 VOLUME 指令建立的掛載點,沒法指定主機上對應的目錄,是自動生成的。
#test FROM ubuntu MAINTAINER hello1 VOLUME ["/data1","/data2"]
上面的dockfile文件經過VOLUME指令指定了兩個掛載點 /data1 和 /data2.
咱們經過docker inspect 查看經過該dockerfile建立的鏡像生成的容器,能夠看到以下信息
"Mounts": [ { "Name": "d411f6b8f17f4418629d4e5a1ab69679dee369b39e13bb68bed77aa4a0d12d21", "Source": "/var/lib/docker/volumes/d411f6b8f17f4418629d4e5a1ab69679dee369b39e13bb68bed77aa4a0d12d21/_data", "Destination": "/data1", "Driver": "local", "Mode": "", "RW": true }, { "Name": "6d3badcf47c4ac5955deda6f6ae56f4aaf1037a871275f46220c14ebd762fc36", "Source": "/var/lib/docker/volumes/6d3badcf47c4ac5955deda6f6ae56f4aaf1037a871275f46220c14ebd762fc36/_data", "Destination": "/data2", "Driver": "local", "Mode": "", "RW": true } ],
能夠看到兩個掛載點的信息。
3、容器共享卷(掛載點)
docker run --name test1 -it myimage /bin/bash
上面命令中的 myimage是用前面的dockerfile文件構建的鏡像。 這樣容器test1就有了 /data1 和 /data2兩個掛載點。
下面咱們建立另外一個容器能夠和test1共享 /data1 和 /data2卷 ,這是在 docker run中使用 --volumes-from標記,如:
能夠是來源不一樣鏡像,如:
docker run --name test2 -it --volumes-from test1 ubuntu /bin/bash
也能夠是同一鏡像,如:
docker run --name test3 -it --volumes-from test1 myimage /bin/bash
上面的三個容器 test1 , test2 , test3 均有 /data1 和 /data2 兩個目錄,且目錄中內容是共享的,任何一個容器修改了內容,別的容器都能獲取到。
4、最佳實踐:數據容器
若是多個容器須要共享數據(如持久化數據庫、配置文件或者數據文件等),能夠考慮建立一個特定的數據容器,該容器有1個或多個卷。
其它容器經過--volumes-from 來共享這個數據容器的卷。
由於容器的卷本質上對應主機上的目錄,因此這個數據容器也不須要啓動。
如: docker run --name dbdata myimage echo "data container"
說明:有個卷,容器之間的數據共享比較方便,但也有不少問題須要解決,如權限控制、數據的備份、卷的刪除等。這些內容後續文章介紹。