Docker實踐(三):數據持久化及共享

環境說明:

主機名 操作系統版本 IP地址 docker版本
ubuntu1604 Ubuntu 16.04.5 172.27.9.31 18.09.2

ubuntu安裝詳見:Ubuntu16.04.5以lvm方式安裝全記錄
docker安裝詳見:Ubuntu16.04安裝Docker
 在Linux上運行的Docker有三種不同的方式將數據從 Docker Host掛載到 Docker 容器,並實現數據的讀取和存儲:volumes、bind mounts、tmpfs。  
三者的區別在於數據存儲在docker主機的位置不同。

Docker實踐(三):數據持久化及共享

  • Volumes(又稱docker managed volume)儲在主機文件系統的中,由docker管理(在Linux上默認位置爲/var/lib/docker/volumes/),只有Docker進程能修改該位置,Volumes是在Docker中保存數據的最佳方式。
  • Bind mounts可以存儲在主機系統的任何位置,可能是重要的系統文件或目錄,Docker主機或Docker容器上的非Docker進程可以隨時修改它們。
  • tmpfs掛載僅存儲在主機系統的內存中,不寫入主機系統的文件系統。 

一、Volumes

簡介

volumes(也被稱爲Docker-managed volumes)是保存Docker容器生成和使用的數據的首選機制。相較於bind mounts依賴於主機的目錄結構,volumes完全由Docker管理。與bind mounts相比,volumes有幾個優勢:

  • 與bind mounts相比,volumes更容易備份或遷移。
  • 可以使用docker cli命令或docker api管理volumes。
  • volumes可以在Linux和Windows容器上工作。
  • 可以更安全地在多個容器之間共享volumes。
  • Volume drivers可以實現在遠程主機或雲主機存儲數據以供加密卷的內容,或添加其他功能。
  • 新的volumes可以通過容器預先填充其內容。

此外,volumes通常比在容器的可寫層中保存數據更好,因爲volumes不會增加使用它的容器的大小,並且volumes的內容存在於給定容器的生命週期之外(即使容器被銷燬volumes也會保存在docker host的文件系統中)
volumes在docker host的位置:
Docker實踐(三):數據持久化及共享

Volumes測試

1.新建Volume

root@ubuntu1604:~# docker volume create my-vol
my-vol

2.列出Volumes

root@ubuntu1604:~# docker volume ls
DRIVER              VOLUME NAME
local               my-vol

3.查看volume詳情

root@ubuntu1604:~# docker volume inspect my-vol
[
    {
        "CreatedAt": "2019-03-25T15:02:16+08:00",
        "Driver": "local",
        "Labels": {},
        "Mountpoint": "/var/lib/docker/volumes/my-vol/_data",
        "Name": "my-vol",
        "Options": {},
        "Scope": "local"
    }
]

volume 在host上的默認目錄爲:/var/lib/docker/volumes/$(VOLUME NAME)/_data
新建的volume內容爲空

root@ubuntu1604:~# ll /var/lib/docker/volumes/my-vol/_data
total 8
drwxr-xr-x 2 root root 4096 Mar 25 15:02 ./
drwxr-xr-x 3 root root 4096 Mar 25 15:02 ../

4.使用volume

4.1新建container

新建container myweb01並使用volume my-vol

root@ubuntu1604:~# docker run -d -p 80:80 -v my-vol:/usr/local/apache2/htdocs --name myweb01 httpd

容器myweb01的80端口被映射爲主機的80端口,my-vol被掛載到apache server存放靜態文件的目錄/usr/local/apache2/htdocs  

4.2訪問myweb01

root@ubuntu1604:~# curl 172.27.9.31:80
<html><body><h1>It works!</h1></body></html>

4.3再次查看volume內容

root@ubuntu1604:~# ll /var/lib/docker/volumes/my-vol/_data                                        
total 12
drwxr-sr-x 2 root www-data 4096 Mar 25 15:30 ./
drwxr-xr-x 3 root root     4096 Mar 25 15:02 ../
-rw-r--r-- 1 root src        45 Jun 12  2007 index.html
root@ubuntu1604:~# more /var/lib/docker/volumes/my-vol/_data/index.html 
<html><body><h1>It works!</h1></body></html>

