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