更新時間:2021-06-16 16:40:07 來源:動力節(jié)點 瀏覽1839次
docker鏡像是一個只讀的docker容器模板,含有啟動docker容器所需的文件系統(tǒng)結(jié)構(gòu)及其內(nèi)容,因此是啟動一個docker容器的基礎(chǔ)。docker鏡像的文件內(nèi)容以及一些運行docker容器的配置文件組成了docker容器的靜態(tài)文件系統(tǒng)運行環(huán)境:rootfs。可以這么理解,docker鏡像是docker容器的靜態(tài)視角,docker容器是docker鏡像的運行狀態(tài)。我們可以通過下圖來理解docker daemon、docker鏡像以及docker容器三者的關(guān)系
從上圖中我們可以看到,當(dāng)由ubuntu:14.04鏡像啟動容器時,ubuntu:14.04鏡像的鏡像層內(nèi)容將作為容器的rootfs;而ubuntu:14.04鏡像的json文件,會由docker daemon解析,并提取出其中的容器執(zhí)行入口CMD信息,以及容器進程的環(huán)境變量ENV信息,最終初始化容器進程。當(dāng)然,容器進程的執(zhí)行入口來源于鏡像提供的rootfs。
rootfs
rootfs是docker容器在啟動時內(nèi)部進程可見的文件系統(tǒng),即docker容器的根目錄。rootfs通常包含一個操作系統(tǒng)運行所需的文件系統(tǒng),例如可能包含典型的類Unix操作系統(tǒng)中的目錄系統(tǒng),如/dev、/proc、/bin、/etc、/lib、/usr、/tmp及運行docker容器所需的配置文件、工具等。在傳統(tǒng)的Linux操作系統(tǒng)內(nèi)核啟動時,首先掛載一個只讀的rootfs,當(dāng)系統(tǒng)檢測其完整性之后,再將其切換為讀寫模式。而在docker架構(gòu)中,當(dāng)docker daemon為docker容器掛載rootfs時,沿用了Linux內(nèi)核啟動時的做法,即將rootfs設(shè)為只讀模式。在掛載完畢之后,利用聯(lián)合掛載(union mount)技術(shù)在已有的只讀rootfs上再掛載一個讀寫層。這樣,可讀寫的層處于docker容器文件系統(tǒng)的最頂層,其下可能聯(lián)合掛載了多個只讀的層,只有在docker容器運行過程中文件系統(tǒng)發(fā)生變化時,才會把變化的文件內(nèi)容寫到可讀寫層,并隱藏只讀層中的舊版本文件。
為了更好的理解docker鏡像的結(jié)構(gòu),下面介紹一下docker鏡像設(shè)計上的關(guān)鍵技術(shù)。
分層docker鏡像是采用分層的方式構(gòu)建的,每個鏡像都由一系列的"鏡像層"組成。分層結(jié)構(gòu)是docker鏡像如此輕量的重要原因。當(dāng)需要修改容器鏡像內(nèi)的某個文件時,只對處于最上方的讀寫層進行變動,不覆寫下層已有文件系統(tǒng)的內(nèi)容,已有文件在只讀層中的原始版本仍然存在,但會被讀寫層中的新版本所隱藏。當(dāng)使用docker commit提交這個修改過的容器文件系統(tǒng)為一個新的鏡像時,保存的內(nèi)容僅為最上層讀寫文件系統(tǒng)中被更新過的文件。分層達到了在不的容器同鏡像之間共享鏡像層的效果。
寫時復(fù)制docker鏡像使用了寫時復(fù)制(copy-on-write)的策略,在多個容器之間共享鏡像,每個容器在啟動的時候并不需要單獨復(fù)制一份鏡像文件,而是將所有鏡像層以只讀的方式掛載到一個掛載點,再在上面覆蓋一個可讀寫的容器層。在未更改文件內(nèi)容時,所有容器共享同一份數(shù)據(jù),只有在docker容器運行過程中文件系統(tǒng)發(fā)生變化時,才會把變化的文件內(nèi)容寫到可讀寫層,并隱藏只讀層中的老版本文件。寫時復(fù)制配合分層機制減少了鏡像對磁盤空間的占用和容器啟動時間。
內(nèi)容尋址在docker 1.10版本后,docker鏡像改動較大,其中最重要的特性便是引入了內(nèi)容尋址存儲(content-addressable storage)的機制,根據(jù)文件的內(nèi)容來索引鏡像和鏡像層。與之前版本對每個鏡像層隨機生成一個UUID不同,新模型對鏡像層的內(nèi)容計算校驗和,生成一個內(nèi)容哈希值,并以此哈希值代替之前的UUID作為鏡像層的唯一標(biāo)識。該機制主要提高了鏡像的安全性,并在pull、push、load和save操作后檢測數(shù)據(jù)的完整性。另外,基于內(nèi)容哈希來索引鏡像層,在一定程度上減少了ID的沖突并且增強了鏡像層的共享。對于來自不同構(gòu)建的鏡像層,主要擁有相同的內(nèi)容哈希,也能被不同的鏡像共享。
聯(lián)合掛載通俗地講,聯(lián)合掛載技術(shù)可以在一個掛載點同時掛載多個文件系統(tǒng),將掛載點的原目錄與被掛載內(nèi)容進行整合,使得最終可見的文件系統(tǒng)將會包含整合之后的各層的文件和目錄。實現(xiàn)這種聯(lián)合掛載技術(shù)的文件系統(tǒng)通常被稱為聯(lián)合文件系統(tǒng)(union filesystem)。以下圖所示的運行Ubuntu:14.04鏡像后的容器中的aufs文件系統(tǒng)為例:
由于初始掛載時讀寫層為空,所以從用戶的角度看,該容器的文件系統(tǒng)與底層的rootfs沒有差別;然而從內(nèi)核的角度看,則是顯式區(qū)分開來的兩個層次。當(dāng)需要修改鏡像內(nèi)的某個文件時,只對處于最上方的讀寫層進行了變動,不復(fù)寫下層已有文件系統(tǒng)的內(nèi)容,已有文件在只讀層中的原始版本仍然存在,但會被讀寫層中的新版本文件所隱藏,當(dāng)docker commit這個修改過的容器文件系統(tǒng)為一個新的鏡像時,保存的內(nèi)容僅為最上層讀寫文件系統(tǒng)中被更新過的文件。聯(lián)合掛載是用于將多個鏡像層的文件系統(tǒng)掛載到一個掛載點來實現(xiàn)一個統(tǒng)一文件系統(tǒng)視圖的途徑,是下層存儲驅(qū)動(aufs、overlay等)實現(xiàn)分層合并的方式。所以嚴(yán)格來說,聯(lián)合掛載并不是docker鏡像的必需技術(shù),比如在使用device mapper存儲驅(qū)動時,其實是使用了快照技術(shù)來達到分層的效果。
Docker鏡像的存儲組織方式
綜合考慮鏡像的層級結(jié)構(gòu),以及volume、init-layer、可讀寫層這些概念,一個完整的、在運行的容器的所有文件系統(tǒng)結(jié)構(gòu)可以用下圖來描述:
從圖中我們不難看到,除了 echo hello 進程所在的 cgroups 和 namespace 環(huán)境之外,容器文件系統(tǒng)其實是一個相對獨立的組織。可讀寫部分(read-write layer 以及 volumes)、init-layer、只讀層(read-only layer) 這 3 部分結(jié)構(gòu)共同組成了一個容器所需的下層文件系統(tǒng),它們通過聯(lián)合掛載的方式巧妙地表現(xiàn)為一層,使得容器進程對這些層的存在一無所知。
以上就是動力節(jié)點小編介紹的"Docker鏡像的技術(shù)原理",希望對大家有幫助,如有疑問,請在線咨詢,有專業(yè)老師隨時為您服務(wù)。
相關(guān)閱讀
初級 202925
初級 203221
初級 202629
初級 203743