深入理解容器基礎(chǔ)概念

容器技術(shù)近年來越來越火,作為云原生技術(shù)的最底層基石,要開發(fā)云原生應(yīng)用,就有必要對于容器技術(shù)有一個更加深入的了解。容器的概念特別多,docker、oci、cri、runc、containerd名字容易看暈,這邊做一下總結(jié)

Container

首先先來了解一下,什么是容器?這邊我們一般說的“容器”,都是“Linux容器”(當然現(xiàn)在微軟也在搞容器,但還沒linux上面那么成熟)。不同于一般認識,其實容器本身并不是一個特別新的技術(shù),早在2000年就已經(jīng)有了,當時是用來在chroot環(huán)境(隔離mount namespac的工具)中做進程隔離(使用namespac和cgroups),容器的歷史可以看這篇文章。而現(xiàn)在docker所用的容器技術(shù),和當時并沒有本質(zhì)上的區(qū)別。容器的本質(zhì),一句話解釋,就是一組受到資源限制,彼此間相互隔離的進程。實現(xiàn)起來也并不復(fù)雜,隔離所用到的技術(shù)都是由linux內(nèi)核本身提供的(所以說目前絕大部分的容器都是必須要跑在linux里面的)。其中namespace用來做訪問隔離(每個容器進程都有自己獨立的進程空間,看不到其他進程),cgroups用來做資源限制(cpu、內(nèi)存、存儲、網(wǎng)絡(luò)的使用限制)??偟膩碚f容器就是一種基于操作系統(tǒng)能力的隔離技術(shù),這和基于hypervisor的虛擬化技術(shù)(能完整模擬出虛擬硬件和客戶機操作系統(tǒng))復(fù)雜度不可同日而語。這邊是一個對比圖

image

可以看出,容器是沒有自己的OS的,直接共享宿主機的內(nèi)核,也沒有hypervisor這一層進行資源隔離和限制,所有對于容器進程的限制都是基于操作系統(tǒng)本身的能力來進行的,由此容器獲得了一個很大的優(yōu)勢:輕量化,由于沒有hypervisor這一層,也沒有自己的操作系統(tǒng),自然占用資源很小,而打出來的鏡像文件也要比虛擬機小的多。對于虛擬機和容器的區(qū)別,劉超老師有一個很形象的比喻:虛擬機好比房子,容器好比衣服。衣服是跟著人的,人站起來了,衣服也跟著起來,人躺下了,衣服也躺下了,而房子永遠在那里,不管人是躺著還是站著。所以說基于容器的技術(shù)原理,它天生對應(yīng)用友好,輕量化,又具備了一定的隔離性,大火也就不奇怪了。

了解了容器的技術(shù)原理,接下來就可以說說容器的那些名詞概念了

OCI

Open Container Initiative,是由多家公司共同成立的項目,并由linux基金會進行管理,致力于container runtime的標準的制定和runc的開發(fā)等工作。所謂container runtime,主要負責的是容器的生命周期的管理。oci的runtime spec標準中對于容器的狀態(tài)描述,以及對于容器的創(chuàng)建、刪除、查看等操作進行了定義。

runC

是對于OCI標準的一個參考實現(xiàn),是一個可以用于創(chuàng)建和運行容器的CLI(command-line interface)工具。runc直接與容器所依賴的cgroup/linux kernel等進行交互,負責為容器配置cgroup/namespace等啟動容器所需的環(huán)境,創(chuàng)建啟動容器的相關(guān)進程。runC基本上就是一個命令行小工具,它可以不用通過Docker引擎,直接就可以創(chuàng)建容器。這是一個獨立的二進制文件,使用OCI容器就可以運行它。

containerd

containerd 是一個守護進程,它可以使用runC管理容器,并使用gRPC暴露容器的其他功能。相比較Docker引擎,使用 gRPC ,containerd暴露出針對容器的增刪改查的接口,Docker engine調(diào)用這些接口完成對于容器的操作。

Docker架構(gòu)

