docker有四種存儲方式:1、“默認儲存”,數據保存在運行的容器中,容器刪除后,數據也隨之刪除;2、“volumes數據卷”;3、“bind mounts掛載”,直接掛載主機文件系統的任何目錄或文件;4、“tmpfs mount”。
本教程操作環境:linux5.9.8系統、docker-1.13.1版、Dell G3電腦。
docker容器的幾種存儲方式
容器的存儲可以分為兩大類:
一種是與鏡像相關的即我們在《docker容器技術基礎之聯合文件系統OverlayFS》一文提到的容器層copy-On-Write特性。默認情況下,在容器內創建的所有文件都存儲在可寫容器層上,這種直接將文件存儲在容器層的方式數據難以持久化和共享,由于依賴存儲驅動與使用直接寫入主機文件系統的數據卷相比,這種額外的抽象會降低性能 。
另一中是宿主機存儲即通過將宿主機目錄綁定或掛在到容器中使用,容器停止后數據也能持久化。主要介紹后者。
幾種存儲掛載方式
這里我們根據數據存儲在 Docker 主機上的不同位置繪制如下圖:
docker四種存儲方式:默認、volumes數據卷、bind mounts掛載、tmpfs mount(僅在linux環境中提供),其中volumes、bind mounts兩種實現持久化容器數據。
1.默認儲存
數據保存在運行的容器中,容器刪除后,數據也隨之刪除
2.bind mounts
綁定掛載與卷相比,功能有限。使用綁定掛載時,主機上的文件或目錄會掛載到容器中。文件或目錄由其在主機上的完整路徑引用。目錄不需要已經存在于 Docker 主機上,如果不存在,docker會幫我們創建。 注意一下,只能自動創建目錄哦。
我們通過 -v 選項綁定掛載一個目錄 /nginx/html 到容器中看看
docker?run?-dt?-v?/nginx/html:/usr/share/nginx/html?--name?nginx?nginx
通過docker inspect nginx 查看容器 Mounts字段
"Mounts":?[ ????{ ????????"Type":?"bind", ????????"Source":?"/nginx/html", ????????"Destination":?"/usr/share/nginx/html", ????????"Mode":?"", ????????"RW":?true, ????????"Propagation":?"rprivate" ????} ],
接著我們在docker主機上創建一個index.html并寫入hello nginx,然后訪問容器IP,顯然我們的掛載已經生效了。
[root@localhost?~]#?echo?"hello?nginx"?>??/nginx/html/index.html [root@localhost?~]#?curl?172.17.0.4 hello?nginx
這里有一個問題,我們可以通過docker主機修改文件使容器內文件生效,反過來也一樣,容器可以修改、創建和刪除主機文件系統上的內容。處理這個問題我們可以在創建容器的時候配置掛載目錄的權限,比如下面的只讀權限:
docker?run?-dt?-v?/nginx/html:/usr/share/nginx/html:ro?--name?nginx?nginx
所以在我們使用綁定掛載的時候,你操作的是主機文件系統,你必須清楚如下:
你掛載的目錄包含哪些內容,以免對其他應用造成影響。
你的容器是否應該有權操作這些目錄。
3.volumes數據卷
volume存儲卷由 Docker 創建和管理,我們可以使用該docker volume create命令顯式的創建卷,或者在容器創建時創建卷。
[root@localhost?~]#?docker?volume?create?nginx_volume nginx_volume [root@localhost?volumes]#?docker?inspect??nginx_volume [ ????{ ????????"CreatedAt":?"2021-08-12T01:58:04-04:00", ????????"Driver":?"local", ????????"Labels":?{}, ????????"Mountpoint":?"/var/lib/docker/volumes/nginx_volume/_data", ????????"Name":?"nginx_volume", ????????"Options":?{}, ????????"Scope":?"local" ????} ]
可以看到掛載點處于docker的根目錄/var/lib/docker/volumes下
通過docker volume rm/prune 清除單個或所有未再使用的卷,可以通過docker 命令來管理卷是對比綁定掛載的一個優勢。
[root@localhost?~]#?docker?volume?ls DRIVER????VOLUME?NAME local?????owncloud-docker-server_files local?????owncloud-docker-server_mysql local?????owncloud-docker-server_redis [root@localhost?~]#?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: owncloud-docker-server_files owncloud-docker-server_mysql owncloud-docker-server_redis Total?reclaimed?space:?199.4MB
在創建容器時如果未指定容器掛載的源則docker會自動為我們創建一個匿名卷,同樣位于docker根目錄下。
[root@localhost?volumes]#?docker?run?-dt?-v?/usr/share/nginx/html?--name?nginx_with_volume?nginx d25bdfce9c7ac7bde5ae35067f6d9cf9f0cd2c9cbea6d1bbd7127b3949ef5ac6 [root@localhost?volumes]#?docker?volume?ls? DRIVER????VOLUME?NAME local?????d8e943f57d17a255f8a4ac3ecbd6471a735aa64cc7a606c52f61319a6c754980 local?????nginx_volume [root@localhost?volumes]#?ls?/var/lib/docker/volumes/ backingFsBlockDev??d8e943f57d17a255f8a4ac3ecbd6471a735aa64cc7a606c52f61319a6c754980??metadata.db??nginx_volume
當我們創建掛載卷之后,此時的存儲與bind mounts是一致,不過當 docker 主機不能保證具有給定的目錄或文件結構時,卷可幫助我們將 docker 主機的配置與容器運行時分離。這樣一來當我們需要將數據從一臺 Docker 主機備份、還原或遷移到另一臺時,卷就很方便了,可以脫離host path的限制。
在使用綁定掛載和卷時我們要注意下面傳播覆蓋原則:
掛載一個空卷時:容器內目錄的內容會傳播(復制)到卷中。
綁定掛載或非空卷時:容器內目錄的內容會被卷或綁定的主機目錄覆蓋。
4.tmpfs mount
tmpfs掛載僅適用于linux主機,當我們使用tmpfs掛載創建容器時,容器可以在容器的可寫層之外創建文件。將數據保留在內存中,當容器停止時,寫入的數據也將被移除。主要用于臨時存儲不想保留在主機或容器可寫層中的敏感文件。
通過–tmpfs選項掛載一個內存塊。
docker?run?-dt?--name?busybox_tmpfs?--tmpfs?/etc/running?busybox
通過–mount的方式帶上參數,指定臨時存儲大小。
docker?run?-dt?--name?busybox_tmpfs2?--mount?type=tmpfs,tmpfs-size=2048,destination=/etc/running?busybox
存儲數據共享
在容器之間共享數據主要有兩種方法,第一種比較簡單,只需要將目錄或者volume掛載到多個容器中即可。這里不做贅述,我們來看一下通過中間容器實現共享的方式。
我們創建一個中間容器,包含綁定掛載目錄和一個卷。
docker?create?-v?/share:/volume1?-v?/volume2??--name?volume_share??busybox
在我們需要共享的容器中通過選項–volumes-from拿過來用即可
docker?run?-d?-t?--volumes-from?volume_share??--name?container1??busybox
我們inspect檢查一下Mounts字段,此時container1已經掛載到了一個bind目錄和一個volume
"Mounts":?[ ????{ ????????"Type":?"bind", ????????"Source":?"/share", ????????"Destination":?"/volume1", ????????"Mode":?"", ????????"RW":?true, ????????"Propagation":?"rprivate" ????}, ????{ ????????"Type":?"volume", ????????"Name":?"21605e49a0ba90a1b952a32c1b3f0d42735da8bfe718f0dc76c37e91f1e51c0e", ????????"Source":?"/var/lib/docker/volumes/21605e49a0ba90a1b952a32c1b3f0d42735da8bfe718f0dc76c37e91f1e51c0e/_data", ????????"Destination":?"/volume2", ????????"Driver":?"local", ????????"Mode":?"", ????????"RW":?true, ????????"Propagation":?"" ????} ],
推薦學習:《docker視頻教程》