發現容器myweb01的內容index.html被複制到volume中,這也印證了前面所講的volumes的特點之一:“新的volumes可以通過容器預先填充其內容” 

4.4更新數據並訪問

root@ubuntu1604:~# echo "update volumes:loong576" >/var/lib/docker/volumes/my-vol/_data/index.html 
root@ubuntu1604:~# curl 172.27.9.31:80                                                             
update volumes:loong576

更新volume中的index.html,發現容器myweb01的訪問內容也一併更新。  

4.5銷燬volume

root@ubuntu1604:~# docker rm -f -v myweb01
myweb01
root@ubuntu1604:~# more /var/lib/docker/volumes/my-vol/_data/index.html
update volumes:loong576
root@ubuntu1604:~# docker ps -a
CONTAINER ID        IMAGE               COMMAND             CREATED             STATUS              PORTS               NAMES
root@ubuntu1604:~# docker volume ls
DRIVER              VOLUME NAME
local               my-vol
root@ubuntu1604:~# docker volume prune
WARNING! This will remove all local volumes not used by at least one container.
Are you sure you want to continue? [y/N] y
Deleted Volumes:
my-vol

Total reclaimed space: 24B
root@ubuntu1604:~# docker volume ls   
DRIVER              VOLUME NAME
root@ubuntu1604:~# more /var/lib/docker/volumes/my-vol/_data/index.html
more: stat of /var/lib/docker/volumes/my-vol/_data/index.html failed: No such file or directory

當銷燬容器時,volume沒有被同時消除,留下孤兒volume,通過docker volume prune即可刪除   

二、Bind mounts  

簡介

 Docker早期就有了Bind mounts。與volumes相比,Bind mounts的功能有限。使用Bind mounts時,主機上的文件或目錄將裝載到容器中。文件或目錄由其在主機上的完整路徑或相對路徑引用。相反,使用卷時,會在主機上Docker的存儲目錄中創建一個新目錄,Docker管理該目錄的內容。

 對於Bind mounts,文件或目錄不需要已經存在於Docker主機上。如果它還不存在,則按需創建。Bind mounts的性能非常好,但它們依賴於主機的文件系統,該文件系統具有特定的可用目錄結構。如果您正在開發新的Docker應用程序,請考慮改用volumes。另外不能使用docker cli命令直接管理綁定裝載。
Bind mounts在docker host的位置:
Docker實踐(三):數據持久化及共享

Bind mounts測試

本文使用NFS作爲Bind mounts的掛載點
NFS搭建配置詳見:Centos7下NFS服務器搭建及客戶端連接配置

1.掛載nfs並新建index.html

root@ubuntu1604:~# mount -t nfs 172.27.9.181:/nfs /mywebtest 
root@ubuntu1604:~# df -h
Filesystem               Size  Used Avail Use% Mounted on
udev                     467M     0  467M   0% /dev
tmpfs                     98M  5.9M   92M   7% /run
/dev/mapper/rootvg-root  4.6G  539M  3.8G  13% /
/dev/mapper/rootvg-usr   4.6G  921M  3.5G  21% /usr
tmpfs                    488M     0  488M   0% /dev/shm
tmpfs                    5.0M     0  5.0M   0% /run/lock
tmpfs                    488M     0  488M   0% /sys/fs/cgroup
/dev/sda1                453M   59M  367M  14% /boot
/dev/mapper/rootvg-tmp   4.6G  9.6M  4.4G   1% /tmp
/dev/mapper/rootvg-opt   4.6G  9.6M  4.4G   1% /opt
/dev/mapper/rootvg-var   4.6G  470M  3.9G  11% /var
/dev/mapper/rootvg-home  4.6G  9.6M  4.4G   1% /home
cgmfs                    100K     0  100K   0% /run/cgmanager/fs
tmpfs                     98M     0   98M   0% /run/user/0
172.27.9.181:/nfs        6.0G   97M  5.9G   2% /mywebtest
root@ubuntu1604:~# cd /mywebtest/ && touch index.html && echo "bind mount webtest:loong576" > index.html
root@ubuntu1604:/mywebtest# more index.html 
bind mount webtest:loong576