docker在早期所有功能都是做在docker engine里面的,但是之后功能越來越多,越來越重,很多功能已經(jīng)和基礎(chǔ)的容器運行時沒有關(guān)系了(比如swarm項目)。所以為了響應(yīng)社區(qū)的呼聲,也為了兼容oci標準,docker也做了架構(gòu)調(diào)整。將容器運行時相關(guān)的程序從docker daemon剝離出來,形成了containerd。Containerd向docker提供運行容器的API,二者通過grpc進行交互。containerd最后會通過runc來實際運行容器。調(diào)整完后的docker架構(gòu)圖如下(docker 1.12版本以后):

image

其中containerd-shim稱之為墊片,它使用runC命令行工具完成容器的啟動、停止以及容器運行狀態(tài)的監(jiān)控。containerd-shim進程由containerd進程拉起,并持續(xù)存在到容器實例進程退出為止(和容器進程同生命周期)。這種設(shè)計的優(yōu)點是,只要是符合OCI規(guī)范的容器,都可以通過containerd-shim來進行調(diào)用(比如kata-runtime)
執(zhí)行ps -ef|grep docker,可以看到當前正在運行的docker進程

[root@localhost ~]# ps -ef|grep docker
root      1431     1  1  2018 ?        10:35:01 /usr/bin/dockerd --bip=10.1.100.1/24 --ip-masq=true --mtu=1472
root      1498  1431  0  2018 ?        01:23:31 docker-containerd -l unix:///var/run/docker/libcontainerd/docker-containerd.sock --metrics-interval=0 --start-timeout 2m --state-dir /var/run/docker/libcontainerd/containerd --shim docker-containerd-shim --runtime docker-runc
root      1802  1431  0  2018 ?        00:00:03 /usr/bin/docker-proxy -proto tcp -host-ip 0.0.0.0 -host-port 4567 -container-ip 10.1.100.2 -container-port 4567
root      1820  1431  0  2018 ?        00:00:03 /usr/bin/docker-proxy -proto tcp -host-ip 0.0.0.0 -host-port 443 -container-ip 10.1.100.2 -container-port 443
root      1848  1498  0  2018 ?        00:00:07 docker-containerd-shim 2abb8ab1515e9dd491fc6e7d747e6ec8cdff3e98bcb6ae67c9b90ddfa120f1ed /var/run/docker/libcontainerd/2abb8ab1515e9dd491fc6e7d747e6ec8cdff3e98bcb6ae67c9b90ddfa120f1ed docker-runc
root      1852  1431  0  2018 ?        00:13:47 /usr/bin/docker-proxy -proto tcp -host-ip 0.0.0.0 -host-port 80 -container-ip 10.1.100.2 -container-port 80
root      1869  1431  0  2018 ?        00:00:03 /usr/bin/docker-proxy -proto tcp -host-ip 0.0.0.0 -host-port 10022 -container-ip 10.1.100.2 -container-port 22
root      1886  1498  0  2018 ?        01:24:27 docker-containerd-shim dd06d2cc632f45af1c53cd8df219c6275862bd94fed811bd3331290f8cf4a9a7 /var/run/docker/libcontainerd/dd06d2cc632f45af1c53cd8df219c6275862bd94fed811bd3331290f8cf4a9a7 docker-runc
root     15443 30672  0 13:08 pts/0    00:00:00 grep --color=auto docker

從上圖可以看出,dockerddocker-containerd、docker-containerd-shim分別對應(yīng)上述架構(gòu)圖中的docker daemon、containerd、containerd-shim,在這邊我啟動了兩個docker容器,所以會有兩個docker-containerd-shim進程。docker-runc就是docker-containerd-shim調(diào)用的真正來創(chuàng)建容器的模塊。

總結(jié)一下,其實docker總的架構(gòu)來說,真正用來創(chuàng)建容器的就是runC,其他的都是一些容器的管理和增強功能,所以說你如果想創(chuàng)建一個容器玩一下,直接下載一個runC的二進制跑一下就行了,當然生產(chǎn)上面不能這么搞。

CRI

kubernetes在初期版本里,就對多個容器引擎做了兼容,因此可以使用docker、rkt對容器進行管理。以docker為例,kubelet中會啟動一個docker manager,通過直接調(diào)用docker的api進行容器的創(chuàng)建等操作。

kubelet做適配的問題,就是容器項目每次升級更新,kubelet都需要相應(yīng)的進行配合變更測試,很多api可能這一版能用,下一版就不能用了,由于容器項目一直在高速迭代,k8項目組苦不堪言。痛定思痛后,sig-node項目組在k8s 1.5版本之后,推出了自己的運行時接口api--CRI(container runtime interface)。cri接口的推出,隔離了各個容器引擎之間的差異,而通過統(tǒng)一的接口與各個容器引擎之間進行互動。

