服務(wù)器
一、概述
docker中的鏡像采用分層構建設計,每個(gè)層可以稱(chēng)之為“l(fā)ayer”,這些layer被存放在了/var/lib/docker/<storage-driver>/目錄下,這里的storage-driver可以有很多種如:AUFS、OverlayFS、VFS、Brtfs等??梢酝ㄟ^(guò)docker info命令查看存儲驅動(dòng),(筆者系統是centos7.4):
通常ubuntu類(lèi)的系統默認采用的是AUFS,centos7.1 系列采用的是OverlayFS。而本文將介紹以OverlayFS作為存儲驅動(dòng)的鏡像存儲原理以及存儲結構。
二、OverlayFS 介紹
OverlayFS是一種堆疊文件系統,它依賴(lài)并建立在其它的文件系統之上(例如ext4fs和xfs等等),并不直接參與磁盤(pán)空間結構的劃分,僅僅將原來(lái)底層文件系統中不同的目錄進(jìn)行“合并”,然后向用戶(hù)呈現,這也就是聯(lián)合掛載技術(shù),對比于A(yíng)UFS,OverlayFS速度更快,實(shí)現更簡(jiǎn)單。 而Linux 內核為Docker提供的OverlayFS驅動(dòng)有兩種:overlay和overlay2。而overlay2是相對于overlay的一種改進(jìn),在inode利用率方面比overlay更有效。但是overlay有環(huán)境需求:docker版本17.06.02 ,宿主機文件系統需要是ext4或xfs格式。
聯(lián)合掛載
overlayfs通過(guò)三個(gè)目錄:lower目錄、upper目錄、以及work目錄實(shí)現,其中lower目錄可以是多個(gè),work目錄為工作基礎目錄,掛載后內容會(huì )被清空,且在使用過(guò)程中其內容用戶(hù)不可見(jiàn),最后聯(lián)合掛載完成給用戶(hù)呈現的統一視圖稱(chēng)為為merged目錄。以下使用mount將演示其如何工作的。
使用mount命令掛載overlayfs語(yǔ)法如下:
mount -t overlay overlay -o lowerdir=lower1:lower2:lower3,upperdir=upper,workdir=work merged_dir
創(chuàng )建三個(gè)目錄A、B、C,以及worker目錄:
然后使用mount聯(lián)合掛載到/tmp/test 下:
然后我們再去查看/tmp/test目錄,你會(huì )發(fā)現目錄A、B、C被合并到了一起,并且相同文件名的文件會(huì )進(jìn)行“覆蓋”,這里覆蓋并不是真正的覆蓋,而是當合并時(shí)候目錄中兩個(gè)文件名稱(chēng)都相同時(shí),merged層目錄會(huì )顯示離它最近層的文件:
同時(shí)我們還可以通過(guò)mount命令查看其掛載的選項:
以上這樣的方式也就是聯(lián)合掛載技術(shù)。
Docker中的overlay驅動(dòng)
介紹了overlay驅動(dòng)原理以后再來(lái)看Docker中的overlay存儲驅動(dòng),以下是來(lái)自docker官網(wǎng)關(guān)于overlay的工作原理圖:
在上述圖中可以看到三個(gè)層結構,即:lowerdir、uperdir、merged,其中lowerdir是只讀的image layer,其實(shí)就是rootfs,對比我們上述演示的目錄A和B,我們知道image layer可以分很多層,所以對應的lowerdir是可以有多個(gè)目錄。而upperdir則是在lowerdir之上的一層,這層是讀寫(xiě)層,在啟動(dòng)一個(gè)容器時(shí)候會(huì )進(jìn)行創(chuàng )建,所有的對容器數據更改都發(fā)生在這里層,對比示例中的C。最后merged目錄是容器的掛載點(diǎn),也就是給用戶(hù)暴露的統一視角,對比示例中的/tmp/test。而這些目錄層都保存在了/var/lib/docker/overlay2/或者/var/lib/docker/overlay/(如果使用overlay)。
演示
啟動(dòng)一個(gè)容器
查看其overlay掛載點(diǎn),可以發(fā)現其掛載的merged目錄、lowerdir、upperdir以及workdir:
overlay2的lowerdir可以有多個(gè),并且是軟連接方式掛載,后續我們會(huì )進(jìn)行說(shuō)明。
如何工作
當容器中發(fā)生數據修改時(shí)候overlayfs存儲驅動(dòng)又是如何進(jìn)行工作的?以下將闡述其讀寫(xiě)過(guò)程:
讀:
如果文件在容器層(upperdir),直接讀取文件;
如果文件不在容器層(upperdir),則從鏡像層(lowerdir)讀??;
修改:
首次寫(xiě)入: 如果在upperdir中不存在,overlay和overlay2執行copy_up操作,把文件從lowdir拷貝到upperdir,由于overlayfs是文件級別的(即使文件只有很少的一點(diǎn)修改,也會(huì )產(chǎn)生的copy_up的行為),后續對同一文件的在此寫(xiě)入操作將對已經(jīng)復制到容器的文件的副本進(jìn)行操作。這也就是常常說(shuō)的寫(xiě)時(shí)復制(copy-on-write)
刪除文件和目錄: 當文件在容器被刪除時(shí),在容器層(upperdir)創(chuàng )建whiteout文件,鏡像層(lowerdir)的文件是不會(huì )被刪除的,因為他們是只讀的,但without文件會(huì )阻止他們顯示,當目錄在容器內被刪除時(shí),在容器層(upperdir)一個(gè)不透明的目錄,這個(gè)和上面whiteout原理一樣,阻止用戶(hù)繼續訪(fǎng)問(wèn),即便鏡像層仍然存在。
注意事項
copy_up操作只發(fā)生在文件首次寫(xiě)入,以后都是只修改副本,
overlayfs只適用兩層目錄,,相比于比AUFS,查找搜索都更快。
容器層的文件刪除只是一個(gè)“障眼法”,是靠whiteout文件將其遮擋,image層并沒(méi)有刪除,這也就是為什么使用docker commit 提交保存的鏡像會(huì )越來(lái)越大,無(wú)論在容器層怎么刪除數據,image層都不會(huì )改變。
三、overlay2鏡像存儲結構
從倉庫pull一個(gè)ubuntu鏡像,結果顯示總共拉取了4層鏡像如下:
此時(shí)4層被存儲在了/var/lib/docker/overlay2/目錄下:
這里面多了一個(gè)l目錄包含了所有層的軟連接,短鏈接使用短名稱(chēng),避免mount時(shí)候參數達到頁(yè)面大小限制(演示中mount命令查看時(shí)候的短目錄):
處于底層的鏡像目錄包含了一個(gè)diff和一個(gè)link文件,diff目錄存放了當前層的鏡像內容,而link文件則是與之對應的短名稱(chēng):
在這之上的鏡像還多了work目錄和lower文件,lower文件用于記錄父層的短名稱(chēng),work目錄用于聯(lián)合掛載指定的工作目錄。而這些目錄和鏡像的關(guān)系是怎么組織在的一起呢?答案是通過(guò)元數據關(guān)聯(lián)。元數據分為image元數據和layer元數據。
image元數據
鏡像元數據存儲在了/var/lib/docker/image/<storage_driver>/imagedb/content/sha256/目錄下,名稱(chēng)是以鏡像ID命名的文件,鏡像ID可通過(guò)docker images查看,這些文件以json的形式保存了該鏡像的rootfs信息、鏡像創(chuàng )建時(shí)間、構建歷史信息、所用容器、包括啟動(dòng)的Entrypoint和CMD等等。例如ubuntu鏡像的id為47b19964fb50:
查看其對應的元數據(使用vim :%!python -m json.tool格式化成json) 截取了其rootfs的構成:
上面的 diff_id 對應的的是一個(gè)鏡像層,其排列也是有順序的,從上到下依次表示鏡像層的最低層到最頂層:
diff_id如何關(guān)聯(lián)進(jìn)行層?具體說(shuō)來(lái),docker 利用 rootfs 中的每個(gè)diff_id 和歷史信息計算出與之對應的內容尋址的索引(chainID) ,而chaiID則關(guān)聯(lián)了layer層,進(jìn)而關(guān)聯(lián)到每一個(gè)鏡像層的鏡像文件。
layer元數據
layer 對應鏡像層的概念,在 docker 1.10 版本以前,鏡像通過(guò)一個(gè) graph 結構管理,每一個(gè)鏡像層都擁有元數據,記錄了該層的構建信息以及父鏡像層 ID,而最上面的鏡像層會(huì )多記錄一些信息作為整個(gè)鏡像的元數據。graph 則根據鏡像 ID(即最上層的鏡像層 ID) 和每個(gè)鏡像層記錄的父鏡像層 ID 維護了一個(gè)樹(shù)狀的鏡像層結構?! ?/p>
在 docker 1.10 版本后,鏡像元數據管理巨大的改變之一就是簡(jiǎn)化了鏡像層的元數據,鏡像層只包含一個(gè)具體的鏡像層文件包。用戶(hù)在 docker 宿主機上下載了某個(gè)鏡像層之后,docker 會(huì )在宿主機上基于鏡像層文件包和 image 元數據構建本地的 layer 元數據,包括 diff、parent、size 等。而當 docker 將在宿主機上產(chǎn)生的新的鏡像層上傳到 registry 時(shí),與新鏡像層相關(guān)的宿主機上的元數據也不會(huì )與鏡像層一塊打包上傳?! ?/p>
Docker 中定義了 Layer 和 RWLayer 兩種接口,分別用來(lái)定義只讀層和可讀寫(xiě)層的一些操作,又定義了 roLayer 和 mountedLayer,分別實(shí)現了上述兩種接口。其中,roLayer 用于描述不可改變的鏡像層,mountedLayer 用于描述可讀寫(xiě)的容器層。具體來(lái)說(shuō),roLayer 存儲的內容主要有索引該鏡像層的 chainID、該鏡像層的校驗碼 diffID、父鏡像層 parent、storage_driver 存儲當前鏡像層文件的 cacheID、該鏡像層的 size 等內容。這些元數據被保存在 /var/lib/docker/image/<storage_driver>/layerdb/sha256/<chainID>/ 文件夾下。如下:
每個(gè)chainID目錄下會(huì )存在三個(gè)文件cache-id、diff、zize:
cache-id文件:
docker隨機生成的uuid,內容是保存鏡像層的目錄索引,也就是/var/lib/docker/overlay2/中的目錄,這就是為什么通過(guò)chainID能找到對應的layer目錄。以chainID為d801a12f6af7beff367268f99607376584d8b2da656dcd8656973b7ad9779ab4 對應的目錄為 130ea10d6f0ebfafc8ca260992c8d0bef63a1b5ca3a7d51a5cd1b1031d23efd5,也就保存在/var/lib/docker/overlay2/130ea10d6f0ebfafc8ca260992c8d0bef63a1b5ca3a7d51a5cd1b1031d23efd5
diff文件:
保存了鏡像元數據中的diff_id(與元數據中的diff_ids中的uuid對應)
size文件:
保存了鏡像層的大小
在 layer 的所有屬性中,diffID 采用 SHA256 算法,基于鏡像層文件包的內容計算得到。而 chainID 是基于內容存儲的索引,它是根據當前層與所有祖先鏡像層 diffID 計算出來(lái)的,具體算如下:
如果該鏡像層是最底層(沒(méi)有父鏡像層),該層的 diffID 便是 chainID。
該鏡像層的 chainID 計算公式為 chainID(n)=SHA256(chain(n-1) diffID(n)),也就是根據父鏡像層的 chainID 加上一個(gè)空格和當前層的 diffID,再計算 SHA256 校驗碼。
mountedLayer 信息存儲的可讀init層以及容器掛載點(diǎn)信息包括:容器 init 層ID(init-id)、聯(lián)合掛載使用的ID(mount-id)以及容器層的父層鏡像的 chainID(parent)。相關(guān)文件位于/var/lib/docker/image/<storage_driver>/layerdb/mounts/<container_id>/ 目錄下。如下啟動(dòng)一個(gè)id為3c96960b3127的容器:
查看其對應的mountedLayer三個(gè)文件:
可以看到initID是在mountID后加了一個(gè)-init,同時(shí)initID就是存儲在/var/lib/docker/overlay2/的目錄名稱(chēng):
查看mountID還可以直接通過(guò)mount命令查看對應掛載的mountID,對應著(zhù)/var/lib/docker/overlay2/目錄,這也是overlayfs呈現的merged目錄:
在容器中創(chuàng )建了一文件:
此時(shí)到宿主的merged目錄就能看到對應的文件:
關(guān)于init層
init層是以一個(gè)uuid -init結尾表示,夾在只讀層和讀寫(xiě)層之間,作用是專(zhuān)門(mén)存放/etc/hosts、/etc/resolv.conf等信息,需要這一層的原因是當容器啟動(dòng)時(shí)候,這些本該屬于image層的文件或目錄,比如hostname,用戶(hù)需要修改,但是image層又不允許修改,所以啟動(dòng)時(shí)候通過(guò)單獨掛載一層init層,通過(guò)修改init層中的文件達到修改這些文件目的。而這些修改往往只讀當前容器生效,而在docker commit提交為鏡像時(shí)候,并不會(huì )將init層提交。該層文件存放的目錄為/var/lib/docker/overlay2/<init_id>/diff
小結
通過(guò)以上的內容介紹,一個(gè)容器完整的層應由三個(gè)部分組成,如下圖:
鏡像層:也稱(chēng)為rootfs,提供容器啟動(dòng)的文件系統
init層: 用于修改容器中一些文件如/etc/hostname、/etc/resolv.conf等
容器層:使用聯(lián)合掛載統一給用戶(hù)提供的可讀寫(xiě)目錄。
四、總結
本文介紹了以overlayfs作為存儲驅動(dòng)的的鏡像存儲原理其中每層的鏡像數據保存在/var/lib/docker/overlay2/<uuid>/diff目錄下,init層數據保存了在 /var/lib/docker/overlay2/<init-id>/diff目錄下,最后統一視圖(容器層)數據在 /var/lib/docker/overlay2/<mount_id>/diff目錄下,docker通過(guò)image元數據和layer元數據利用內容尋址(chainID)將這些目錄組織起來(lái)構成容器所運行的文件系統。
參考:
《use overlayfs driver 》
《Docker 鏡像之存儲管理》
到此這篇關(guān)于Docker鏡像存儲overlayfs的使用的文章就介紹到這了,更多相關(guān)Docker鏡像存儲overlayfs內容請搜素特網(wǎng)科技以前的文章或下面相關(guān)文章,希望大家以后多多支持特網(wǎng)科技!
更多關(guān)于云服務(wù)器,域名注冊,虛擬主機的問(wèn)題,請訪(fǎng)問(wèn)特網(wǎng)科技官網(wǎng):wap.friendlycc.com.cn
免責聲明:本站發(fā)布的內容(圖片、視頻和文字)以原創(chuàng )、來(lái)自本網(wǎng)站內容采集于網(wǎng)絡(luò )互聯(lián)網(wǎng)轉載等其它媒體和分享為主,內容觀(guān)點(diǎn)不代表本網(wǎng)站立場(chǎng),如侵犯了原作者的版權,請告知一經(jīng)查實(shí),將立刻刪除涉嫌侵權內容,聯(lián)系我們QQ:712375056,同時(shí)歡迎投稿傳遞力量。
Copyright ? 2009-2022 56dr.com. All Rights Reserved. 特網(wǎng)科技 特網(wǎng)云 版權所有 特網(wǎng)科技 粵ICP備16109289號
域名注冊服務(wù)機構:阿里云計算有限公司(萬(wàn)網(wǎng)) 域名服務(wù)機構:煙臺帝思普網(wǎng)絡(luò )科技有限公司(DNSPod) CDN服務(wù):阿里云計算有限公司 百度云 中國互聯(lián)網(wǎng)舉報中心 增值電信業(yè)務(wù)經(jīng)營(yíng)許可證B2
建議您使用Chrome、Firefox、Edge、IE10及以上版本和360等主流瀏覽器瀏覽本網(wǎng)站