Docker容器鏡像加載及底層基本原理深入解析
前言
回想上學(xué)的時(shí)候,某老師神采奕奕的講解著操作系統(tǒng)某個(gè)知識(shí)點(diǎn)原理,可謂是激情澎湃,我環(huán)顧周圍基友們,臉上懵逼兩字清晰可見,毫不含糊,恍然大悟原來是在講天書。為了不讓大家臉上呈現(xiàn)懵逼二字,希望能以人能看懂的語言,讓大家理解。
一、Docker run
這一小節(jié),標(biāo)題是Docker run ,我想受到過九年義務(wù)教育的大家,不難翻譯吧,如果這都翻譯不了,那么你一定要順著網(wǎng)線爬過來找我,我一定把你腦殼打得開竅。
上一章節(jié),最后我們用Docker啟動(dòng)了一個(gè)ningx的容器:
#運(yùn)行容器 docker run --name nginx-container -p 80:80 -d nginx
瀏覽器輸入虛擬機(jī)地址即可訪問 Nginx
那么,docker run啟動(dòng)命令是干了什么,才生成了一個(gè)nginx容器的呢?帶著疑問,我們接著說。
首先我們要很明白 運(yùn)行容器的命令
nginx-contarner
:nginx容器的名稱(容器相當(dāng)于java中類生成的對(duì)象)nginx
:鏡像(鏡像相當(dāng)于java中類)
(下圖借鑒一位博主的,如有不合適,請(qǐng)我聯(lián)系我刪除)
運(yùn)行容器命令,做了什么呢?首先Docker會(huì)去本機(jī)尋找鏡像,如果沒有找到,它會(huì)去DockerHub上去下載,如果能夠找到并下載到本地就會(huì)使用這個(gè)鏡像去執(zhí)行,否則就會(huì)返回找不到該鏡像的錯(cuò)誤。
就好比,你在家里上廁所,需要紙,你就會(huì)在廁所里尋找衛(wèi)生紙,如果找到了,就直接可以用了。但是,如果你沒有找到,那就得叫老爸在家里找衛(wèi)生紙,找到了你就可以安心笑了,沒有找到的話,老爸就會(huì)告訴你家里沒有衛(wèi)生紙紙。這里的衛(wèi)生紙就是所謂的鏡像.
二、Docker底層原理
1、Docker是怎么工作的
我們知道Docker是一個(gè)客戶端-服務(wù)端(C/S)架構(gòu)。根據(jù)上節(jié)講述的C/S架構(gòu)運(yùn)行模式就不難去理解。
Docker客戶端只需要向Docker守護(hù)進(jìn)程發(fā)出請(qǐng)求,Docker守護(hù)進(jìn)程在接收到Docker客戶端的請(qǐng)求后去執(zhí)行針對(duì)容器的相應(yīng)操作,完成所有工作后返回結(jié)果。(詳細(xì)深入待后續(xù))
守護(hù)進(jìn)程和普通進(jìn)程區(qū)別是指 : 將后臺(tái)程序變成一種服務(wù),比如說,用命令行輸入啟動(dòng)程序,如果不是守護(hù)進(jìn)程的話,一旦命令行窗口關(guān)閉,程序就終止了;而如果啟動(dòng)守護(hù)進(jìn)程,則退出命令行窗口之后,服務(wù)一直處于運(yùn)行狀態(tài)。
2、為什么Docker比虛擬機(jī)快
Docker與虛擬機(jī)的對(duì)比,第一節(jié)文章就已經(jīng)闡述過了。通過對(duì)比,我們就可以知道為什么Docker比虛擬機(jī)快。這里我在總結(jié)下:
1、容器由于沒有了虛擬操作系統(tǒng)和虛擬機(jī)監(jiān)視器這兩個(gè)層次,大幅減少了應(yīng)用程序運(yùn)行帶來的額外消耗。
2、Docker利用的是宿主機(jī)的內(nèi)核,那么容器中的應(yīng)用程序就是完全運(yùn)行在了宿主操作系統(tǒng)中。因此在docker容器里運(yùn)行應(yīng)用程序,與在宿主機(jī)中運(yùn)行應(yīng)用程序效果是一樣的。
三、Docker鏡像
1、鏡像
鏡像是Docker容器的基石,容器是鏡像的運(yùn)行實(shí)例,有了鏡像才能啟動(dòng)容器。它包含運(yùn)行某個(gè)軟件所需的所有內(nèi)容,包括代碼、運(yùn)行時(shí)、庫、環(huán)境變量和配置文件。(這里可以去上一篇文章中,有對(duì)Docker鏡像的形象比喻)
2、聯(lián)合文件系統(tǒng)UnionFS
要想理解Docker鏡像的加載原理,那么我們得要知道UnionFS(聯(lián)合文件系統(tǒng))
1、Union文件系統(tǒng)(UnionFS) 是一種分層、輕量級(jí)并且高性能的文件系統(tǒng),它支持對(duì)文件系統(tǒng)的修改作為一次提交來一層層的疊加,同時(shí)可以將不同目錄掛載到同一個(gè)虛擬文件系統(tǒng)下。Union文件系統(tǒng)是 Docker 鏡像的基礎(chǔ)。鏡像可以通過分層來進(jìn)行繼承,基于基礎(chǔ)鏡像(沒有父鏡像),可以制作各種具體的應(yīng)用鏡像。
看這文縐縐的Union文件系統(tǒng)的描述,難免呈現(xiàn)懵逼二字,過于抽象。看著都沒耐心繼續(xù)往下看…理解不了
UnionFS 最主要的功能簡(jiǎn)單理解為把不同的目錄合并成一個(gè)目錄,原來目錄下的內(nèi)容路徑都不會(huì)改變。比如,我現(xiàn)在有兩個(gè)目錄 A 和 B,它們分別有兩個(gè)文件:
$ tree . ├── A │ ├── a │ └── x └── B ├── b └── x
然后,使用聯(lián)合掛載的方式,將這兩個(gè)目錄掛載到一個(gè)公共的目錄 C 上:
$ mkdir C $ mount -t aufs -o dirs=./A:./B none ./C
這時(shí),再查看目錄 C 的內(nèi)容,就能看到目錄 A 和 B 下的文件被合并到了一起:
$ tree ./C ./C ├── a ├── b └── x
可以看到,在這個(gè)合并后的目錄 C 里,有 a、b、x 三個(gè)文件,并且 x 文件只有一份,同時(shí)合并后的目錄對(duì)于原來的目錄里文件的路徑是不會(huì)改變的。這,就是“合并”的含義。
但是,大家應(yīng)該會(huì)有個(gè)疑問,就是x文件到底是原先哪個(gè)目錄下的。答案是誰先被掛載就顯示成誰的,也就是說如果目錄A先被掛載,那優(yōu)先顯示目錄A里的x文件。(具體詳細(xì)深入后面講解)
3、Docker鏡像的加載原理
Docker設(shè)計(jì)時(shí),就充分利用Union FS的技術(shù),將其設(shè)計(jì)為分層存儲(chǔ)的架構(gòu)。 鏡像實(shí)際是由多層文件系統(tǒng)聯(lián)合組成,這種層級(jí)的文件系統(tǒng)UnionFS,在內(nèi)部又分為2部分:
1) bootfs(boot file system):docker鏡像的最底層是bootfs,主要包含bootloader(加載器)和kernel(內(nèi)核)。bootloader主要是引導(dǎo)加載kernel,linux剛啟動(dòng)時(shí)會(huì)加載bootfs文件系統(tǒng)。當(dāng)bootfs加載完成后,整個(gè)內(nèi)核就在內(nèi)存中了,此時(shí)內(nèi)存的使用權(quán)已由bootfs轉(zhuǎn)交給了內(nèi)核,此時(shí)系統(tǒng)也會(huì)卸載bootfs。
這里的加載,可以理解為,我們windows電腦開機(jī)時(shí)候,從黑屏到進(jìn)入操作系統(tǒng)的過程。
2)rootfs(root file system):在bootfs之上,包含的就是典型linux系統(tǒng)中的/dev、/proc、/bin、/etc等標(biāo)準(zhǔn)目錄和文件。不同的 Linux 發(fā)行版, boots 基本是一致的, rootfs 會(huì)有差別。
舉個(gè)例子:如下圖所示
以圖為例,從左到右,分為3個(gè)過程:
1、docker鏡像的最底層是bootfs,然后是一個(gè)Base Image的基礎(chǔ)鏡像,這個(gè)基礎(chǔ)鏡像是Centos。
2、執(zhí)行安裝mysql操作,那么Docker會(huì)在Centos基礎(chǔ)鏡像之上又加了一層mysql鏡像。
3、執(zhí)行安裝tomcat,那么在之前的mysql鏡像上在繼續(xù)加一層tomcat鏡像。
就像疊積目一樣,一層一層往上。也說明了docker的鏡像實(shí)際上是由層一層的文件系統(tǒng)組成的。對(duì)于不同的的linux發(fā)行版本,bootfs基本是一致的,rootfs會(huì)有差別,所以不同的發(fā)行版可以共用bootfs。
另外,平時(shí)我們安裝進(jìn)虛擬機(jī)的CentOS都是好幾個(gè)G,為什么Docker這里才200M?
因?yàn)榈讓又苯佑弥鳈C(jī)的內(nèi)核,自己只需要提供rootfs就行了,所以rootfs可以很小,只需要包含最基本的命令、工具和程序庫即可。這樣一來,啟動(dòng)速度也快了,因?yàn)樽罾速M(fèi)時(shí)間的引導(dǎo)加載過程沒了。
4、Docker鏡像分層理解
知道了鏡像的加載原理,我們?cè)趤砜纯碊ocker鏡像的分層理解。
首先可以去下載一個(gè)reids 鏡像,注意觀察下載的日志輸出,可以看到是一層層的在下載。
當(dāng)下載的層文件與我們之前層文件有沖突,也就是下載過的文件就會(huì)顯示Already exists不會(huì)再去下載,它只會(huì)去下載一些跟 redis 相關(guān)的新的東西。
那么:為什么Docker鏡像要采用這種分層的結(jié)構(gòu)呢?
這種方式最大的好處就在于資源共享。比如有多個(gè)鏡像都從相同的BASE鏡像構(gòu)建來的,那么宿主機(jī)只需要在磁盤上保留1分BASE鏡像,同時(shí)內(nèi)存中也只需要加載一份BASE鏡像,這樣所有的容器都可以使用。另外,鏡像的每一層都是可以共享的。
如何查看鏡像分層?
可以通過docker image inspect來查看鏡像的分層,比如查看剛才下載的redis鏡像:
docker image inspect redis:latest
所有的docker鏡像都起始于一個(gè)基礎(chǔ)鏡像層,當(dāng)進(jìn)行修改或者增加新的內(nèi)容時(shí),就會(huì)在當(dāng)前鏡像層之上,創(chuàng)建新的鏡像層。
就好比:修房子,首先有了地基,然后蓋了第一層后并裝修,開始蓋第二層,你發(fā)現(xiàn)想要的東西,第一層已經(jīng)有了,那么就不會(huì)重復(fù)去修建了,只會(huì)修不一樣,新的裝飾。
四、Docker容器
鏡像(Image)和容器(Container)的關(guān)系,就像是面向?qū)ο蟪绦蛟O(shè)計(jì)中的類和實(shí)例一樣,鏡像是靜態(tài)的定義,容器是鏡像運(yùn)行時(shí)的實(shí)體。容器可以被創(chuàng)建、啟動(dòng)、停止、刪除、暫停等 。
Docker | 面向?qū)ο?/th> |
---|---|
容器 | 對(duì)象 |
鏡像 | 類 |
容器的實(shí)質(zhì)是進(jìn)程,但與直接在宿主執(zhí)行的進(jìn)程是不同,容器進(jìn)程運(yùn)行于屬于自己的獨(dú)立的命名空間。因此容器可以擁有自己的 root 文件系統(tǒng)、自己的網(wǎng)絡(luò)配置、自己的進(jìn)程空間,甚至自己的用戶 ID 空間。
五、Docker鏡像與容器的形象比喻
請(qǐng)看上一章節(jié):大白話帶你快速安裝Docker,不懂你捶我
以上就是Docker容器鏡像加載及底層基本原理深入解析的詳細(xì)內(nèi)容,更多關(guān)于Docker容器鏡像加載底層原理的資料請(qǐng)關(guān)注腳本之家其它相關(guān)文章!
相關(guān)文章
Docker安裝部署Mysql8的過程(以作數(shù)據(jù)持久化)
這篇文章主要介紹了Docker安裝部署Mysql8(以作數(shù)據(jù)持久化),首先創(chuàng)建容器并進(jìn)行持久化處理,接著配置遠(yuǎn)程連接并嘗試,本文結(jié)合實(shí)例代碼給大家介紹的非常詳細(xì),需要的朋友可以參考下2022-09-09Docker 實(shí)現(xiàn)瀏覽器里開發(fā)Android應(yīng)用的功能
這篇文章主要介紹了Docker 實(shí)現(xiàn)瀏覽器里開發(fā)Android應(yīng)用的功能的相關(guān)資料,這里對(duì)布置環(huán)境做了詳細(xì)的步驟,也許你能用到這樣的功能,需要的朋友可以參考下2016-11-11基于Docker搭建Redis主從集群的實(shí)現(xiàn)
本文基于Docker+Redis5.0.5版本,通過cluster方式創(chuàng)建一個(gè)6個(gè)redis實(shí)例的主從集群,需要的朋友們下面隨著小編來一起學(xué)習(xí)學(xué)習(xí)吧2021-05-05在Docker容器中部署Django的時(shí)區(qū)問題
本文主要介紹了在Docker容器中部署Django的時(shí)區(qū)問題,文中通過示例代碼介紹的非常詳細(xì),具有一定的參考價(jià)值,感興趣的小伙伴們可以參考一下2021-10-10使用docker-compose搭建mysql主從詳細(xì)過程
這篇文章主要給大家介紹了關(guān)于使用docker-compose搭建mysql主從的相關(guān)資料,Docker-Compose項(xiàng)目是Docker官方的開源項(xiàng)目,負(fù)責(zé)實(shí)現(xiàn)對(duì)Docker容器集群的快速編排,需要的朋友可以參考下2024-01-01Docker網(wǎng)絡(luò)配置(橋接網(wǎng)絡(luò)和自定義網(wǎng)絡(luò))自定義網(wǎng)絡(luò)設(shè)置ip方式
這篇文章主要介紹了Docker網(wǎng)絡(luò)配置(橋接網(wǎng)絡(luò)和自定義網(wǎng)絡(luò))自定義網(wǎng)絡(luò)設(shè)置ip方式,具有很好的參考價(jià)值,希望對(duì)大家有所幫助,如有錯(cuò)誤或未考慮完全的地方,望不吝賜教2024-01-01基于Docker的Mysql主備搭建的實(shí)現(xiàn)步驟
本文主要介紹了基于Docker的Mysql主備搭建的實(shí)現(xiàn)步驟,文中通過示例代碼介紹的非常詳細(xì),具有一定的參考價(jià)值,感興趣的小伙伴們可以參考一下2022-01-01docker和docker-compose一鍵安裝教程(支持在線和離線)
這篇文章主要介紹了docker和docker-compose一鍵安裝(支持在線和離線),本文給大家介紹的非常詳細(xì),對(duì)大家的學(xué)習(xí)或工作具有一定的參考借鑒價(jià)值,需要的朋友可以參考下2020-12-12解決vscode docker插件docker.socket權(quán)限問題
本文給大家分享關(guān)于vscode docker插件docker.socket權(quán)限問題,文末給大家提到vscode中docker插件無法連接的問題及解決方案,需要的朋友參考下吧2021-06-06