溫馨提示×

溫馨提示×

您好,登錄后才能下訂單哦!

密碼登錄×
登錄注冊×
其他方式登錄
點擊 登錄注冊 即表示同意《億速云用戶服務(wù)條款》

Docker鏡像分層怎么實現(xiàn)

發(fā)布時間:2022-09-23 13:58:31 來源:億速云 閱讀:190 作者:iii 欄目:開發(fā)技術(shù)

今天小編給大家分享一下Docker鏡像分層怎么實現(xiàn)的相關(guān)知識點,內(nèi)容詳細(xì),邏輯清晰,相信大部分人都還太了解這方面的知識,所以分享這篇文章給大家參考一下,希望大家閱讀完這篇文章后有所收獲,下面我們一起來了解一下吧。

    創(chuàng)建測試鏡像

    我們創(chuàng)建一個最簡單的鏡像:

    1.構(gòu)建測試鏡像v1.0:docker build -t image_test:1.0 .

    FROM alpine:3.15.0 #除了繼承基礎(chǔ)鏡像,啥也不做

    2.構(gòu)建測試鏡像v2.0:docker build -t image_test:2.0 .

    FROM alpine:3.15.0
    RUN dd if=/dev/zero of=file1 bs=10M count=1 #添加一個10M的文件file1

    3.構(gòu)建測試鏡像v3.0:docker build -t image_test:3.0 .

    FROM alpine:3.15.0
    RUN dd if=/dev/zero of=file1 bs=10M count=1 #添加一個10M的文件file1
    RUN dd if=/dev/zero of=file2 bs=10M count=1 #添加一個10M的文件file2

    這樣本地就構(gòu)建了3個測試鏡像:

    Docker鏡像分層怎么實現(xiàn)

    查看鏡像

    我們有2種方法查看鏡像:

    使用docker inspect:獲取鏡像的元數(shù)據(jù)使用docker history:查看鏡像的構(gòu)建歷史 使用docker inspect

    使用docker inspect

    查看鏡像的元數(shù)據(jù)。
    其中Parent可以看到父鏡像, Layers這一項下面可以看到鏡像的所有層。

    使用docker history

    使用docker history可以看到鏡像的構(gòu)建歷史。
    我們每一行列出了鏡像包含的層。

    Docker鏡像分層怎么實現(xiàn)

    鏡像分層圖

    根據(jù)上面的docker history命令,我們可以輕松的畫出三個鏡像的分層圖:

    Docker鏡像分層怎么實現(xiàn)

    從上面的圖可以看到,我們的鏡像是分層的,我們的Dockerfile中新增一條指令,就會新增一層!
    如果我們將多個命令合成一個,那么也只會生成一層。修改一下上面的image_test:3.0,把兩條RUN合并成一條:

    FROM alpine:3.15.0
    RUN dd if=/dev/zero of=file1 bs=10M count=1 && \
        dd if=/dev/zero of=file2 bs=10M count=1

    使用docker history 查看image_test:4.0,可以看到,只有2層了!

    Docker鏡像分層怎么實現(xiàn)

    鏡像分層的好處

    知道了鏡像是分層的,那么我們是不是好奇為啥要這么設(shè)計呢?
    試想一下我們?nèi)绻环謱訒惺裁磫栴}?

    以拉取鏡像為例!
    拉取鏡像的鏡像很大,比如Redis的鏡像有100多M
    第一次我們拉取6.2版本的Redis,下載了完成的100M到本地,下次我要下載6.2.6版本的,是不是又得下載100M。
    盡管可能兩個版本之間就改了幾行配置文件。

    這樣是非常低效的。如果能只下載有差異的部分就好了!

    這個痛點,也就是鏡像分層要解決的問題。實際上,Docker也是這么實現(xiàn)的。
    第一次下載redis:6.2時,因為之前沒有下載過,所以下載了所有的層,總共113M。網(wǎng)絡(luò)慢點的話還是需要花一些時間的!

    Docker鏡像分層怎么實現(xiàn)

    第二次下載redis:7.0-rc,就變得快了很多!因為前面3層是redis:6.2是一樣的,這些層已經(jīng)下載過了!

    Docker鏡像分層怎么實現(xiàn)

    如果版本2是基于版本1的基礎(chǔ)上,那么版本2不需要copy一份全量的數(shù)據(jù),只需一份和版本1差異化的增量數(shù)據(jù)即可!

    這樣的最終好處是,可以體現(xiàn)在以下方面:

    • 拉取更快:因為分層了,只需拉取本地不存在的層即可!

    • 存儲更少:因為共同的層只需存儲一份即可!

    • 運(yùn)行時存儲更少:容器運(yùn)行時可以共享相同的層!

    對于第3點,多個基于相同鏡像運(yùn)行的容器,都可以直接使用相同的鏡像層,每個容器只需一個自己的可寫層即可:

    Docker鏡像分層怎么實現(xiàn)

    Docker鏡像加載原理

    下面這張圖想必各位是不陌生了,再往下還有一張。那我們要如何在這么多不陌生的人里面脫穎而出呢?就看誰能把這兩張圖說出花來了哈。

    Docker鏡像分層怎么實現(xiàn)

    bootfs(boot file system) 主要包含 bootloader 和 kernel, bootloader 主要是引導(dǎo)加載 kernel,Linux 剛啟動時會加載 bootfs 文件系統(tǒng),在Docker 鏡像的最底層是引導(dǎo)文件系統(tǒng) bootfs。這一層與我們典型的 Linux/Unix 系統(tǒng)是一樣的,包含 boot 加載器和內(nèi)核。當(dāng) boot 加載完成之后整個內(nèi)核就都在內(nèi)存中了,此時內(nèi)存的使用權(quán)已由 bootfs 轉(zhuǎn)交給內(nèi)核,此時系統(tǒng)也會卸載 bootfs。

    rootfs (root file system) ,在 bootfs 之上。包含的就是典型 Linux 系統(tǒng)中的 /dev, /proc, /bin, /etc 等標(biāo)準(zhǔn)目錄和文件。rootfs 就是各種不同的操作系統(tǒng)發(fā)行版,比如 Ubuntu,Centos 等等。

    對于一個精簡的 OS,rootfs 可以很小,只需要包括最基本的命令、工具和程序庫就可以了,因為底層直接用 Host 的 kernel,自己只需要提供 rootfs 就行了。由此可見對于不同的 linux 發(fā)行版, bootfs 基本是一致的, rootfs 會有差別, 因此不同的發(fā)行版可以公用 bootfs。

    Docker鏡像分層怎么實現(xiàn)

    Docker鏡像層都是只讀的,容器層是可寫的。 當(dāng)容器啟動時,一個新的可寫層被加載到鏡像的頂部。 這一層通常被稱作“容器層”,“容器層”之下的都叫“鏡像層”。所有對容器的改動,無論添加、刪除、還是修改文件都只會發(fā)生在容器層中。

    那么,先讓我們來重新認(rèn)識一下與 Docker 鏡像相關(guān)的 4 個概念:rootfs、Union mount、image 以及 layer。

    rootfs

    Rootfs:代表一個 Docker Container 在啟動時(而非運(yùn)行后)其內(nèi)部進(jìn)程可見的文件系統(tǒng)視角,或者是 Docker Container 的根目錄。當(dāng)然,該目錄下含有 Docker Container 所需要的系統(tǒng)文件、工具、容器文件等。

    傳統(tǒng)來說,Linux 操作系統(tǒng)內(nèi)核啟動時,內(nèi)核首先會掛載一個只讀(read-only)的 rootfs,當(dāng)系統(tǒng)檢測其完整性之后,決定是否將其切換為讀寫(read-write)模式,或者最后在 rootfs 之上另行掛載一種文件系統(tǒng)并忽略 rootfs。Docker 架構(gòu)下,依然沿用 Linux 中 rootfs 的思想。當(dāng) Docker Daemon 為 Docker Container 掛載 rootfs 的時候,與傳統(tǒng) Linux 內(nèi)核類似,將其設(shè)定為只讀(read-only)模式。在 rootfs 掛載完畢之后,和 Linux 內(nèi)核不一樣的是,Docker Daemon 沒有將 Docker Container 的文件系統(tǒng)設(shè)為讀寫(read-write)模式,而是利用 Union mount 的技術(shù),在這個只讀的 rootfs 之上再掛載一個讀寫(read-write)的文件系統(tǒng),掛載時該讀寫(read-write)文件系統(tǒng)內(nèi)空無一物。

    Docker鏡像分層怎么實現(xiàn)

    正如 read-only 和 read-write 的含義那樣,該容器中的進(jìn)程對 rootfs 中的內(nèi)容只擁有讀權(quán)限,對于 read-write 讀寫文件系統(tǒng)中的內(nèi)容既擁有讀權(quán)限也擁有寫權(quán)限。容器雖然只有一個文件系統(tǒng),但該文件系統(tǒng)由“兩層”組成,分別為讀寫文件系統(tǒng)和只讀文件系統(tǒng)。

    Union mount

    Union mount:代表一種文件系統(tǒng)掛載的方式,允許同一時刻多種文件系統(tǒng)掛載在一起,并以一種文件系統(tǒng)的形式,呈現(xiàn)多種文件系統(tǒng)內(nèi)容合并后的目錄。

    一般情況下,通過某種文件系統(tǒng)掛載內(nèi)容至掛載點的話,掛載點目錄中原先的內(nèi)容將會被隱藏。而 Union mount 則不會將掛載點目錄中的內(nèi)容隱藏,反而是將掛載點目錄中的內(nèi)容和被掛載的內(nèi)容合并,并為合并后的內(nèi)容提供一個統(tǒng)一獨立的文件系統(tǒng)視角。通常來講,被合并的文件系統(tǒng)中只有一個會以讀寫(read-write)模式掛載,而其他的文件系統(tǒng)的掛載模式均為只讀(read-only)。實現(xiàn)這種 Union mount 技術(shù)的文件系統(tǒng)一般被稱為 Union Filesystem,較為常見的有 UnionFS、AUFS、OverlayFS 等。

    Docker 實現(xiàn)容器文件系統(tǒng) Union mount 時,提供多種具體的文件系統(tǒng)解決方案,如 Docker 早版本沿用至今的的 AUFS,還有在 docker 1.4.0 版本中開始支持的 OverlayFS 等。

    Docker鏡像分層怎么實現(xiàn)

    AUFS 掛載 Ubuntu 文件系統(tǒng)示意圖

    使用鏡像 ubuntu 創(chuàng)建的容器中,可以暫且將該容器整個 rootfs 當(dāng)成是一個文件系統(tǒng)。上文也提到,掛載時讀寫(read-write)文件系統(tǒng)中空無一物。既然如此,從用戶視角來看,容器內(nèi)文件系統(tǒng)和 rootfs 完全一樣,用戶完全可以按照往常習(xí)慣,無差別的使用自身視角下文件系統(tǒng)中的所有內(nèi)容;然而,從內(nèi)核的角度來看,兩者在有著非常大的區(qū)別。追溯區(qū)別存在的根本原因,那就不得不提及 AUFS 等文件系統(tǒng)的 COW(copy-on-write)特性。

    COW 文件系統(tǒng)和其他文件系統(tǒng)最大的區(qū)別就是:從不覆寫已有文件系統(tǒng)中已有的內(nèi)容。由于通過 COW 文件系統(tǒng)將兩個文件系統(tǒng)(rootfs 和 read-write filesystem)合并,最終用戶視角為合并后的含有所有內(nèi)容的文件系統(tǒng),然而在 Linux 內(nèi)核邏輯上依然可以區(qū)別兩者,那就是用戶對原先 rootfs 中的內(nèi)容擁有只讀權(quán)限,而對 read-write filesystem 中的內(nèi)容擁有讀寫權(quán)限。

    既然對用戶而言,全然不知哪些內(nèi)容只讀,哪些內(nèi)容可讀寫,這些信息只有內(nèi)核在接管,那么假設(shè)用戶需要更新其視角下的文件 /etc/hosts,而該文件又恰巧是 rootfs 只讀文件系統(tǒng)中的內(nèi)容,內(nèi)核是否會拋出異?;蛘唏g回用戶請求呢?答案是否定的。當(dāng)此情形發(fā)生時,COW 文件系統(tǒng)首先不會覆寫 read-only 文件系統(tǒng)中的文件,即不會覆寫 rootfs 中 /etc/hosts,其次反而會將該文件拷貝至讀寫文件系統(tǒng)中,即拷貝至讀寫文件系統(tǒng)中的 /etc/hosts,最后再對后者進(jìn)行更新操作。如此一來,縱使 rootfs 與 read-write filesystem 中均由 /etc/hosts,諸如 AUFS 類型的 COW 文件系統(tǒng)也能保證用戶視角中只能看到 read-write filesystem 中的 /etc/hosts,即更新后的內(nèi)容。

    當(dāng)然,這樣的特性同樣支持 rootfs 中文件的刪除等其他操作。例如:用戶通過 apt-get 軟件包管理工具安裝 Golang,所有與 Golang 相關(guān)的內(nèi)容都會被安裝在讀寫文件系統(tǒng)中,而不會安裝在 rootfs。此時用戶又希望通過 apt-get 軟件包管理工具刪除所有關(guān)于 MySQL 的內(nèi)容,恰巧這部分內(nèi)容又都存在于 rootfs 中時,刪除操作執(zhí)行時同樣不會刪除 rootfs 實際存在的 MySQL,而是在 read-write filesystem 中刪除該部分內(nèi)容,導(dǎo)致最終 rootfs 中的 MySQL 對容器用戶不可見,也不可訪。

    掌握 Docker 中 rootfs 以及 Union mount 的概念之后,再來理解 Docker 鏡像,就會變得水到渠成。

    image

    Docker 中 rootfs 的概念,起到容器文件系統(tǒng)中基石的作用。對于容器而言,其只讀的特性,也是不難理解。神奇的是,實際情況下 Docker 的 rootfs 設(shè)計與實現(xiàn)比上文的描述還要精妙不少。

    繼續(xù)以 ubuntu 為例,雖然通過 AUFS 可以實現(xiàn) rootfs 與 read-write filesystem 的合并,但是考慮到 rootfs 自身接近 200MB 的磁盤大小,如果以這個 rootfs 的粒度來實現(xiàn)容器的創(chuàng)建與遷移等,是否會稍顯笨重,同時也會大大降低鏡像的靈活性。而且,若用戶希望擁有一個 ubuntu 的 rootfs,那么是否有必要創(chuàng)建一個全新的 rootfs,畢竟 ubuntu 和 ubuntu 的 rootfs 中有很多一致的內(nèi)容。

    Docker 中 image 的概念,非常巧妙的解決了以上的問題。最為簡單的解釋 image,就是 Docker 容器中只讀文件系統(tǒng) rootfs 的一部分。換言之,實際上 Docker 容器的 rootfs 可以由多個 image 來構(gòu)成。多個 image 構(gòu)成 rootfs 的方式依然沿用 Union mount 技術(shù)。

    Docker鏡像分層怎么實現(xiàn)

    多個 Image 構(gòu)成 rootfs 的示意圖。圖中,rootfs 中每一層 image 中的內(nèi)容劃分只為了闡述清楚 rootfs 由多個 image 構(gòu)成,并不代表實際情況中 rootfs 中的內(nèi)容劃分。

    從上圖可以看出,舉例的容器 rootfs 包含 4 個 image,其中每個 image 中都有一些用戶視角文件系統(tǒng)中的一部分內(nèi)容。4 個 image 處于層疊的關(guān)系,除了最底層的 image,每一層的 image 都疊加在另一個 image 之上。另外,每一個 image 均含有一個 image ID,用以唯一的標(biāo)記該 image。

    基于以上的概念,Docker Image 中又抽象出兩種概念:Parent Image 以及 Base Image。除了容器 rootfs 最底層的 image,其余 image 都依賴于其底下的一個或多個 image,而 Docker 中將下一層的 image 稱為上一層 image 的 Parent Image。imageID_0 是 imageID_1 的 Parent Image,imageID_2 是 imageID_3 的 Parent Image,而 imageID_0 沒有 Parent Image。對于最下層的 image,即沒有 Parent Image 的鏡像,在 Docker 中習(xí)慣稱之為 Base Image。

    通過 image 的形式,原先較為臃腫的 rootfs 被逐漸打散成輕便的多層。Image 除了輕便的特性,同時還有上文提到的只讀特性,如此一來,在不同的容器、不同的 rootfs 中 image 完全可以用來復(fù)用。

    多 image 組織關(guān)系與復(fù)用關(guān)系如圖下圖(圖中鏡像名稱的舉例只為將 image 之間的關(guān)系闡述清楚,并不代表實際情況中相應(yīng)名稱 image 之間的關(guān)系):

    Docker鏡像分層怎么實現(xiàn)

    多 image 組織關(guān)系示意圖

    圖中共羅列了 11 個 image,這 11 個 image 之間的關(guān)系呈現(xiàn)一副森林圖。森林中含有兩棵樹,左邊樹中包含 5 個節(jié)點,即含有 5 個 image;右邊樹中包含 6 個節(jié)點,即含有 6 個 image。圖中,有些 image 標(biāo)記了紅色字段,意味該 image 代表某一種容器鏡像 rootfs 的最上層 image。如圖中的 ubuntu:14.04,代表 imageID_3 為該類型容器 rootfs 的最上層,沿著該節(jié)點找到樹的根節(jié)點,可以發(fā)現(xiàn)路徑上還有 imageID_2,imageID_1 和 imageID_0。特殊的是,imageID_2 作為 imageID_3 的 Parent Image,同時又是容器鏡像 ubuntu:12.04 的 rootfs 中的最上層,可見鏡像 ubuntu:14.04 只是在鏡像 ubuntu:12.04 之上,再另行疊加了一層。因此,在下載鏡像 ubuntu:12.04 以及 ubuntu:14.04 時,只會下載一份 imageID_2、imageID_1 和 imageID_0,實現(xiàn) image 的復(fù)用。同時,右邊樹中 mysql:5.6、mongo:2.2、debian:wheezy 和 debian:jessie 也呈現(xiàn)同樣的關(guān)系。

    layer

    Docker 術(shù)語中,layer 是一個與 image 含義較為相近的詞。容器鏡像的 rootfs 是容器只讀的文件系統(tǒng),rootfs 又是由多個只讀的 image 構(gòu)成。于是,rootfs 中每個只讀的 image 都可以稱為一層 layer。

    除了只讀的 image 之外,Docker Daemon 在創(chuàng)建容器時會在容器的 rootfs 之上,再 mount 一層 read-write filesystem,而這一層文件系統(tǒng),也稱為容器的一層 layer,常被稱為 top layer。

    因此,總結(jié)而言,Docker 容器中的每一層只讀的 image,以及最上層可讀寫的文件系統(tǒng),均被稱為 layer。如此一來,layer 的范疇比 image 多了一層,即多包含了最上層的 read-write filesystem。

    有了 layer 的概念,大家可以思考這樣一個問題:容器文件系統(tǒng)分為只讀的 rootfs,以及可讀寫的 top layer,那么容器運(yùn)行時若在 top layer 中寫入了內(nèi)容,那這些內(nèi)容是否可以持久化,并且也被其它容器復(fù)用?

    上文對于 image 的分析中,提到了 image 有復(fù)用的特性,既然如此,再提一個更為大膽的假設(shè):容器的 top layer 是否可以轉(zhuǎn)變?yōu)?image?

    答案是肯定的。Docker 的設(shè)計理念中,top layer 轉(zhuǎn)變?yōu)?image 的行為(Docker 中稱為 commit 操作),大大釋放了容器 rootfs 的靈活性。Docker 的開發(fā)者完全可以基于某個鏡像創(chuàng)建容器做開發(fā)工作,并且無論在開發(fā)周期的哪個時間點,都可以對容器進(jìn)行 commit,將所有 top layer 中的內(nèi)容打包為一個 image,構(gòu)成一個新的鏡像。Commit 完畢之后,用戶完全可以基于新的鏡像,進(jìn)行開發(fā)、分發(fā)、測試、部署等。不僅 docker commit 的原理如此,基于 Dockerfile 的 docker build,其追核心的思想,也是不斷將容器的 top layer 轉(zhuǎn)化為 image。

    爽,酣暢淋漓啊這波讀下來?。?!

    Docker 鏡像下載

    Docker Image 作為 Docker 生態(tài)中的精髓,下載過程中需要 Docker 架構(gòu)中多個組件的協(xié)作。Docker 鏡像的下載流程如圖:

    Docker鏡像分層怎么實現(xiàn)

    1、docker client發(fā)送鏡像的tag到registry。
    2、registry根據(jù)鏡像tag,得到鏡像的manifest文件,返回給docker client。
    3、docker client拿到manifest文件后,根據(jù)其中的config的digest,也就是image ID,檢查下鏡像在本地是否存在。
    4、如果鏡像不存在,則下載config文件,并根據(jù)config文件中的diff_ids得到鏡像每一層解壓后的digest。
    5、然后根據(jù)每層解壓后的digest文件,檢查本地是否存在,如果不存在,則通過manifest文件中的6、layer的digest下載該層并解壓,然后校驗解壓后digest是否匹配。
    7、下載完所有層后,鏡像就下載完畢。

    鏡像存儲

    Docker Daemon 執(zhí)行鏡像下載任務(wù)時,從 Docker Registry 處下載指定鏡像之后,仍需要將鏡像合理地存儲于宿主機(jī)的文件系統(tǒng)中。更為具體而言,存儲工作分為兩個部分:

    (1) 存儲鏡像內(nèi)容;

    (2) 在 graph 中注冊鏡像信息。

    說到鏡像內(nèi)容,需要強(qiáng)調(diào)的是,每一層 layer 的 Docker Image 內(nèi)容都可以認(rèn)為有兩個部分組成:鏡像中每一層 layer 中存儲的文件系統(tǒng)內(nèi)容,這部分內(nèi)容一般可以認(rèn)為是未來 Docker 容器的靜態(tài)文件內(nèi)容;另一部分內(nèi)容指的是容器的 json 文件,json 文件代表的信息除了容器的基本屬性信息之外,還包括未來容器運(yùn)行時的動態(tài)信息,包括 ENV 等信息。

    存儲鏡像內(nèi)容,意味著 Docker Daemon 所在宿主機(jī)上已經(jīng)存在鏡像的所有內(nèi)容,除此之外,Docker Daemon 仍需要對所存儲的鏡像進(jìn)行統(tǒng)計備案,以便用戶在后續(xù)的鏡像管理與使用過程中,可以有據(jù)可循。為此,Docker Daemon 設(shè)計了 graph,使用 graph 來接管這部分的工作。graph 負(fù)責(zé)記錄有哪些鏡像已經(jīng)被正確存儲,供 Docker Daemon 調(diào)用。

    鏡像在遠(yuǎn)端倉庫存儲

    在本地起一個registry服務(wù),然后推送三個鏡像到鏡像倉庫。可以得到registry中的文件內(nèi)容如下所示。registry中包含三個鏡像: xxx/library/debian:latest,xxx/repo:tag和xxx/busybox:v1

    └── registry
        └── v2
            ├── blobs
            │   └── sha256
            │       ├── 0d
            │       │   └── 0d96da54f60b86a4d869d44b44cfca69d71c4776b81d361bc057d6666ec0d878
            │       │       └── data
            │       ├── 34
            │       │   └── 34efe68cca33507682b1673c851700ec66839ecf94d19b928176e20d20e02413
            │       │       └── data
            │       ...
            └── repositories
                ├── busybox
                │   ├── _layers
                │   │   └── sha256
                │   │       ├── 7138284460ffa3bb6ee087344f5b051468b3f8697e2d1427bac1a20c8d168b14
                │   │       │   └── link
                │   │       └── e685c5c858e36338a47c627763b50dfe6035b547f1f75f0d39753db71e319016
                │   │           └── link
                │   ├── _manifests
                │   │   ├── revisions
                │   │   │   └── sha256
                │   │   │       └── 34efe68cca33507682b1673c851700ec66839ecf94d19b928176e20d20e02413
                │   │   │           └── link
                │   │   └── tags
                │   │       └── v1
                │   │           ├── current
                │   │           │   └── link
                │   │           └── index
                │   │               └── sha256
                │   │                   └── 34efe68cca33507682b1673c851700ec66839ecf94d19b928176e20d20e02413
                │   │                       └── link
                │   └── _uploads
                ├── library
                │   └── debian
                │       ├── _layers
                │       │   └── sha256
                │       │       ├── 41c22baa66ecf728c1ea0c5405ebe72c5b2606ef66b4565a209e23e1ab05fe80
                │       │       │   └── link
                │       │       ├── 67283bbdd4a0dd32f555b4279fd546b3c69251342f0c6715b075cc72049d28a1
                │       │       │   └── link
                │       │       ...
                │       ├── _manifests
                │       │   ├── revisions
                │       │   │   └── sha256
                │       │   │       └── 57c1e4ff150e2782a25c8cebb80b574f81f06b74944caf972f27e21b76074194
                │       │   │           └── link
                │       │   └── tags
                │       │       └── latest
                │       │           ├── current
                │       │           │   └── link
                │       │           └── index
                │       │               └── sha256
                │       │                   └── 57c1e4ff150e2782a25c8cebb80b574f81f06b74944caf972f27e21b76074194
                │       │                       └── link
                │       └── _uploads
                └── repo
                    ├── _layers
                    │   └── sha256
                    │       ├── 0d96da54f60b86a4d869d44b44cfca69d71c4776b81d361bc057d6666ec0d878
                    │       │   └── link
                    │       ├── 3790aef225b922bc97aaba099fe762f7b115aec55a0083824b548a6a1e610719
                    │       │   └── link
                    │       ...
                    ├── _manifests
                    │   ├── revisions
                    │   │   └── sha256
                    │   │       └── 36cb5b157911061fb610d8884dc09e0b0300a767a350563cbfd88b4b85324ce4
                    │   │           └── link
                    │   └── tags
                    │       └── tag
                    │           ├── current
                    │           │   └── link
                    │           └── index
                    │               └── sha256
                    │                   └── 36cb5b157911061fb610d8884dc09e0b0300a767a350563cbfd88b4b85324ce4
                    │                       └── link
                    └── _uploads

    對上面的文件結(jié)構(gòu)進(jìn)行整理,可以得到如下圖所示的結(jié)構(gòu):

    Docker鏡像分層怎么實現(xiàn)

    registry有兩個目錄,分別為blobs和repositories,其中blobs保存的是鏡像的manifest文件、config文件和layer文件內(nèi)容,文件名字均為data,每個文件可能是manifest、config、layer中的一種。repositories保存的是鏡像的repo、tag、layer摘要等信息。其中的_manifests文件夾下包含著鏡像的 tags 和 revisions 信息,每一個鏡像的每一個 tag 對應(yīng) tag 名相同的目錄。每個 tag名目錄下面有 current 目錄和 index 目錄, current 目錄下的 link 文件保存了該 tag 目前的 manifest 文件的 sha256 編碼,對應(yīng)在 blobs 中的 sha256 目錄下的 data 文件,而 index 目錄則列出了該 tag 歷史上傳的所有版本的 sha256 編碼信息。_revisions 目錄里存放了該 repository 歷史上上傳版本的所有 sha256 編碼信息。

    本地鏡像存儲

    鏡像在本地存儲目錄為/var/lib/docker/image/overlay2,查看下面的文件結(jié)構(gòu):

    tree -L 4 /var/lib/docker/image/overlay2/
    /var/lib/docker/image/overlay2/
    ├── distribution
    │   ├── diffid-by-digest
    │   │   └── sha256
    │   │       ├── 0240c3db9dedbfe40ec02d465375aa5b059bf8ac78dc249d1f1c91b9429fce44
    │   │       ├── 41c22baa66ecf728c1ea0c5405ebe72c5b2606ef66b4565a209e23e1ab05fe80
    │   │       ├── 4cdd12619cf5ed0ae43b41cd51f26fbdbd1f5ded860e4188822ec29158218263
    │   │       ├── ...
    │   └── v2metadata-by-diffid
    │       └── sha256
    │           ├── 00188c48b6d80656e2344142a77bccf6927123e7492baf43df68e280b2baf7f2
    │           ├── 04fefa2a1a8fefaafde3b966f11d547e3bbaa2bb36bf90c58e33c1d305052fa9
    │           ├── ...
    ├── imagedb
    │   ├── content
    │   │   └── sha256
    │   │       ├── 7138284460ffa3bb6ee087344f5b051468b3f8697e2d1427bac1a20c8d168b14
    │   │       ├── ...
    │   └── metadata
    │       └── sha256
    │           ├── b8604a3fe8543c9e6afc29550de05b36cd162a97aa9b2833864ea8a5be11f3e2
    │           └── dabbfbe0c57b6e5cd4bc089818d3f664acfad496dc741c9a501e72d15e803b34
    ├── layerdb
    │   ├── mounts
    │   │   ├── 2d534be7517fb3efd9c14248eefdb4781924095fe304f5aa0c848f2e76c6bf08
    │   │   │   ├── init-id
    │   │   │   ├── mount-id
    │   │   │   └── parent
    │   │   ├──...
    │   ├── sha256
    │   │   ├── 0e16a5a61bcb4e6b2bb2d746c2d6789d6c0b66198208b831f74b52198d744189
    │   │   │   ├── cache-id
    │   │   │   ├── diff
    │   │   │   ├── parent
    │   │   │   ├── size
    │   │   │   └── tar-split.json.gz
    │   │   ├── 0ee0aa554b8be64c963aaaf162df152784d868d21a7414146cb819a93e4bdb9e
    │   │   │   ├── cache-id
    │   │   │   ├── diff
    │   │   │   ├── parent
    │   │   │   ├── size
    │   │   │   └── tar-split.json.gz
    │   │   ├── ...
    │   └── tmp
    └── repositories.json

    對上面的文件結(jié)構(gòu)進(jìn)行整理,可以得到如下圖所示的結(jié)構(gòu):

    Docker鏡像分層怎么實現(xiàn)

    以上就是“Docker鏡像分層怎么實現(xiàn)”這篇文章的所有內(nèi)容,感謝各位的閱讀!相信大家閱讀完這篇文章都有很大的收獲,小編每天都會為大家更新不同的知識,如果還想學(xué)習(xí)更多的知識,請關(guān)注億速云行業(yè)資訊頻道。

    向AI問一下細(xì)節(jié)

    免責(zé)聲明:本站發(fā)布的內(nèi)容(圖片、視頻和文字)以原創(chuàng)、轉(zhuǎn)載和分享為主,文章觀點不代表本網(wǎng)站立場,如果涉及侵權(quán)請聯(lián)系站長郵箱:is@yisu.com進(jìn)行舉報,并提供相關(guān)證據(jù),一經(jīng)查實,將立刻刪除涉嫌侵權(quán)內(nèi)容。

    AI