更新時間:2021-06-16 16:40:07 來源:動力節(jié)點 瀏覽2143次
docker鏡像是一個只讀的docker容器模板,含有啟動docker容器所需的文件系統(tǒng)結構及其內容,因此是啟動一個docker容器的基礎。docker鏡像的文件內容以及一些運行docker容器的配置文件組成了docker容器的靜態(tài)文件系統(tǒng)運行環(huán)境:rootfs。可以這么理解,docker鏡像是docker容器的靜態(tài)視角,docker容器是docker鏡像的運行狀態(tài)。我們可以通過下圖來理解docker daemon、docker鏡像以及docker容器三者的關系

從上圖中我們可以看到,當由ubuntu:14.04鏡像啟動容器時,ubuntu:14.04鏡像的鏡像層內容將作為容器的rootfs;而ubuntu:14.04鏡像的json文件,會由docker daemon解析,并提取出其中的容器執(zhí)行入口CMD信息,以及容器進程的環(huán)境變量ENV信息,最終初始化容器進程。當然,容器進程的執(zhí)行入口來源于鏡像提供的rootfs。
rootfs
rootfs是docker容器在啟動時內部進程可見的文件系統(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)內核啟動時,首先掛載一個只讀的rootfs,當系統(tǒng)檢測其完整性之后,再將其切換為讀寫模式。而在docker架構中,當docker daemon為docker容器掛載rootfs時,沿用了Linux內核啟動時的做法,即將rootfs設為只讀模式。在掛載完畢之后,利用聯(lián)合掛載(union mount)技術在已有的只讀rootfs上再掛載一個讀寫層。這樣,可讀寫的層處于docker容器文件系統(tǒng)的最頂層,其下可能聯(lián)合掛載了多個只讀的層,只有在docker容器運行過程中文件系統(tǒng)發(fā)生變化時,才會把變化的文件內容寫到可讀寫層,并隱藏只讀層中的舊版本文件。
為了更好的理解docker鏡像的結構,下面介紹一下docker鏡像設計上的關鍵技術。
分層docker鏡像是采用分層的方式構建的,每個鏡像都由一系列的"鏡像層"組成。分層結構是docker鏡像如此輕量的重要原因。當需要修改容器鏡像內的某個文件時,只對處于最上方的讀寫層進行變動,不覆寫下層已有文件系統(tǒng)的內容,已有文件在只讀層中的原始版本仍然存在,但會被讀寫層中的新版本所隱藏。當使用docker commit提交這個修改過的容器文件系統(tǒng)為一個新的鏡像時,保存的內容僅為最上層讀寫文件系統(tǒng)中被更新過的文件。分層達到了在不的容器同鏡像之間共享鏡像層的效果。
寫時復制docker鏡像使用了寫時復制(copy-on-write)的策略,在多個容器之間共享鏡像,每個容器在啟動的時候并不需要單獨復制一份鏡像文件,而是將所有鏡像層以只讀的方式掛載到一個掛載點,再在上面覆蓋一個可讀寫的容器層。在未更改文件內容時,所有容器共享同一份數(shù)據(jù),只有在docker容器運行過程中文件系統(tǒng)發(fā)生變化時,才會把變化的文件內容寫到可讀寫層,并隱藏只讀層中的老版本文件。寫時復制配合分層機制減少了鏡像對磁盤空間的占用和容器啟動時間。
內容尋址在docker 1.10版本后,docker鏡像改動較大,其中最重要的特性便是引入了內容尋址存儲(content-addressable storage)的機制,根據(jù)文件的內容來索引鏡像和鏡像層。與之前版本對每個鏡像層隨機生成一個UUID不同,新模型對鏡像層的內容計算校驗和,生成一個內容哈希值,并以此哈希值代替之前的UUID作為鏡像層的唯一標識。該機制主要提高了鏡像的安全性,并在pull、push、load和save操作后檢測數(shù)據(jù)的完整性。另外,基于內容哈希來索引鏡像層,在一定程度上減少了ID的沖突并且增強了鏡像層的共享。對于來自不同構建的鏡像層,主要擁有相同的內容哈希,也能被不同的鏡像共享。
聯(lián)合掛載通俗地講,聯(lián)合掛載技術可以在一個掛載點同時掛載多個文件系統(tǒng),將掛載點的原目錄與被掛載內容進行整合,使得最終可見的文件系統(tǒng)將會包含整合之后的各層的文件和目錄。實現(xiàn)這種聯(lián)合掛載技術的文件系統(tǒng)通常被稱為聯(lián)合文件系統(tǒng)(union filesystem)。以下圖所示的運行Ubuntu:14.04鏡像后的容器中的aufs文件系統(tǒng)為例:

由于初始掛載時讀寫層為空,所以從用戶的角度看,該容器的文件系統(tǒng)與底層的rootfs沒有差別;然而從內核的角度看,則是顯式區(qū)分開來的兩個層次。當需要修改鏡像內的某個文件時,只對處于最上方的讀寫層進行了變動,不復寫下層已有文件系統(tǒng)的內容,已有文件在只讀層中的原始版本仍然存在,但會被讀寫層中的新版本文件所隱藏,當docker commit這個修改過的容器文件系統(tǒng)為一個新的鏡像時,保存的內容僅為最上層讀寫文件系統(tǒng)中被更新過的文件。聯(lián)合掛載是用于將多個鏡像層的文件系統(tǒng)掛載到一個掛載點來實現(xiàn)一個統(tǒng)一文件系統(tǒng)視圖的途徑,是下層存儲驅動(aufs、overlay等)實現(xiàn)分層合并的方式。所以嚴格來說,聯(lián)合掛載并不是docker鏡像的必需技術,比如在使用device mapper存儲驅動時,其實是使用了快照技術來達到分層的效果。
Docker鏡像的存儲組織方式
綜合考慮鏡像的層級結構,以及volume、init-layer、可讀寫層這些概念,一個完整的、在運行的容器的所有文件系統(tǒng)結構可以用下圖來描述:

從圖中我們不難看到,除了 echo hello 進程所在的 cgroups 和 namespace 環(huán)境之外,容器文件系統(tǒng)其實是一個相對獨立的組織。可讀寫部分(read-write layer 以及 volumes)、init-layer、只讀層(read-only layer) 這 3 部分結構共同組成了一個容器所需的下層文件系統(tǒng),它們通過聯(lián)合掛載的方式巧妙地表現(xiàn)為一層,使得容器進程對這些層的存在一無所知。
以上就是動力節(jié)點小編介紹的"Docker鏡像的技術原理",希望對大家有幫助,如有疑問,請在線咨詢,有專業(yè)老師隨時為您服務。