與oci不同,cri與kubernetes的概念更加貼合,并緊密綁定。cri不僅定義了容器的生命周期的管理,還引入了k8s中pod的概念,并定義了管理pod的生命周期。在kubernetes中,pod是由一組進行了資源限制的,在隔離環(huán)境中的容器組成。而這個隔離環(huán)境,稱之為PodSandbox。在cri開始之初,主要是支持docker和rkt兩種。其中kubelet是通過cri接口,調(diào)用docker-shim,并進一步調(diào)用docker api實現(xiàn)的。

如上文所述,docker獨立出來了containerd。kubernetes也順應(yīng)潮流,孵化了cri-containerd項目,用以將containerd接入到cri的標準中。

CRI-O

為了進一步與oci進行兼容,kubernetes還孵化了cri-o,成為了架設(shè)在cri和oci之間的一座橋梁。通過這種方式,可以方便更多符合oci標準的容器運行時,接入kubernetes進行集成使用。可以預(yù)見到,通過cri-o,kubernetes在使用的兼容性和廣泛性上將會得到進一步加強。

Kubernetes架構(gòu)

cri.png

看到這張圖可能大家都暈了,其實這也反應(yīng)了容器及容器編排技術(shù)高速發(fā)展的現(xiàn)狀,K8的容器接入方案分別經(jīng)歷了四個階段(從右往左):

1.最早是在kubelet這一層進行適配,通過啟動docker-manager來訪問docker(不同的容器產(chǎn)品有不同的manager,這部分代碼是kubelet項目標準代碼的一部分)

2.K8 1.5之后引入了CRI接口,通過docker-shim(墊片)的方式接入docker。shim程序一般由容器廠商根據(jù)CRI規(guī)范自己開發(fā),實現(xiàn)方式可以自己定義(即CRI規(guī)范定義了要做什么,怎么做可以基于自己的理解)。而docker-shim由于歷史原因,還是k8項目組來做的,這部分代碼也包含在kubelet代碼里面,但架構(gòu)上是分開的。

3.docker在分出containerd后,k8也順應(yīng)潮流,孵化了cri-containerd項目,用于和containerd對接,這樣就不走docker daemon了。

4.目前孵化的cri-o項目,則連containerd都繞過了,直接使用runC去創(chuàng)建容器(你可以把cri-o看作是k8生態(tài)里面的containerd)

值得注意的是,在containerd的1.1版本中,甚至已經(jīng)去除了cri-containerd這樣一個守護進程,cri接口以插件的形式直接整合在了containerd項目里面,目前docker和kubernetes分別調(diào)用containerd的架構(gòu)圖如下:


containerd.png

容器項目發(fā)展趨勢

可以看到,隨著k8生態(tài)的不斷成熟和業(yè)界影響力的不斷增大,k8項目對于docker的依賴已經(jīng)越來越少,從cri-containerd開始就已經(jīng)可以脫離docker體系,到cri-o更是連docker的影子都看不到了(containerd項目主要還是docker在維護)。而現(xiàn)在還有crictl這樣的工具,連容器的日常維護都不需要使用docker命令了。Docker inc.基于自身的商業(yè)訴求,也是不斷再往平臺化發(fā)展(swarm項目),也在不斷添加復(fù)雜的功能,可惜憑一己之力還是很難和谷歌一手搭建出來的CNCF的宏偉藍圖去抗爭。

目前在CNCF里面有兩個容器運行時項目,分別是rktcontainerd。rkt從目前的發(fā)展情況看很有可能被移出CNCF,cri-o和containerd都在同時發(fā)展,這兩個項目其實重合度是比較高的,做的事情也差不多,只不過cri-o是專門為k8s設(shè)計的,而containerd設(shè)計之初的定義就是一個通用的容器運行時平臺,有說containerd即將通過委員會評審,從CNCF中畢業(yè)。

安全容器

