Docker鏡像由一些鬆耦合的只讀鏡像層組成,故要求鏡像存儲必須支持分層存儲的特性。在Linux上支持每種鏡像存儲驅動都有本身的鏡像分層、鏡像層共享以及寫時複製(CoW)技術的具體實現。本文只討論Docker本地存儲技術,不討論存儲卷。node
全部的Docker鏡像都起始於一個基礎鏡像層,當進行修改或增長新的內容時,就會在當前鏡像層之上,建立新的鏡像層。默認Docker鏡像由多個只讀層鏡像疊加而成,啓動容器後,Docker會加載只讀鏡像層,並再頂部添加一個讀寫層,並經過寫時複製的方式,來寫讀寫層linux
多個鏡像之間能夠而且確實會共享鏡像層,這樣能夠有效節省空間 並提高性能。例如多個centos7的鏡像能夠共享centos7的基礎image,由於基礎image你們都同樣docker
CoW就是copy-on-write,表示只在須要寫時纔去複製,這個是針對已有文件的修改場景。好比基於一個image啓動多個Container,若是爲每一個Container都去分配一個image同樣的文件系統,那麼將會佔用大量的磁盤空間。而CoW技術可讓全部的容器共享image的文件系統,全部數據都從image中讀取,只有當要對文件進行寫操做時,才從image裏把要寫的文件複製到本身的文件系統進行修改。因此不管有多少個容器共享同一個image,所作的寫操做都是對從image中複製到本身的文件系統中的複本上進行,並不會修改image的源文件,且多個容器操做同一個文件,會在每一個容器的文件系統裏生成一個複本,每一個容器修改的都是本身的複本,相互隔離,相互不影響。使用CoW能夠有效的提升磁盤的利用率。ubuntu
每一個Docker容器都有本身的非持久化存儲,即容器的本地存儲,默認狀況這是容器所有文件和文件系統保存的地方,故本地存儲要知足鏡像存儲的技術特性。本地存儲自動建立,從屬於容器,生命週期與容器相同,這意味着刪除容器也會刪除所有非持久化數據。centos
在linux2.6內核版本中併入內核,devicemapper將全部的鏡像和容器存儲在本身的虛擬塊設備上,devicemapper工做在塊層次上而不是文件層次上。在Docker 17.06以及更高的版本中能夠配置direct-lvm 做爲存儲驅動,這種模式下經過使用基於裸塊設備 (Raw Block Device)的LVM精簡池(LVM thin pool)來獲取更好的性能。app
如上圖所示,Overlay在主機上用到2個目錄,這2個目錄被當作是overlay的層。upperdir爲容器層、lowerdir爲鏡像層使用聯合掛載技術將它們掛載在同一目錄(merged)下,提供統一視圖。ide
overlay只使用2層,意味着多層鏡像不會被實現爲多個OverlayFS層。每一個鏡像被實現爲本身的目錄,這個目錄在路徑/var/lib/docker/overlay下。硬連接被用來索引和低層共享的數據,節省了空間,可是會有inode佔用過多的問題。性能
當建立一個容器時,overlay驅動鏈接表明鏡像層頂層的目錄(只讀)和一個表明容器層的新目錄(讀寫)。ui
docker的overlay2驅動須要在kernel 3.10.0-514以上和Docker 17.06以上版本支持。而centos/redhat7系統默認內核爲3.10.*。overlay2能夠直接形成muitiple lower layers(最大128層)不用像overlay同樣要經過硬連接的方式共享數據。
在overlay2每層的內容都是不同的,diff是文件系統的統一掛載點,link文件描述的是該層的標識符,lower文件描述了層與層之間的組織關係,overlay2是將底層多個lowerdir和upperdir和workdir聯合掛載,造成最終的merged掛載點。centos7
以下爲ubuntu:18.04的鏡像
/var/lib/docker/overlay2/ |-- 6e599f35a3366d95287390fc00183a80bfc9a34492aaf9694836ec7b5722d0b6 | |-- diff | |-- link | |-- lower | |-- merged | `-- work |-- 6f66846fe6a29834193bf36380eb1664947f21435edd8ce8fbc9b79dea92c51b | |-- diff | |-- link | |-- lower | |-- merged | `-- work |-- a1869d02b056d66742372c4b6d31d64f98b477590cdd76a842a653424f46710b | |-- diff | |-- link | |-- lower | |-- merged | `-- work |-- backingFsBlockDev |-- da05539957d703ae81cf279c76059c947c96bd1f91fd24691b9e7630dcb13ff7 | |-- diff | `-- link `-- l |-- 2LYVTSJQWPVOB46BCA74GFHJ7T -> ../da05539957d703ae81cf279c76059c947c96bd1f91fd24691b9e7630dcb13ff7/diff |-- HEXAQW5O23XL6HHRVOMKWGAI4Z -> ../6f66846fe6a29834193bf36380eb1664947f21435edd8ce8fbc9b79dea92c51b/diff |-- KXIOHK4OI6PPPFZ56I3ZORNHS7 -> ../6e599f35a3366d95287390fc00183a80bfc9a34492aaf9694836ec7b5722d0b6/diff `-- PHQQ6RCEXR6BLZJGKBP6GYS55Q -> ../a1869d02b056d66742372c4b6d31d64f98b477590cdd76a842a653424f46710b/diff
一、overlay只支持兩層lowerdir和upperdir,而且只支持一個lowerdir,因此若是你的容器鏡像有多層的話,層與層以前的數據共享是經過硬連接來實現的,咱們也知道硬連接自己是同一個inode但不一樣的文件名而已,但爲何仍是會大量消耗inode這裏簡單作的實驗
咱們在一臺配置了storage-driver的機器上PULL ubuntu:18.04鏡像
[root@master dir]# docker pull ubuntu:18.04 18.04: Pulling from library/ubuntu 32802c0cfa4d: Pull complete da1315cffa03: Pull complete fa83472a3562: Pull complete f85999a86bef: Pull complete Digest: sha256:48eb09a5c832172357f172593ce5e98e027814f758f6aeaef59a7fd658e50d49 Status: Downloaded newer image for ubuntu:18.04
整個鏡像是一個四層鏡像層組成的鏡像,在/var/lib/docker/overlay/下每層對應一個目錄,經過tree命令能夠看見每一個目錄內只包含一個root文件夾
tree -L 2 /var/lib/docker/overlay/ /var/lib/docker/overlay/ |-- 0a9cd41c44a802a325bfc5bfdda757bced8eaf69a8d6004e5d6fcb730591ab31 | `-- root |-- 1f9c95c6642a98930a14d914ac9bcfe9535b5a604dc27851cd76266326c76ed7 | `-- root |-- 2d79f688e1bf505ef20100f7450ad7e5ea550500bd07a17b7b9b08513fc96988 | `-- root `-- e8b1fcddec600628a75964619da3d0de7310fcbd6350b0c07ddf038d71c25d8b `-- root 8 directories, 0 files
這個root目錄內包含的是該層獨有的文件和根lowdir共享的數據硬連接,這裏看見共享的數據他們自己都是經過硬連接方式鏈接起來的。
[root@master overlay]# ls -i /var/lib/docker/overlay/0a9cd41c44a802a325bfc5bfdda757bced8eaf69a8d6004e5d6fcb730591ab31/root/bin/ls 70832997 /var/lib/docker/overlay/0a9cd41c44a802a325bfc5bfdda757bced8eaf69a8d6004e5d6fcb730591ab31/root/bin/ls [root@master overlay]# ls -i /var/lib/docker/overlay/1f9c95c6642a98930a14d914ac9bcfe9535b5a604dc27851cd76266326c76ed7/root/bin/ls 70832997 /var/lib/docker/overlay/1f9c95c6642a98930a14d914ac9bcfe9535b5a604dc27851cd76266326c76ed7/root/bin/ls [root@master overlay]# ls -i /var/lib/docker/overlay/2d79f688e1bf505ef20100f7450ad7e5ea550500bd07a17b7b9b08513fc96988/root/bin/ls 70832997 /var/lib/docker/overlay/2d79f688e1bf505ef20100f7450ad7e5ea550500bd07a17b7b9b08513fc96988/root/bin/ls [root@master overlay]# ls -i /var/lib/docker/overlay/e8b1fcddec600628a75964619da3d0de7310fcbd6350b0c07ddf038d71c25d8b/root/bin/ls 70832997 /var/lib/docker/overlay/e8b1fcddec600628a75964619da3d0de7310fcbd6350b0c07ddf038d71c25d8b/root/bin/ls
但爲何overlay仍是會佔用大量inode呢?根本緣由在於那些文件夾,每層的root目錄內存放的都是完整的rootfs文件夾,但它們都是新建出來
的,它們inode都不同,因此在overlay下一個容器鏡像層數越多,佔用的inode就越多
四,參考資料
https://docs.docker.com/storage/storagedriver/overlayfs-driver/
https://docs.docker.com/storage/storagedriver/select-storage-driver/#supported-backing-filesystems
https://www.bladewan.com/2018/01/25/docker_storage_driver/