1. COW機制
Docker鏡像由多個只讀層疊加而成,啟動容器時,Docker會加載只讀鏡像層并在鏡像棧頂部添加一個讀寫層。
如果運行中的容器修改了現有的一個已經存在的文件,那么該文件將會從讀寫層下面的只讀層復制到讀寫層,該文件的只讀版本依然存在,只是已經被讀寫層中該文件的副本所隱藏,這就是“寫時復制(COW)”機制。
對于這種方式來說,我們去訪問一個文件,修改和刪除等一類的操作,其效率會非常的低,因為隔著很多層鏡像。
而要想繞過這種限制,我們可以通過使用存儲卷的機制來實現。
2. 什么是存儲卷
存儲卷就是將宿主機的本地文件系統中存在的某個目錄直接與容器內部的文件系統上的某一目錄建立綁定關系。這就意味著,當我們在容器中的這個目錄下寫入數據時,容器會將其內容直接寫入到宿主機上與此容器建立了綁定關系的目錄。
3. 使用存儲卷的好處
如果容器中跑的進程的所有有效數據都保存在存儲卷中,從而脫離容器自身文件系統之后,帶來的好處是當容器關閉甚至被刪除時,只要不刪除與此容器綁定的在宿主機上的這個存儲目錄,我們就不用擔心數據丟失了。因此就可以實現數據持久,脫離容器的生命周期而持久。
我們通過這種方式管理容器,容器就可以脫離主機的限制,可以在任意一臺部署了docker的主機上跑容器,而其數據則可以置于一個共享存儲文件系統上,比如nfs。
Docker的存儲卷默認情況下是使用其所在的宿主機上的本地文件系統目錄的,也就是說宿主機上有一塊屬于自己的硬盤,這個硬盤并沒有共享給其他的Docker主機,而在這臺主機上啟動的容器所使用的存儲卷是關聯到此宿主機硬盤上的某個目錄之上。
這就意味著容器在這臺主機上停止運行或者被刪除了再重建,只要關聯到硬盤上的這個目錄下,那么其數據還存在。但如果在另一臺主機上啟動一個新容器,那么數據就沒了。而如果在創建容器的時候我們手動的將容器的數據掛載到一臺nfs服務器上,那么這個問題就不再是問題了。
4. 為什么要用存儲卷
關閉并重啟容器,其數據不受影響,但刪除Docker容器,則其更改將會全部丟失。
因此Docker存在的問題有:
- 存儲于聯合掛載文件系統中,不易于宿主機訪問
- 容器間數據共享不便
- 刪除容器其數據會丟失
而要解決這些問題,解決方案就是使用存儲卷。
5. 存儲卷管理方式
存儲卷(Data Volume)于容器初始化時被自動創建,由base image提供的卷中的數據會于此期間完成復制。
Volume的初衷是獨立于容器的生命周期實現數據持久化,因此刪除容器之時既不會刪除卷,也不會對未被引用的卷做垃圾回收操作。
存儲卷為Docker提供了獨立于容器的數據管理機制,我們可以把鏡像想象成靜態文件,例如“程序”,把卷類比為動態內容,例如“數據”。所以鏡像可以重用,而卷則可以共享。
卷實現了“程序(鏡像)”和“數據(卷)”的分離,以及“程序(鏡像)”和“制作鏡像的主機”的分離,用戶制作鏡像時無須再考慮鏡像運行的容器所在的主機的環境。
6. 存儲卷的分類
Docker有兩種類型的卷,每種類型都在容器中存在一個掛載點,但其在宿主機上的位置有所不同:
- 綁定掛載卷
- 指向主機文件系統上用戶指定位置的卷
- Docker-managed volume
- Docker守護進程在主機文件系統的一部分中創建托管卷,這些卷歸Docker所有
- Docker守護進程在主機文件系統的一部分中創建托管卷,這些卷歸Docker所有
7. 容器數據管理
用戶在使用Docker的過程中,往往需要能查看容器內應用產生的數據,或者需要把容器內的數據進行備份,甚至多個容器之間進行數據的共享,這必然涉及容器的數據管理操作。
容器中管理數據主要有兩種方式:
- 數據卷(Data Volumes)
- 數據卷容器(Data Volumes Containers)
容器Volume使用語法:
Docker-managed volume
docker run -it --name CONTAINER_NAME -v VOLUMEDIR IMAGE_NAME[root@localhost ~]# docker run -it --rm busybox
/ # ls
bin dev etc home proc root sys tmp usr var
/ # exit
[root@localhost ~]# docker run -it --rm -v /data busybox
/ # ls
bin data dev etc home proc root sys tmp usr var
/ # [root@localhost ~]# docker ps
CONTAINER ID IMAGE COMMAND CREATED STATUS PORTS NAMES
8ba3c89bc11e busybox "sh" About a minute ago Up About a minute silly_jennings
[root@localhost ~]# docker inspect 8ba3c89bc11e
......省略N行"Type": "volume","Name": "0ba1343e6a02708b09335913d14e0707895c4ae8e8d3115df4e0efef2c232352","Source": "/var/lib/docker/volumes/0ba1343e6a02708b09335913d14e0707895c4ae8e8d3115df4e0efef2c2