最后討論一個比較前沿的話題,叫做“安全容器”。根據(jù)前面的介紹,相信你也了解了,容器有諸多好處,但也并不是完美的。它有個很大的軟肋--隔離性?;趦?nèi)核提供的namespace功能,其實很多東西還是無法隔離的,一個簡單的例子就是時間,一旦在某個容器內(nèi)修改了系統(tǒng)時間,所有運行在這個宿主機上的容器內(nèi)的時間都會改變,這顯然不符合“沙盒”原則。再比如容器里面的jvm,如果不修改內(nèi)核代碼的話,看到的都是宿主機的cpu和內(nèi)存情況。而更加嚴重的問題是,由于共享宿主機內(nèi)核,一旦某個容器被植入惡意代碼,攻擊宿主機內(nèi)核,會影響到該宿主機上的所有容器。而這個問題在虛擬機時代是不存在的,因為虛擬機都是獨立操作系統(tǒng)和內(nèi)核,里面可以隨便你折騰。目前所有的公有云,還都是使用虛擬機進行多租戶管理,安全性是一個很重要的原因。

基于上述情況,很容易就能想到,是否有一種技術(shù),既可以擁有容器的速度,還可以擁有虛擬機的隔離性呢?你別說,還真有人在研究這個,而且已經(jīng)有了幾個有一定成熟度的項目,比如kata container和gvisor。

kata containers是由OpenStack基金會管理,但獨立于OpenStack項目之外的容器項目。kata containers整合了Intel的 Clear Containers 和 國內(nèi)HyperHQ團隊 的 runV項目,它的本質(zhì)是在容器中建立一個經(jīng)過裁剪的,輕量化的內(nèi)核,所以在你啟動一個kata container后,你就能看到一個正常的虛擬機在運行,而Qemu就是這個虛擬機的VMM(虛擬機管理程序)。作為標準的虛擬機,kata container自然原生就帶了pod的概念,一個虛擬機就是一個pod,而用戶定義的容器,就是這個pod里面的進程。這邊是kata container的一個架構(gòu)圖:


kata.png

從這個架構(gòu)圖可以看到,kata-runtime是和runc平級的,而kata container是完全按照OCI規(guī)范來進行設(shè)計的。大家不難想到,根據(jù)前面的介紹,containerd可以直接通過containerd-shim來對kata-runtime進行調(diào)用,所以對于docker來說,完全可以通過原來的方式創(chuàng)建kata容器,管理的方式也都和原來一樣。而你也不難想到,k8自然也是可以非常方便的創(chuàng)建和管理kata container容器(通過docker-shim、cri-containerd或者cri-o)。

可以看到,kata container項目基本還是走的傳統(tǒng)虛擬機的路子,通過裁剪出一個精簡的guest kernel(這個內(nèi)核是經(jīng)過高度優(yōu)化的,只用于一個容器的運行),以及通過hypervisor(QEMU)虛擬出來的硬件設(shè)備,提供一個完整的虛擬機環(huán)境。相對而言,gVisor設(shè)計更加激進,gVisor的設(shè)計中有個一個sentry進程,負責轉(zhuǎn)發(fā)應(yīng)用對于內(nèi)核各類功能的調(diào)用,簡單說,就是對應(yīng)用“冒充”內(nèi)核的系統(tǒng)組件,在這種思想下,不難理解,sentry需要自己實現(xiàn)一個完成的linux內(nèi)核的網(wǎng)絡(luò)棧,以便于處理應(yīng)用進程間的通訊請求。目前gVisor還處于早期階段,能調(diào)用的內(nèi)核功能還相當有限,并且在重I/O或者重網(wǎng)絡(luò)的情況下性能會急劇下降。但這種通過用戶態(tài)去運行一個操作系統(tǒng)內(nèi)核,來為應(yīng)用進程提供強隔離的思路,確實是未來安全容器進一步演化的一個方向。

就目前來說,我更加看好kata container的發(fā)展。一方面gVisor這種“冒充內(nèi)核組件”的方式雖思路很好,但還不夠成熟,功能和性能各方面還有限制,另外更重要的是,gVisor本質(zhì)上不是內(nèi)核,它所有的調(diào)用還是要依賴于宿主機內(nèi)核的能力,而kata container是一個獨立內(nèi)核,這可以讓kata起來的內(nèi)核版本不同于宿主機的內(nèi)核,提供真正虛擬機級別的隔離性,對于cilium這類對于內(nèi)核版本要求非常高的項目具有非常重大的意義。其實目前業(yè)界其實已有這方面的試水,華為云的CCI(云容器實例)明確提到了是基于kata container的安全容器技術(shù),阿里也推出了ECI(彈性容器實例,是不是基于kata不確定),應(yīng)該說安全容器的發(fā)展前景還是非常良好的。

