溫馨提示×

溫馨提示×

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

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

docker容器底層技術(shù)怎么實現(xiàn)

發(fā)布時間:2021-12-30 14:55:03 來源:億速云 閱讀:186 作者:iii 欄目:云計算

本篇內(nèi)容介紹了“docker容器底層技術(shù)怎么實現(xiàn)”的有關(guān)知識,在實際案例的操作過程中,不少人都會遇到這樣的困境,接下來就讓小編帶領(lǐng)大家學(xué)習(xí)一下如何處理這些情況吧!希望大家仔細閱讀,能夠?qū)W有所成!

在沒有探討是否包含操作系統(tǒng)之前,大家一起來看兩張圖片,如下所示:

docker容器底層技術(shù)怎么實現(xiàn)很容易可以辨別出,圖一docker引擎畫在了應(yīng)用底部,類似于虛擬機的位置,docker虛擬化技術(shù)替代了虛擬機,更輕量級,看上去更容易理解和接受;

圖二docker引擎畫在了應(yīng)用的側(cè)邊欄,從圖片上看,進程則是直接運行在虛擬機上,docker容器更多的是進行旁路式的輔助和管理;其它沒什么區(qū)別,其中圖一也是PPT和網(wǎng)上常見的作圖方式,這種方式真的正確嗎?下文揭曉。

容器底層技術(shù)實現(xiàn)

docker底層主要是通過cgroup和namespace兩種技術(shù)實現(xiàn),cgroup實現(xiàn)資源限額, namespace實現(xiàn)資源隔離。

這兩個概念看起來非常抽象,其實一起來看個例子,一切就明白了,執(zhí)行docker exec -it 5080b69f08c4 /bin/bash

[root@tomcat-7c5857b68f-fzrbr /]# ps aux|grep tomcat
root         1 79.1 23.4 10168216 3788616 ?    Ssl  Oct22 8559:52 /usr/java/jre/bin/java -Djava.util.logging.config.file=/usr/local/tomcat/conf/logging.properties -Djava.io.tmpdir=/usr/local/tomcat/temp org.apache.catalina.startup.Bootstrap start
root       109  0.0  0.0   9052   668 pts/0    S+   19:24   0:00 grep --color=auto tomcat
 

在容器內(nèi)部執(zhí)行ps之后出現(xiàn)兩個進程在運行,一個是我的服務(wù),另外一個是我剛剛執(zhí)行的ps,已經(jīng)看到容器內(nèi)部進程已經(jīng)跟我們的宿主機中的服務(wù)完全隔離開了。這其實就是對被隔離應(yīng)用的進程空間做了隔離,使得這些進程空間下的進程只能看到重新計算之后的進程編號,這就是linux的namespace機制,linux底層是通過clone()函數(shù)實現(xiàn),而當(dāng)在docker中創(chuàng)建進程時就可以通過指定參數(shù)返回一個全新的進程空間,這樣的話的就做到了pid為1的目的,其實你到宿主機上查看下,這個docker中運行的服務(wù),在宿主機上存在著同樣的進程,只不過這個進程的pid是真實的pid。

除了剛才我們提到的pid namespace隔離技術(shù),Linux還為我們提供了Mount、UTS、IPC、Network、User等隔離機制,其效果都是為進程上下文起到隔離作用,使我們只能看到指定的內(nèi)容。

上面剛剛說了,namespace只是對進程做了隔離,使其在容器內(nèi)部看不到宿主機的進程,但是對于宿主機來說,還是能夠看到這些被隔離的進程。換句話說,這些被隔離的進程跟宿主機上的其它進程完全沒什么區(qū)別。所以說上述例子中的tomcat依然可以隨意占用宿主機的資源?其實docker利用了linux底層的Cgroup進行了資源限制。

Linux Cgroups 的全稱是 Linux Control Group。它最主要的作用,就是限制一個進程組能夠使用的資源上限,包括 CPU、內(nèi)存、磁盤、網(wǎng)絡(luò)帶寬等.

進入容器內(nèi)部/sys/fs/cgroup/文件夾下面,里面包含了很多子目錄,通過這些目錄中的文件內(nèi)容就可以實現(xiàn)對各種資源的限制。

看到這里,再品一下,容器就是一個進程而已。 

什么叫一個進程?你剛才上面舉的例子,不是在tomcat容器中執(zhí)行了一個ps,這明明是兩個進程,在說了,我也可以在這個容器中運行其它服務(wù),這些也都是正常運行的進程,這怎么能說是一個進程呢?不信的話,你進到看看nginx容器中ps看下,它的進程更多。

root         1  0.0  0.0  54952  4416 ?        Ss   Oct29   0:00 nginx: master process /usr/xshj/openresty/nginx/sbin/nginx -g daemon off;
xshj         6  0.0  0.1  76164 23380 ?        S    Oct29   0:00 nginx: worker process
xshj         7  0.0  0.1  76164 23380 ?        S    Oct29   0:00 nginx: worker process
xshj         8  0.0  0.1  76164 23392 ?        S    Oct29   0:00 nginx: worker process
xshj         9  0.0  0.1  76300 23392 ?        S    Oct29   0:00 nginx: worker process
root        25  0.0  0.0  12484   992 pts/0    S+   18:47   0:00 grep --color=auto nginx
   