/mywebtest被掛載到遠程的nfs服務器172.27.9.181的/nfs目錄,並在/mywebtest目錄新建index.html文件

2.新建container myweb02

root@ubuntu1604:~# docker run -d -p 81:80 -v /mywebtest/:/usr/local/apache2/htdocs --name myweb02 httpd
749a107648450a627a03fadc29680a0cdaff1e68ba10421ddebb52e2f7f7baf4

新建容器myweb02,將 /mywebtest掛載到容器/usr/local/apache2/htdocs,容器的80端口映射爲主機的81端口。

3.訪問myweb02

root@ubuntu1604:~# curl 172.27.9.31:81
bind mount webtest:loong576

發現訪問內容爲剛剛新建的index.html,bind mounts的內容覆蓋了了容器的index.html。

4.更新index.html

root@ubuntu1604:~# echo "update bind mount webtest:loong576 02" >/mywebtest/index.html 
root@ubuntu1604:~# curl 172.27.9.31:81                                                 
update bind mount webtest:loong576 02

更新index.html,訪問myweb02,發現一併更新

5.銷燬容器

root@ubuntu1604:~# docker rm -f myweb02
myweb02
root@ubuntu1604:~# docker ps -a        
CONTAINER ID        IMAGE               COMMAND             CREATED             STATUS              PORTS               NAMES
root@ubuntu1604:~# more /mywebtest/index.html 
update bind mount webtest:loong576 02

容器myweb02被銷燬,但是Bind mounts繼續存在。
volumes與bind mounts異同:

不同點 volumes bind mounts
Source位置 /var/lib/docker/volumes/... 可以任意指定
對已有掛載點影響 容器內數據複製到volume 覆蓋掉容器的內容
是否支持單個文件 不支持,只能是目錄 支持
權限控制 讀寫或者只讀 讀寫或者只讀
移植性 強,無需指定host目錄 弱,與host path綁定

三、tmpfs mounts

簡介

 volumes和bind mounts允許您在主機和容器之間共享文件,這樣即使容器停止,您也可以保留數據。
 如果您在Linux上運行docker,則有第三個選項:tmpfs mounts。當使用tmpfs裝載創建容器時,容器可以在容器的可寫層之外創建文件。
 與volumes和bind mounts不同,tmpfs掛載是臨時的,並且只持久存在於主機內存中。當容器停止時,tmpfs掛載將被刪除,在那裏寫入的文件將不會被持久化。
tmpfs mounts在docker host的位置:
Docker實踐(三):數據持久化及共享

tmpfs mounts測試

1.新建container myweb03

root@ubuntu1604:~# docker run -d -p 82:80 --tmpfs /web03 --name myweb03 httpd 

新建容器myweb03,容器對目錄/web03所有的讀寫操作都在內存中。

2.新建test.txt

root@ubuntu1604:~# docker exec -it myweb03 bash                              
root@f91161779960:/usr/local/apache2# cd /web03/ && echo tmpfs-test > test.txt
root@f91161779960:/web03# more test.txt 
tmpfs-test

在/web03中新建測試文件test.txt,重啓容器後觀察該文件是否存在。

3.重啓myweb03

root@ubuntu1604:~# docker stop myweb03
myweb03
root@ubuntu1604:~# docker start myweb03
myweb03
root@ubuntu1604:~# docker exec -it myweb03 bash
root@f91161779960:/usr/local/apache2# cd /web03/
root@f91161779960:/web03# ls -l
total 0

重啓容器,發現測試文件test.txt消失。

四、容器間的數據共享

bind mounts方式

 該方式爲依賴於主機的共享,多個容器通過 Volume 綁定到主機上的相同位置

1.新建index.html

root@ubuntu1604:~# echo "container datas share : bind mounts" > /mywebtest/index.html

2.新建container web01 web02 web03

