您好,登錄后才能下訂單哦!
一、概述
docker鏡像采用分層分層構建設計,每層稱為"layer", layer存放在/data/docker/存儲驅動/目錄下面
這些存儲驅動有,AUFS,OverlayFS等,可以通過docker info命令查看存儲驅動,centos7.1+默認采用OverlayFS模式.
二、OverlayFS介紹
OverlayFS是一種堆疊文件系統,建立在其他文件系統之上,并不參與磁盤底層劃分,只是將底層文件系統目錄"合并",實際是偽合并,只是呈現給用戶好像一個文件系統結構,這也就是聯合掛載技術,對比于AUFS,OverlayFS速度更快,實現更簡單,因為OverlayFS只分兩層,只讀層,和讀寫層, Linux 內核為Docker提供的OverlayFS驅動有兩種:overlay和overlay2。而overlay2是相對于overlay的一種改進,在inode利用率方面比overlay更有效。但是overlay有環境需求:docker版本17.06.02+,宿主機文件系統需要是ext4或xfs格式.
聯合掛載技術:
overlayfs通過三個目錄:lower目錄、upper目錄、以及work(不太理解這個目錄怎么工作的)目錄實現,其中lower目錄可以是多個,work目錄為工作基礎目錄,掛載后內容會被清空,且在使用過程中其內容用戶不可見,最后聯合掛載完成給用戶呈現的統一視圖稱為為merged目錄。以下使用mount將演示其如何工作的
然后使用mount聯合掛載到/tmp/test 下:
mount -t overlay overlay -o lowerdir=A:B,upperdir=C,workdir=worker /tmp/test
掛載之后三個目錄會合并成一個,并且相同文件名的文件會進行“覆蓋”,這里覆蓋并不是真正的覆蓋,而是當合并時候目錄中兩個文件名稱都相同時,merged(/tmp/test)層目錄會顯示離它最近層的文件(lowerdir=A:B,A離他最近)
看看掛載情況:
docker官網overlay驅動模型:
在上述圖中可以看到三個層結構,即:lowerdir、uperdir、merged,其中lowerdir是只讀的image layer,其實就是rootfs,對比我們上述演示的目錄A和B,我們知道image layer可以分很多層,所以對應的lowerdir是可以有多個目錄。而upperdir則是在lowerdir之上的一層,這層是讀寫層,在啟動一個容器時候會進行創建,所有的對容器數據更改都發生在這里層,對比示例中的C。最后merged目錄是容器的掛載點,也就是給用戶暴露的統一視角,對比示例中的/tmp/test。而docker目錄層都保存在了/var/lib/docker/overlay2/或者/var/lib/docker/overlay/(如果使用overlay)
容器示例:
創建一個容器:
docker run -it centos /bin/bash
查看掛載情況:
容器修改數據時,overlay怎么工作?
讀:
1.如果文件在容器層(upperdir),直接讀取文件
2.如果文件不在容器層(upperdir),則從鏡像層(lowerdir)讀取
寫:
1.首次寫入: 如果在upperdir中不存在,overlay和overlay2執行copy_up操作,把文件從lowdir拷貝到upperdir,由于overlayfs是文件級別的(即使文件只有很少的一點修改,也會產生的copy_up的行為),后續對同一文件的在此寫入操作將對已經復制到容器的文件的副本進行操作。這也就是常常說的寫時復制(copy-on-write)
2.刪除文件和目錄: 當文件在容器被刪除時,在容器層(upperdir)創建whiteout文件,鏡像層(lowerdir)的文件是不會被刪除的,因為他們是只讀的,但without文件會阻止他們顯示,當目錄在容器內被刪除時,在容器層(upperdir)一個不透明的目錄,這個和上面whiteout原理一樣,阻止用戶繼續訪問,即便鏡像層仍然存在
注意:
1.copy_up操作只發生在文件首次寫入,以后都是只修改副本
2.容器層的文件刪除只是偽刪除,是靠whiteout文件將其遮擋,image層并沒有刪除,這也就是為什么使用docker commit 提交保存的鏡像會越來越大,無論在容器層怎么刪除數據,image層都不會改變
過程演示:
發現修改操作只在C目錄發生也就是upperdir層發生
三、overlay2 鏡像存儲結構
docker pull ubuntu
四層layer存儲位置:
這里面多了一個l目錄包含了所有層的軟連接,短鏈接使用短名稱,避免mount時候參數達到頁面大小限制(演示中mount命令查看時候的短目錄)
處于底層的鏡像目錄包含了一個diff和一個link文件,diff目錄存放了當前層的鏡像內容,而link文件則是與之對應的短名稱
在這之上的鏡像還多了work目錄和lower文件,lower文件用于記錄父層的短名稱,work目錄用于聯合掛載指定的工作目錄。
而這些目錄和鏡像的關系是通過元數據關聯。元數據分為image元數據和layer元數據:
image鏡像原數據:
鏡像元數據存儲在了/var/lib/docker/image/<storage_driver>/imagedb/content/sha256/目錄下,名稱是以鏡像ID命名的文件,鏡像ID可通過docker images查看,這些文件以json的形式保存了該鏡像的rootfs信息、鏡像創建時間、構建歷史信息、所用容器、包括啟動的Entrypoint和CMD等等:
ubuntu鏡像id
進入鏡像元數據目錄
cd /data/docker/image/overlay2/imagedb/content/sha256/
vim 775349758637aff77bf85e2ff0597e86e3e859183ef0baba8b3e8fc8d3cba51c
上面的 diff_id 對應的的是一個鏡像層,其排列也是有順序的,從上到下依次表示鏡像層的最低層到最頂層
docker 利用 rootfs 中的每個diff_id 和歷史信息計算出與之對應的內容尋址的索引(chainID) ,而chaiID則關聯了layer層,進而關聯到每一個鏡像層的鏡像文件
layer元數據:
鏡像層只包含一個具體的鏡像層文件包。用戶在 docker 宿主機上下載了某個鏡像層之后,docker 會在宿主機上基于鏡像層文件包和 image 元數據構建本地的 layer 元數據,包括 diff、parent、size 等。而當 docker 將在宿主機上產生的新的鏡像層上傳到 registry 時,與新鏡像層相關的宿主機上的元數據也不會與鏡像層一塊打包上傳。
Docker 中定義了 Layer 和 RWLayer 兩種接口,分別用來定義只讀層和可讀寫層的一些操作,又定義了 roLayer 和 mountedLayer,分別實現了上述兩種接口。其中,roLayer 用于描述不可改變的鏡像層,mountedLayer 用于描述可讀寫的容器層。具體來說,roLayer 存儲的內容主要有索引該鏡像層的 chainID、該鏡像層的校驗碼 diffID、父鏡像層 parent、storage_driver 存儲當前鏡像層文件的 cacheID、該鏡像層的 size 等內容。這些元數據被保存在
每個chainID目錄下會存在三個文件cache-id、diff、size
cache-id文件:
docker隨機生成的uuid,內容是保存鏡像層的目錄索引,也就是/var/lib/docker/overlay2/中的目錄,這就是為什么通過chainID能找到對應的layer目錄。以chainID為565879c6effe6a013e0b2e492f182b40049f1c083fc582ef61e49a98dca23f7e 對應的目錄為 0b7bbc608eca835ac9bdb31a1794016a8fd1dacc8f58fbcf2763db1dc40d3f32,也就保存在/data/docker/overlay2/0b7bbc608eca835ac9bdb31a1794016a8fd1dacc8f58fbcf2763db1dc40d3f32
diff文件:
保存了鏡像元數據中的diff_id(與元數據中的diff_ids中的uuid對應
size文件:
保存了鏡像層的大小
在 layer 的所有屬性中,diffID 采用 SHA256 算法,基于鏡像層文件包的內容計算得到。而 chainID 是基于內容存儲的索引,它是根據當前層與所有祖先鏡像層 diffID 計算出來的,具體算如下:
1.如果該鏡像層是最底層(沒有父鏡像層),該層的 diffID 便是 chainID
2.該鏡像層的 chainID 計算公式為 chainID(n)=SHA256(chain(n-1) diffID(n)),也就是根據父鏡像層的 chainID 加上一個空格和當前層的 diffID,再計算 SHA256 校驗碼
mountedLayer 信息存儲的可讀init層以及容器掛載點信息包括:容器 init 層ID(init-id)、聯合掛載使用的ID(mount-id)以及容器層的父層鏡像的 chainID(parent)。相關文件位于/var/lib/docker/image/<storage_driver>/layerdb/mounts/<container_id>/ 目錄下
可以看到initID是在mountID后加了一個-init,同時initID就是存儲在/var/lib/docker/overlay2/的目錄名稱:
查看mountID還可以直接通過mount命令查看對應掛載的mountID,對應著/data/docker/overlay2/目錄,這也是overlayfs呈現的merged目錄
在容器中創建一個文件,在merged目錄將能看到:
關于init層:
init層是以一個uuid+-init結尾表示,夾在只讀層和讀寫層之間,作用是專門存放/etc/hosts、/etc/resolv.conf等信息,需要這一層的原因是當容器啟動時候,這些本該屬于image層的文件或目錄,比如hostname,用戶需要修改,但是image層又不允許修改,所以啟動時候通過單獨掛載一層init層,通過修改init層中的文件達到修改這些文件目的。而這些修改往往只讀當前容器生效,而在docker commit提交為鏡像時候,并不會將init層提交。該層文件存放的目錄為/data/docker/overlay2/<init_id>/diff
免責聲明:本站發布的內容(圖片、視頻和文字)以原創、轉載和分享為主,文章觀點不代表本網站立場,如果涉及侵權請聯系站長郵箱:is@yisu.com進行舉報,并提供相關證據,一經查實,將立刻刪除涉嫌侵權內容。