其實我說的一個進程指的是只有一個進程是受docker控制的,其它進程雖然也在運行,但是他們不受docker的控制,它們都是野進程,如果主的掛了,其它的都得跟著玩完。這也是為什么在編寫Dockerfile的時候,CMD中的命令不能后臺運行的原因,簡單來說,docker僅在它的1號進程(PID為1)運行時,會保持運行。如果1號進程退出了,Docker容器也就退出了。這個問題也是新手或者沒有從事過docker相關(guān)開發(fā)的同學(xué)經(jīng)常碰到的問題,我的容器剛剛啟動,怎么就exit了呢?因為它需要一個前臺進程把它hang住。比如在執(zhí)行nginx命令的時候,我們會使用ENTRYPOINT [ "/usr/sbin/nginx", "-g", "daemon off;" ]

容器單進程并不是指容器里只能運行"一個"進程而是指容器沒有管理多進程的能力。這是因為容器里PID=1的進程就是應(yīng)用本身,其他的進程都是PID=1進程的子進程。

再說了,Pod是k8s調(diào)度的最小單位,為什么不能是容器,而需要搞出一個Pod的概念?因為容器單進程模式,而Pod則是進程組。通過進程組的概念,Pod能夠把容器 "有原則的" 組織到一起運行,從而能夠進行每個容器的管理。而k8s需要做的工作就是將 "進程組" 的概念映射到容器技術(shù)中。

docker容器底層技術(shù)怎么實現(xiàn)    

容器技術(shù)深入理解

其實docker的核心技術(shù)可以總結(jié)為:為待創(chuàng)建進程的容器開啟namespace配置、指定Cgroup參數(shù)、切換容器根目錄。本質(zhì)上來說也就是運行在宿主機上的普通進程而已。

表示不服,容器技術(shù)從誕生至今一直反復(fù)強調(diào)的特性就是一致性,你這說的和普通進程沒什么區(qū)別,如何保證一致性?答案很簡單,docker鏡像不僅能夠打包應(yīng)用,還能打包整個操作系統(tǒng)的文件和目錄,記住是操作系統(tǒng)的文件和目錄。通過這種方式docker就把一個應(yīng)用所有的依賴庫包括操作系統(tǒng)中的文件和目錄都被打包到鏡像中。docker正是通過打包操作系統(tǒng)級別的方式,解決了開發(fā)到線上環(huán)境的一致性。

搞明白容器的本質(zhì)之后,你就可以解決很多現(xiàn)實問題,比如:我有一個老項目,兩個服務(wù)之間是緊密耦合的,如果按照k8s中Pod的編排思想,改動成本非常高。這個時候,就可以考慮把這個兩個服務(wù)打包到一個鏡像中,并且其中一個進程作為主進程啟動,另外一個后臺運行。但后臺運行的進程就需要你自己管理了,說白了,服務(wù)掛了也沒人知道。這也是為什么說k8s Pod能夠把多個緊密關(guān)聯(lián)的進程有組織的管理在一起的原因。

說了半天,容器就是運行在宿主機上的一個資源被限制、視圖被隔離的進程;那一個宿主機操作系統(tǒng)只有一個內(nèi)核,也就是說,所有的容器都依賴這一個內(nèi)核了?比如我現(xiàn)在有一個需求,我的兩個容器運行在同一臺宿主機上,但是依賴的內(nèi)核版本不一樣,或者需要配置的內(nèi)核參數(shù)不一樣,怎么解決呢?解決不了,這也是容器化技術(shù)相比于虛擬機的主要缺陷之一。

說好的打包操作系統(tǒng)呢?

網(wǎng)上搜索下,到處充斥著docker能夠打包操作系統(tǒng)的言論,這句話其實是不準確的,而且容易讓人誤解docker的能力。下面先來看一組概念內(nèi)核,操作系統(tǒng)和發(fā)行版之間的區(qū)別。

  • Linux內(nèi)核是Linux操作系統(tǒng)的核心部分。這就是Linus最初寫的。

  • Linux操作系統(tǒng)是內(nèi)核和用戶域(庫,GNU實用程序,配置文件等)的組合。

  • Linux發(fā)行版是Linux操作系統(tǒng)的特定版本,例如Debian,CentOS或Alpine。

大多數(shù)在編寫Dockerfile時都會顯式或隱式地依賴于運行在容器中的某種Linux操作系統(tǒng)的特定發(fā)行版本,比如:

$ cat <<EOF > Dockerfile
FROM alpine:3.7
RUN apk add --no-cache mysql-client
ENTRYPOINT ["mysql"]
EOF

$ docker build -t mysql-alpine .
$ docker run mysql-alpine
 

對于剛剛開始學(xué)習(xí)容器技術(shù)的同學(xué)來說,這可能導(dǎo)致一種錯誤的印象,docker是操作系統(tǒng)級別的隔離,而且總是基于眾所周知的和廣泛分布的Linux發(fā)行版本debian,centos或alpine等。結(jié)合上面所說的docker容器啟動后,只是運行在宿主機上的一個進程,理所當(dāng)然依賴于宿主機的內(nèi)核。這里又打包了一個完整的操作系統(tǒng),怎么回事呢?

其實linux操作系統(tǒng)中代碼包含兩部分,一部分是文件目錄和配置,另外一部分是內(nèi)核,這兩部分是分開存放的,系統(tǒng)只有在宿主機開機啟動時才會加載內(nèi)核模塊。說白了,即使鏡像中包含了內(nèi)核也不會被加載。說到最后,原來鏡像只是包含了操作系統(tǒng)的軀干(文件系統(tǒng)),并沒有包含操作系統(tǒng)的靈魂(內(nèi)核)。

“docker容器底層技術(shù)怎么實現(xiàn)”的內(nèi)容就介紹到這里了,感謝大家的閱讀。如果想了解更多行業(yè)相關(guān)的知識可以關(guān)注億速云網(wǎng)站,小編將為大家輸出更多高質(zhì)量的實用文章!

向AI問一下細節(jié)

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

AI