root@ubuntu1604:~# docker run -d -p 7701:80 -v /mywebtest/:/usr/local/apache2/htdocs --name web01 httpd       
cfa46a13458aa650c2d3243460f38ef0a53d4f8d4643633b34edb1c257fa56f6
root@ubuntu1604:~# docker run -d -p 7702:80 -v /mywebtest/:/usr/local/apache2/htdocs --name web02 httpd 
4655998a69590653af9e41eaa92e48a3798666e79a70f55f9ca33d5c1e60ea05
root@ubuntu1604:~# docker run -d -p 7703:80 -v /mywebtest/:/usr/local/apache2/htdocs --name web03 httpd 
69e917fbbb20f8a5b886b14ffa05ee93d28461e551eaf4caf9abc0610f60943b

新建容器web01/web02/web03,將主機的/mywebtst分別掛載到容器的usr/local/apache2/htdocs目錄。

3.訪問web

root@ubuntu1604:~# curl 172.27.9.31:7701
container datas share : bind mounts
root@ubuntu1604:~# curl 172.27.9.31:7702
container datas share : bind mounts
root@ubuntu1604:~# curl 172.27.9.31:7703
container datas share : bind mounts

在/web03中新建測試文件test.txt,重啓容器後觀察該文件是否存在。

4.更新index.html

root@ubuntu1604:~# echo "container datas share 02 : bind mounts" > /mywebtest/index.html 
root@ubuntu1604:~# curl 172.27.9.31:7701                                                 
container datas share 02 : bind mounts
root@ubuntu1604:~# curl 172.27.9.31:7702
container datas share 02 : bind mounts
root@ubuntu1604:~# curl 172.27.9.31:7703
container datas share 02 : bind mounts

更新並再次訪問web,發現所有容器的web訪問頁面已更新。

Volume container方式

 創建一個容器專門用於定義Volumes(可以是上文提到的volumes也可以是bind mounts),這個容器可以不運行,因爲停止的容器也會保留對Volume的引用。然後其它的容器在創建或運行時通過--volumes-from從該容器複製Volume定義。 
使用該方式的注意事項:

  • 一般容器名加前綴 vc_,表示 volume container
  • 涉及的各容器對於 Volume 綁定的目錄位置及命名規範都必須協同一致

1.新建container vc_data

root@ubuntu1604:~# docker create -v /mywebtest/:/usr/local/apache2/htdocs -v /apps --name vc_data  busybox

使用的busybox無實際意義,該鏡像很小很適合測試

2.查看vc_data

root@ubuntu1604:~# docker inspect vc_data

Docker實踐(三):數據持久化及共享
/mywebtest/通過bind mounts方式掛載到容器/usr/local/apache2/htdocs目錄,卷6a635ec450eeecd487df4f25615c14443aa2a4da07b8c605a031d5ab9b5bbf47通過volume方式掛載至容器/apps目錄。

3.使用vc_data

root@ubuntu1604:~# docker run -d -p 7704:80 --volumes-from vc_data --name web04 httpd
25ff55566720281791f2b1956236204dbca6ad529fa460a76d80e970786df22d
root@ubuntu1604:~# docker run -d -p 7705:80 --volumes-from vc_data --name web05 httpd 
dcce95be79b1ecc888d748d684b814743583c5db1ac41f026ca4ed5525f51c67
root@ubuntu1604:~# docker run -d -p 7706:80 --volumes-from vc_data --name web06 httpd 
edd257edaf6101ee8911afeb08b70ec95673b5e1c64c774e2b00f1486b025ba8

新建容器web04/web05/web06並使用vc_data。

4.查看web04

root@ubuntu1604:~# docker inspect web04

Docker實踐(三):數據持久化及共享
掛載信息和vc_data一致。

5.共享驗證

root@ubuntu1604:~# echo "abc123" > /var/lib/docker/volumes/6a635ec450eeecd487df4f25615c14443aa2a4da07b8c605a031d5ab9b5bbf47/_data/test.txt
root@ubuntu1604:~# curl 172.27.9.31:7704
container datas share : Volume container
root@ubuntu1604:~# curl 172.27.9.31:7705
container datas share : Volume container
root@ubuntu1604:~# curl 172.27.9.31:7706
container datas share : Volume container
root@ubuntu1604:~# docker exec -it web04 bash
root@25ff55566720:/usr/local/apache2# cd /apps/ && ls -l
total 4
-rw-r--r-- 1 root root 7 Mar 27 08:12 test.txt
root@25ff55566720:/apps# more test.txt 
abc123