kata container與service mesh

這兩個一個是基于虛擬化技術(shù)的容器運行時,一個是微服務(wù)治理框架,有什么關(guān)系呢?先來看一下下面這個圖

image

這是一個典型的service mesh的架構(gòu)圖,service 和sidecar分別部署為獨立的進程,所有的服務(wù)治理邏輯諸如服務(wù)發(fā)現(xiàn)、服務(wù)注冊、負載、限流/熔斷/降級、分布式跟蹤、灰度等功能都放在sidecar里面實現(xiàn),由服務(wù)網(wǎng)格統(tǒng)一管理所有的sidecar,應(yīng)用無感知。這就是所謂的服務(wù)治理下沉到基礎(chǔ)設(shè)施,這也是service mesh的核心理念。

service mesh理念很好,真正實現(xiàn)起來難度卻很大。究其原因,sidecar仍然是一個用戶態(tài)的進程,proxy攔截了所有進出service的流量,iptables本身性能就不行,對于服務(wù)調(diào)用來說又多了幾跳,用戶態(tài)的上下文切換,性能必然會有損失,事實上istio的性能問題至今一直為人詬病,也不能大規(guī)模使用于生產(chǎn)環(huán)境。為了解決這個問題,也誕生了諸如cilium這樣的項目,直接繞過內(nèi)核的tcp堆棧來提高性能。而安全容器項目,為這個問題的解決提供了一個新的思路,因為kata container本身就是一個精簡的guest kernel,那為何不把這部分服務(wù)治理邏輯直接下沉到guest kernel中,作為內(nèi)核網(wǎng)絡(luò)協(xié)議棧的一部分,真正的成為基礎(chǔ)設(shè)施。這樣只要基于虛擬化的容器啟動,自動就具有了服務(wù)治理的全部功能,而且是內(nèi)核級別的,應(yīng)用完全無感知。之前小劍老師分享的service mesh介紹中,有這么一張PPT

image

當時小劍的結(jié)論是把服務(wù)治理這一層加入內(nèi)核的網(wǎng)絡(luò)協(xié)議棧是最理想的,但是實現(xiàn)起來不現(xiàn)實。而kata container里面運行的是一個真正的內(nèi)核(哪怕是精簡的),要定制一些功能相對沒那么難,此外基于內(nèi)核態(tài)還可以做很多用戶態(tài)做不了的事情。當然這里面還有很多工作要做,但無疑虛擬化的容器項目無疑給我們打開了新世界的大門。

