前一篇隨筆中咱們瞭解了docker的網絡相關說明,回顧請參考http://www.javashuo.com/article/p-upglxrrl-hs.html;今天咱們來聊一聊docker的數據管理相關說明;html
在前面的博客中咱們有強調過docker的鏡像是分層構建的,把鏡像啓動爲容器後,docker會加載只讀層鏡像並在鏡像最頂層添加一個讀寫層;咱們還說過該讀寫層不屬於鏡像屬於容器;若是該容器宕掉了,那麼隨之鏡像最頂層的讀寫層也隨之消失;那麼問題來了,若是以前運行的容器,在宕掉前在可寫層生成的數據怎麼保存下來呢?爲了解決這個問題,咱們先來看看docker的COW機制吧;node
如上圖所示,docker鏡像是分層構建的,在最下面一層的數據到第二層或更高層有相同數據時,在上面一層的數據就會覆蓋下面一層相同的數據;從而使得在上面一層和下面一層相同的數據只會存在一份,不一樣的數據都會存在;一樣的道理,docker鏡像經過層層鏡像構建,在docker鏡像最頂層看到的數據就應該是下面若干層重疊之後,相同的數據在最上層只會看到一份,而其餘數據則是由下面若干層不一樣數據的疊加構成;在運行層容器時,容器內部看到的數據就是全部層鏡像不一樣數據的集合和相同數據留一份的結果;若是運行過程當中容器修改了現有文件,那麼該文件就從讀寫層下面去複製一份到讀寫層,該文件的原來在只讀層的文件仍是存在,只是已經被讀寫層把該文件的副本隱藏了,這就叫docker的寫時複製(cow)機制;linux
從上面的信息咱們瞭解到docker容器在產生數據是在可寫層,在修改數據時,會把原來的數據從原來只讀層複製到可寫層,從而隱藏原來的只讀層的,可是隻讀層的數據還在;因此容器刪除後,咱們修改的數據不會保存到鏡像,而是隨容器的刪除而刪除;關閉並重啓容器對於數據不受什麼影響;咱們如今有沒有一種辦法讓讀寫層的數據保存起來,即使容器被刪除後數據還依然可存在呢?nginx
先來講說nfs數據共享吧;nfs共享是經過把一個目錄經過網絡的形式掛載到另一個目錄;從而實現往一個目錄寫數據時,就至關於把數據寫到遠端的目錄的文件中;在docker容器中咱們把這種相似的方式叫作卷;所謂卷就是容器上的一個或多個目錄,此類目錄可繞過聯合文件系統,與宿主機上的某目錄產生關聯關係(綁定,相似nfs裏的掛載);volume於容器初始化之時就會建立,由base image提供的卷中的數據會在此期間完成複製;volume的初衷是獨立於容器的生命週期實現數據持久化,所以刪除容器時,既不會刪除卷,也不會對那些沒有被引用的卷做垃圾回收操做;web
卷爲docker提供了獨立於容器的數據管理機制;咱們能夠把鏡像想象成靜態文件,例如程序,把卷類比成動態內容,好比數據,因而鏡像能夠複用,而卷能夠共享;卷實現了程序(鏡像)和數據(卷)的分離;實現了容器之間的數據共享和複用,使得容器間傳遞數據變得高效方便;對數據卷內數據的修改會立馬生效,不管是在容器中修改仍是在本地操做;docker有兩種類型的卷,每種類型都在容器中存在一個掛載點,但其在宿主機上的位置有所不一樣而已;bind mount volume這種卷是由用戶指定目錄把存儲上的一個目錄掛載到容器內部的某個目錄;docekr-managed volume這種卷是docker本身管理的卷,一般表現形式上把宿主機上的/var/lib/docker/vfs/dir/某個卷的ID 掛載到容器內部某個目錄下;docker
示例:在的docker容器中使用docker-managed 類型的volumecentos
[root@node1 ~]# docker run --name m2 -it --rm -v /mydata linux1874/myimg:v0.1 /bin/sh / # ls / bin dev etc home mydata proc root sys tmp usr var / # cd /mydata/ /mydata # ls /mydata # [root@node1 ~]# docker container inspect m2 -f {{.Mounts}} [{volume 65db95bc3010530381e2bcc20fdd216329a502527e17a1e70c1cb7f6e2d2a422 /var/lib/docker/volumes/65db95bc3010530381e2bcc20fdd216329a502527e17a1e70c1cb7f6e2d2a422/_data /mydata local true }] [root@node1 ~]# ll /var/lib/docker/volumes/65db95bc3010530381e2bcc20fdd216329a502527e17a1e70c1cb7f6e2d2a422/_data total 0 [root@node1 ~]# echo "hello world" > /var/lib/docker/volumes/65db95bc3010530381e2bcc20fdd216329a502527e17a1e70c1cb7f6e2d2a422/_data/aa.txt [root@node1 ~]# cat /var/lib/docker/volumes/65db95bc3010530381e2bcc20fdd216329a502527e17a1e70c1cb7f6e2d2a422/_data/aa.txt hello world [root@node1 ~]# docker attach m2 /mydata # ls aa.txt /mydata # cat aa.txt hello world /mydata #
提示:-v只指定了一個目錄表示指定容器內部的目錄,它會經過docker daemon 自動在宿主機上生成掛載目錄;像這種方式的掛載就叫作docker -managed類型的數據卷;從上面的信息能夠看到咱們能夠用docker container inspect -f {{.Mounts}} 容器名稱,來查看容器的卷、標識符以及掛載點主機目錄信息;咱們在生成的掛載目錄下建立一個aa.txt的文件,而後在容器裏/mydata裏可以看到該文件和文件內容;bash
測試:咱們把容器停掉看看數據卷是否會被刪除呢?網絡
[root@node1 ~]# cat /var/lib/docker/volumes/65db95bc3010530381e2bcc20fdd216329a502527e17a1e70c1cb7f6e2d2a422/_data/aa.txt hello world [root@node1 ~]# docker attach m2 /mydata # ls aa.txt /mydata # cat aa.txt hello world /mydata # exit [root@node1 ~]# [root@node1 ~]# docker ps CONTAINER ID IMAGE COMMAND CREATED STATUS PORTS NAMES 33c6f135eb86 linux1874/myimg:v0.1 "/bin/sh -c '/bin/ht…" 20 minutes ago Up 20 minutes m1 [root@node1 ~]# cat /var/lib/docker/volumes/65db95bc3010530381e2bcc20fdd216329a502527e17a1e70c1cb7f6e2d2a422/_data/aa.txt cat: /var/lib/docker/volumes/65db95bc3010530381e2bcc20fdd216329a502527e17a1e70c1cb7f6e2d2a422/_data/aa.txt: No such file or directory [root@node1 ~]#
提示:在運行容器時若是使用了--rm選項,但容器停掉之後,對應掛載點數據卷會隨之刪除;curl
測試:運行容器不使用--rm選項,看看容器停掉後,是否還會刪除數據卷?
[root@node1 ~]# docker run --name m2 -v /mydata -it linux1874/myimg:v0.1 /bin/sh / # ls / bin dev etc home mydata proc root sys tmp usr var / # cd mydata/ /mydata # ls /mydata # [root@node1 ~]# docker container inspect -f {{.Mounts}} m2 [{volume 28c477840d926c2fc33ebfacd607b84cfd5a272d279e1f966a65b7cb2f1d9a2e /var/lib/docker/volumes/28c477840d926c2fc33ebfacd607b84cfd5a272d279e1f966a65b7cb2f1d9a2e/_data /mydata local true }] [root@node1 ~]# cd /var/lib/docker/volumes/28c477840d926c2fc33ebfacd607b84cfd5a272d279e1f966a65b7cb2f1d9a2e/_data [root@node1 _data]# ls [root@node1 _data]# echo "hello tom" > aa.txt [root@node1 _data]# cat aa.txt hello tom [root@node1 _data]# docker attach m2 /mydata # ls aa.txt /mydata # cat aa.txt hello tom /mydata # exit [root@node1 _data]#docker ps -a CONTAINER ID IMAGE COMMAND CREATED STATUS PORTS NAMES e6560584d41e linux1874/myimg:v0.1 "/bin/sh" About a minute ago Exited (0) 9 seconds ago m2 33c6f135eb86 linux1874/myimg:v0.1 "/bin/sh -c '/bin/ht…" 32 minutes ago Up 32 minutes m1 [root@node1 _data]# docker container rm m2 m2 [root@node1 _data]# docker ps -a CONTAINER ID IMAGE COMMAND CREATED STATUS PORTS NAMES 33c6f135eb86 linux1874/myimg:v0.1 "/bin/sh -c '/bin/ht…" 35 minutes ago Up 35 minutes m1 [root@node1 _data]# cd [root@node1 ~]# cd - /var/lib/docker/volumes/28c477840d926c2fc33ebfacd607b84cfd5a272d279e1f966a65b7cb2f1d9a2e/_data [root@node1 _data]# ls aa.txt [root@node1 _data]# cat aa.txt hello tom [root@node1 _data]#
提示:在不使用--rm選項運行容器,容器中止後刪除容器,對於數據卷是不會被刪除的;
示例:在docker容器中使用bind-mount 類型volume
[root@node1 ~]# mkdir /hostdir/v1 -p [root@node1 ~]# docker run --name m3 -it -v /hostdir/v1/:/mydata linux1874/myimg:v0.1 /bin/sh / # ls / bin dev etc home mydata proc root sys tmp usr var / # cd /mydata/ /mydata # ls /mydata # [root@node1 ~]# docker container inspect -f {{.Mounts}} m3 [{bind /hostdir/v1 /mydata true rprivate}] [root@node1 ~]# cd /hostdir/v1/ [root@node1 v1]# ls [root@node1 v1]# echo "hello jerry" > aa.sh [root@node1 v1]# cat aa.sh hello jerry [root@node1 v1]# docker attach m3 /mydata # ls aa.sh /mydata # cat aa.sh hello jerry /mydata # exit [root@node1 v1]# docker ps -a CONTAINER ID IMAGE COMMAND CREATED STATUS PORTS NAMES 62ddbdc11a62 linux1874/myimg:v0.1 "/bin/sh" About a minute ago Exited (0) 4 seconds ago m3 33c6f135eb86 linux1874/myimg:v0.1 "/bin/sh -c '/bin/ht…" 41 minutes ago Up 41 minutes m1 [root@node1 v1]# docker container rm m3 m3 [root@node1 v1]# cd [root@node1 ~]# cd - /hostdir/v1 [root@node1 v1]# ls aa.sh [root@node1 v1]# cat aa.sh hello jerry [root@node1 v1]#
提示:-v指定宿主機目錄:容器目錄表示把宿主機目錄掛載到容器的某個目錄;容器裏的目錄能夠是不存在的目錄,它會自動建立;這種數據卷咱們叫作bind-mount類型的數據卷;一般表現形式就是用戶本身定義把宿主機的那個目錄看成數據卷掛載到容器裏的某個目錄;和上面同樣咱們在宿主機上的對應目錄下建立文件,在容器對應目錄是能夠正常訪問到該文件的;-v可以使用屢次來指定不一樣的數據卷掛載關係;一般bind-mount類型的卷用的比較多;
示例:多個容器的卷使用同一宿主機目錄
[root@node1 ~]# ll /hostdir/v1/aa.sh -rw-r--r-- 1 root root 12 May 24 13:59 /hostdir/v1/aa.sh [root@node1 ~]# cat /hostdir/v1/aa.sh hello jerry [root@node1 ~]# docker ps -a CONTAINER ID IMAGE COMMAND CREATED STATUS PORTS NAMES [root@node1 ~]# docker run --name m1 -d -v /hostdir/v1/:/var/www/web/html linux1874/myimg:v0.1 9eb3287e4007f0656b1f099aac9504724307679ac41689774059388a96d75cf0 [root@node1 ~]# docker container inspect -f {{.Mounts}} m1 [{bind /hostdir/v1 /var/www/web/html true rprivate}] [root@node1 ~]# docker container inspect -f {{.NetworkSettings.IPAddress}} m1 172.17.0.2 [root@node1 ~]# curl http://172.17.0.2 <HTML><HEAD><TITLE>404 Not Found</TITLE></HEAD> <BODY><H1>404 Not Found</H1> The requested URL was not found </BODY></HTML> [root@node1 ~]# curl http://172.17.0.2/aa.sh hello jerry [root@node1 ~]# docker run --name m2 -d -v /hostdir/v1/:/var/www/web/html linux1874/myimg:v0.1 ff877e29d10c55b355b5270218d486894958880058e2eb7bef9bdd1c7c531f0f [root@node1 ~]# docker container inspect -f {{.Mounts}} m2 [{bind /hostdir/v1 /var/www/web/html true rprivate}] [root@node1 ~]# docker container inspect -f {{.NetworkSettings.IPAddress}} m2 172.17.0.3 [root@node1 ~]# curl http://172.17.0.3 <HTML><HEAD><TITLE>404 Not Found</TITLE></HEAD> <BODY><H1>404 Not Found</H1> The requested URL was not found </BODY></HTML> [root@node1 ~]# curl http://172.17.0.3/aa.sh hello jerry [root@node1 ~]#
提示:數據卷掛載到容器會覆蓋容器原有文件;這個同mount掛載沒有本質的不一樣;從上面信息能夠看到aa.sh就把原有的index.html給覆蓋了;除了以上方式指定掛載同一宿主機目錄外,咱們還可使用--volumes-from選項來指定從那個容器裏複製數據掛載到本容器;以下
[root@node1 ~]# docker run --name m3 -d --volumes-from m1 linux1874/myimg:v0.1 61a1fbdc9c559a594870dc1e2bbf505a4eb588fc03e5ab50233b55b907beb9b0 [root@node1 ~]# docker container inspect -f {{.Mounts}} m3 [{bind /hostdir/v1 /var/www/web/html true rprivate}] [root@node1 ~]# docker container inspect -f {{.NetworkSettings.IPAddress}} m3 172.17.0.4 [root@node1 ~]# curl http://172.17.0.4/aa.sh hello jerry [root@node1 ~]# docker images REPOSITORY TAG IMAGE ID CREATED SIZE linux1874/myimg v0.1 e408b1c6e04f 38 hours ago 1.22MB busybox latest 78096d0a5478 10 days ago 1.22MB centos 7 b5b4d78bc90c 2 weeks ago 203MB nginx stable-alpine ab94f84cc474 4 weeks ago 21.3MB [root@node1 ~]# docker run --name c1 -it --volumes-from m1 centos:7 /bin/sh sh-4.2# ls / anaconda-post.log dev home lib64 mnt proc run srv tmp var bin etc lib media opt root sbin sys usr sh-4.2# cat /var/www/web/html/aa.sh hello jerry sh-4.2#
示例:以只讀方式掛載數據卷
[root@node1 ~]# docker ps -a CONTAINER ID IMAGE COMMAND CREATED STATUS PORTS NAMES [root@node1 ~]# docker images REPOSITORY TAG IMAGE ID CREATED SIZE linux1874/myimg v0.1 e408b1c6e04f 38 hours ago 1.22MB busybox latest 78096d0a5478 10 days ago 1.22MB centos 7 b5b4d78bc90c 2 weeks ago 203MB nginx stable-alpine ab94f84cc474 4 weeks ago 21.3MB [root@node1 ~]# docker run --name c1 -it -v /hostdir/v1/:/mydata:ro centos:7 /bin/sh sh-4.2# ls / anaconda-post.log dev home lib64 mnt opt root sbin sys usr bin etc lib media mydata proc run srv tmp var sh-4.2# cd mydata/ sh-4.2# ls aa.sh sh-4.2# echo "hello tom" > aa.sh sh: aa.sh: Read-only file system sh-4.2# exit exit [root@node1 ~]# docker run --name c2 -it -v /hostdir/v1/:/mydata centos:7 /bin/sh sh-4.2# cd /mydata/ sh-4.2# ls aa.sh sh-4.2# echo "hello tom" > aa.sh sh-4.2# cat aa.sh hello tom sh-4.2# exit exit [root@node1 ~]#
提示:咱們掛載數據卷不指定權限默認是rw,以讀寫方式掛載;指定權限爲ro(只讀)掛載數據卷後,在容器內部就不能修改數據卷裏的文件內容了;
示例:利用容器備份另外一容器的數據
[root@node1 ~]# ll /hostdir/v1/ total 4 -rw-r--r-- 1 root root 10 May 24 14:42 aa.sh [root@node1 ~]# echo "hello world" > /hostdir/v1/bb.sh [root@node1 ~]# echo "hello world,hello tom" > /hostdir/v1/cc.sh [root@node1 ~]# ls /hostdir/v1/ aa.sh bb.sh cc.sh [root@node1 ~]# docker run --name m1 -d -v /hostdir/v1/:/var/www/web/html linux1874/myimg:v0.1 5959e832c01f68c24e2542138a95eb7bfeabcb7608b070ef1b536c625ddfd612 [root@node1 ~]# docker run --name c1 --volumes-from m1 -v $(pwd):/backup centos:7 tar cvf /backup/backup.tar.gz /var/www/web/html tar: Removing leading `/' from member names /var/www/web/html/ /var/www/web/html/aa.sh /var/www/web/html/bb.sh /var/www/web/html/cc.sh [root@node1 ~]# ls backup.tar.gz [root@node1 ~]# tar xf backup.tar.gz [root@node1 ~]# ls backup.tar.gz var [root@node1 ~]# cd var/www/web/html/ [root@node1 html]# ls aa.sh bb.sh cc.sh [root@node1 html]# cat aa.sh bb.sh cc.sh hello tom hello world hello world,hello tom [root@node1 html]#
提示:解釋下上面利用容器備份另外一容器裏的數據;首先經過--volumes-from來克隆m1的數據卷,而後在經過-v來指定把當前路徑掛載到容器內部的/backup目錄下,而後經過啓動容器執行tar cvf /backup/backup.tar.gz /var/www/web/html來把容器裏的/var/www/web/html的文件打包到/backup/backup.tar.gz(容器內部的目錄);可以在當前目錄看到打包的文件緣由是由於咱們把當前路徑掛載到容器裏的/backup目錄,因此咱們在當前宿主機目錄可以看到打包好的文件;
示例:利用容器恢復剛纔打包的數據文件
首先運行一個容器
[root@node1 ~]# docker ps -a CONTAINER ID IMAGE COMMAND CREATED STATUS PORTS NAMES 5959e832c01f linux1874/myimg:v0.1 "/bin/sh -c '/bin/ht…" 15 minutes ago Up 15 minutes m1 [root@node1 ~]# docker run --name m2 -it -v /var/www/web/html linux1874/myimg:v0.1 /bin/sh / # ls /var/www/web/html/ index.html / # [root@node1 ~]#
而後在來一容器克隆以前容器的數據卷,經過掛載當前目錄爲數據卷,在執執行 tar xf命令來解包
[root@node1 ~]# docker ps -a CONTAINER ID IMAGE COMMAND CREATED STATUS PORTS NAMES 6462f22e0d7f linux1874/myimg:v0.1 "/bin/sh" 2 minutes ago Up 2 minutes m2 5959e832c01f linux1874/myimg:v0.1 "/bin/sh -c '/bin/ht…" 22 minutes ago Up 21 minutes m1 [root@node1 ~]# docker run --name c2 --volumes-from m2 -v $(pwd):/backup centos:7 tar xf /backup/backup.tar.gz [root@node1 ~]# docker attach m2 / # ls bin dev etc home proc root sys tmp usr var / # ls /var/www/web/html/ aa.sh bb.sh cc.sh index.html / # cd /var/www/web/html/ /var/www/web/html # cat aa.sh bb.sh cc.sh hello tom hello world hello world,hello tom /var/www/web/html #
提示:以上命令的思想是運行容器C2 把m2的數據卷掛載先克隆到c2上,而後經過掛載當前宿主機目錄到容器的/backup,而後再執行解包操做便可;這裏還須要注意一點,若是容器的工做目錄不是根目錄或者是其餘特殊目錄,解壓命令能夠經過-C來指定解壓到那個目錄;