分別在共享目錄更新新建文件,各容器也能正常訪問讀取共享數據。

Data-packed volume container 方式

 這種模式擴展至Volume container模式。Data-packed volume container不僅定義Volumes,而且將從本容器的映像中的一些數據(如靜態文件、配置數據、代碼等)複製到這個定義的Volumes中,從而可與其它容器共享。

1.構建鏡像

配置查看

root@ubuntu1604:~# pwd
/root
root@ubuntu1604:~# ls
Dockerfile  htdocs
root@ubuntu1604:~# more htdocs/index.html 
container datas share : Data-packed volume
root@ubuntu1604:~# more Dockerfile 
FROM busybox
ADD htdocs /usr/local/apache2/htdocs
VOLUME /usr/local/apache2/htdocs

構建鏡像

root@ubuntu1604:~# docker build -t image_datapacked .
Sending build context to Docker daemon  18.43kB
Step 1/3 : FROM busybox
 ---> d8233ab899d4
Step 2/3 : ADD htdocs /usr/local/apache2/htdocs
 ---> d9266ad06c41
Step 3/3 : VOLUME /usr/local/apache2/htdocs
 ---> Running in c7d1cab717d4
Removing intermediate container c7d1cab717d4
 ---> f8f9f9c15171
Successfully built f8f9f9c15171
Successfully tagged image_datapacked:latest

通過Dockerfile方式構建鏡像,鏡像名爲image_datapacked

2.創建data-packed volume container

root@ubuntu1604:~# docker run -it  --name vc_datapacked image_datapacked
/ # cd /usr/local/apache2/htdocs/
/usr/local/apache2/htdocs # ls
index.html
/usr/local/apache2/htdocs # more index.html 
container datas share : Data-packed volume

運行data-packed volume container:vc_datapacked,可以看到之前寫進鏡像層的index.html:container datas share : Data-packed volume
查看vc_datapacked詳情

root@ubuntu1604:~# docker inspect vc_datapacked  

Docker實踐(三):數據持久化及共享
因爲在 Dockerfile中已經使用了VOLUME指令,這裏就不需要指定volume的 mount point了。
volume爲/var/lib/docker/volumes/3c37bc016de3018cb59292cdfca581893a77d19ba8b8f5538b04aab71b3603a1,容器掛載點爲/usr/local/apache2/htdocs

3.使用vc_datapacked

root@ubuntu1604:~# docker run -d -p 7707:80 --volumes-from vc_datapacked --name web_datapacked httpd

新建容器web_datapacked並使用vc_datapacked。

4.查看web_datapacked

root@ubuntu1604:~# docker inspect web_datapacked

Docker實踐(三):數據持久化及共享
volume爲/var/lib/docker/volumes/3c37bc016de3018cb59292cdfca581893a77d19ba8b8f5538b04aab71b3603a1,容器掛載點爲/usr/local/apache2/htdocs。掛載信息和vc_datapacked一致。

5.共享驗證

root@ubuntu1604:~# curl 172.27.9.31:7707
container datas share : Data-packed volume

訪問容器web_datapacked的web服務,返回結果與寫入鏡像image_datapacked的index.html一直,實現了靜態文件index.html

6.總結

  • 1.相較於volume container,data-packed volume container方式直接把共享數據寫進鏡像層,通過上傳至私有倉庫,其它docker host都能使用該鏡像實現容器的數據共享;
  • 2.data-packed volume container只適用於靜態數據共享;
  • 3.若要修改data-packed volume container中的共享數據,只能重建image,不能動態修改。

本文參考:
https://docs.docker.com/storage/
http://www.atjiang.com/persistent-storage-and-shared-state-with-volumes-in-docker/
https://blog.51cto.com/cloudman/1948779
 

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章