最后編輯于
?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請聯(lián)系作者
平臺聲明:文章內(nèi)容(如有圖片或視頻亦包括在內(nèi))由作者上傳并發(fā)布,文章內(nèi)容僅代表作者本人觀點,簡書系信息發(fā)布平臺,僅提供信息存儲服務(wù)。
  • 序言:七十年代末,一起剝皮案震驚了整個濱河市,隨后出現(xiàn)的幾起案子,更是在濱河造成了極大的恐慌,老刑警劉巖,帶你破解...
    沈念sama閱讀 230,501評論 6 544
  • 序言:濱河連續(xù)發(fā)生了三起死亡事件,死亡現(xiàn)場離奇詭異,居然都是意外死亡,警方通過查閱死者的電腦和手機,發(fā)現(xiàn)死者居然都...
    沈念sama閱讀 99,673評論 3 429
  • 文/潘曉璐 我一進店門,熙熙樓的掌柜王于貴愁眉苦臉地迎上來,“玉大人,你說我怎么就攤上這事。” “怎么了?”我有些...
    開封第一講書人閱讀 178,610評論 0 383
  • 文/不壞的土叔 我叫張陵,是天一觀的道長。 經(jīng)常有香客問我,道長,這世上最難降的妖魔是什么? 我笑而不...
    開封第一講書人閱讀 63,939評論 1 318
  • 正文 為了忘掉前任,我火速辦了婚禮,結(jié)果婚禮上,老公的妹妹穿的比我還像新娘。我一直安慰自己,他們只是感情好,可當我...
    茶點故事閱讀 72,668評論 6 412
  • 文/花漫 我一把揭開白布。 她就那樣靜靜地躺著,像睡著了一般。 火紅的嫁衣襯著肌膚如雪。 梳的紋絲不亂的頭發(fā)上,一...
    開封第一講書人閱讀 56,004評論 1 329
  • 那天,我揣著相機與錄音,去河邊找鬼。 笑死,一個胖子當著我的面吹牛,可吹牛的內(nèi)容都是我干的。 我是一名探鬼主播,決...
    沈念sama閱讀 44,001評論 3 449
  • 文/蒼蘭香墨 我猛地睜開眼,長吁一口氣:“原來是場噩夢啊……” “哼!你這毒婦竟也來了?” 一聲冷哼從身側(cè)響起,我...
    開封第一講書人閱讀 43,173評論 0 290
  • 序言:老撾萬榮一對情侶失蹤,失蹤者是張志新(化名)和其女友劉穎,沒想到半個月后,有當?shù)厝嗽跇淞掷锇l(fā)現(xiàn)了一具尸體,經(jīng)...
    沈念sama閱讀 49,705評論 1 336
  • 正文 獨居荒郊野嶺守林人離奇死亡,尸身上長有42處帶血的膿包…… 初始之章·張勛 以下內(nèi)容為張勛視角 年9月15日...
    茶點故事閱讀 41,426評論 3 359
  • 正文 我和宋清朗相戀三年,在試婚紗的時候發(fā)現(xiàn)自己被綠了。 大學時的朋友給我發(fā)了我未婚夫和他白月光在一起吃飯的照片。...
    茶點故事閱讀 43,656評論 1 374
  • 序言:一個原本活蹦亂跳的男人離奇死亡,死狀恐怖,靈堂內(nèi)的尸體忽然破棺而出,到底是詐尸還是另有隱情,我是刑警寧澤,帶...
    沈念sama閱讀 39,139評論 5 364
  • 正文 年R本政府宣布,位于F島的核電站,受9級特大地震影響,放射性物質(zhì)發(fā)生泄漏。R本人自食惡果不足惜,卻給世界環(huán)境...
    茶點故事閱讀 44,833評論 3 350
  • 文/蒙蒙 一、第九天 我趴在偏房一處隱蔽的房頂上張望。 院中可真熱鬧,春花似錦、人聲如沸。這莊子的主人今日做“春日...
    開封第一講書人閱讀 35,247評論 0 28
  • 文/蒼蘭香墨 我抬頭看了看天上的太陽。三九已至,卻和暖如春,著一層夾襖步出監(jiān)牢的瞬間,已是汗流浹背。 一陣腳步聲響...
    開封第一講書人閱讀 36,580評論 1 295
  • 我被黑心中介騙來泰國打工, 沒想到剛下飛機就差點兒被人妖公主榨干…… 1. 我叫王不留,地道東北人。 一個月前我還...
    沈念sama閱讀 52,371評論 3 400
  • 正文 我出身青樓,卻偏偏與公主長得像,于是被迫代替她去往敵國和親。 傳聞我的和親對象是個殘疾皇子,可洞房花燭夜當晚...
    茶點故事閱讀 48,621評論 2 380

推薦閱讀更多精彩內(nèi)容

  • 導(dǎo)讀 接觸kubernetes的時候, 搞不懂OCI,CRI,runC,containerd,shim 之間的區(qū)別...
    allenhaozi閱讀 7,242評論 2 7
  • Moby(Docker)社區(qū) Docker在17年4月的時候推出了名為Moby項目,Moby著眼于“一個將組件裝配...
    marshalzxy閱讀 1,788評論 1 3
  • 從chroot,control groups,lxc,warden,一路走到如今的docker、rocket、wi...
    yiduyangyi閱讀 2,547評論 0 5
  • 每一天的開始, 你擁有這樣的一種資源。 有目標的人, 感嘆資源不夠用, 沒有目標的人, 感嘆資源來得太多。
    小劇在成長閱讀 209評論 0 3
  • 舊時明月何其多, 湖里河間塞滿籮。 墨客文人輕甩筆, 滿街落座盡嫦娥!
    云逸1108閱讀 114評論 0 2