基于Kubernetes的容器云平臺(tái)實(shí)戰(zhàn)》——2.2 容器生命周期管理">《基于Kubernetes的容器云平臺(tái)實(shí)戰(zhàn)》——2.2 容器生命周期管理
664
2025-03-31
1.4.2 Docker原理
Docker是基于操作系統(tǒng)虛擬化技術(shù)實(shí)現(xiàn)的,這一點(diǎn)與基于硬件虛擬化的各種虛擬機(jī)產(chǎn)品有很大不同,但是兩者所要解決的問(wèn)題在很多方面卻有相似之處,比如,都希望為應(yīng)用提供一個(gè)虛擬、完整和獨(dú)占的運(yùn)行環(huán)境,都希望能夠提高這些虛擬環(huán)境之間的隔離度,也都希望能夠從管理的角度對(duì)這些虛擬環(huán)境占用的宿主機(jī)資源進(jìn)行方便的管控。在解釋為何使用Docker的時(shí)候已經(jīng)提到,Docker解決這些問(wèn)題的途徑是在共享宿主機(jī)內(nèi)核的基礎(chǔ)上包裝內(nèi)核提供的一系列API。具體到Linux操作系統(tǒng)上,內(nèi)核所提供的相關(guān)API涉及很多方面,其中被大家關(guān)注得最多也是最主要的是CGroup和namespace。另外,在實(shí)現(xiàn)分層鏡像和容器的根文件系統(tǒng)視圖時(shí),Docker使用了與虛擬文件系統(tǒng)相關(guān)的掛載和綁定掛載API,這些都不是新內(nèi)容,只是Docker這類容器化產(chǎn)品將它們進(jìn)行包裝并推動(dòng)了操作系統(tǒng)已有虛擬化能力的大眾化而已。
下面就對(duì)這幾個(gè)Docker中應(yīng)用到的主要技術(shù)分別進(jìn)行簡(jiǎn)單的介紹。
CGroup是Control Group的縮寫,它是Linux中的特有功能,首先由Google公司提交的內(nèi)核補(bǔ)丁實(shí)現(xiàn)。顧名思義,這個(gè)功能與控制、分組有關(guān)。其實(shí),如果單從功能角度來(lái)看的話,也許叫做Group Control更好一些。這主要是因?yàn)樵摴δ艿暮诵脑谟趯?duì)進(jìn)程進(jìn)行層次化分組,并能夠以每個(gè)組的粒度實(shí)現(xiàn)諸如資源限制和策略控制功能,而這正是前面提到的虛擬化目標(biāo)的基礎(chǔ)。每一個(gè)虛擬環(huán)境(或者稱之為“容器”)中的應(yīng)用進(jìn)程,以及后續(xù)加入該環(huán)境中的其他進(jìn)程都應(yīng)該受到同樣的策略管控,這是很容易理解的;但是在沒有這個(gè)基礎(chǔ)設(shè)施之前,單從已有的操作系統(tǒng)功能上看是無(wú)法實(shí)現(xiàn)的。而有了這種分層的分組功能之后,不僅是容器運(yùn)行時(shí),包括系統(tǒng)管理員,也可以方便地實(shí)現(xiàn)對(duì)容器中進(jìn)程占用的CPU、內(nèi)存等資源的限制。而這種控制功能,在CGroup中是由很多控制器來(lái)完成的,主要的控制器包括blkio、cpu、cpuacct、cpuset、devices、freezer、hugetlb、memory、net_cls、net_prio和perf_event等。
這些控制器和不同的進(jìn)程組之間的關(guān)系在第一個(gè)版本的CGroup實(shí)現(xiàn)中是很靈活的。每個(gè)控制器可以對(duì)應(yīng)到單獨(dú)的一個(gè)組,以及由該組的子組所構(gòu)成的所謂“層次結(jié)構(gòu)”。這也是目前Docker所支持的實(shí)現(xiàn)方式。但是這種實(shí)現(xiàn)被認(rèn)為過(guò)于復(fù)雜,帶來(lái)了很多技術(shù)上的障礙,因此在第二個(gè)版本的實(shí)現(xiàn)中將這種“層次結(jié)構(gòu)”限定為只有一個(gè)。但是版本二的CGroup功能直到在4.15版本內(nèi)核中才完整實(shí)現(xiàn),目前可能還不成熟。
不管是哪一個(gè)版本的CGroup實(shí)現(xiàn),對(duì)進(jìn)程分組的控制都是通過(guò)一個(gè)虛擬文件系統(tǒng)下的目錄節(jié)點(diǎn)和其中的節(jié)點(diǎn)文件來(lái)實(shí)現(xiàn)的,而各種控制器功能也是通過(guò)一些節(jié)點(diǎn)文件來(lái)實(shí)現(xiàn)。整個(gè)CGroup功能模塊的對(duì)外接口就是通過(guò)這個(gè)虛擬文件系統(tǒng)來(lái)暴露。在使用了systemd作為init的Linux系統(tǒng)上,這個(gè)CGroup虛擬文件系統(tǒng)的掛接點(diǎn)路徑為/sys/fs/cgroup。在下面的目錄列表中,cpu和cpuacct是指向“cpu,cpuacct”的符號(hào)鏈接,systemd目錄節(jié)點(diǎn)是systemd自己創(chuàng)建的一個(gè)“層次結(jié)構(gòu)”,與任何控制器無(wú)關(guān),只利用到CGroup核心的進(jìn)程分組管理功能。其他目錄節(jié)點(diǎn)和其下的子節(jié)點(diǎn)基本上每個(gè)都對(duì)應(yīng)著一種控制器。下面是systemd管理下默認(rèn)的CGroup層次結(jié)構(gòu)的根列表。
# ls -p /sys/fs/cgroup
blkio/? cpu? cpuacct? cpu,cpuacct/? cpuset/? devices/? freezer/? hugetlb/? memory/? net_cls/? perf_event/? systemd/
默認(rèn)情況下,Docker在這每個(gè)層次結(jié)構(gòu)目錄下都創(chuàng)建了自己的節(jié)點(diǎn)子目錄,然后再為每個(gè)容器創(chuàng)建以容器ID為名稱的節(jié)點(diǎn)目錄,將所有容器相關(guān)的進(jìn)程都管理在這個(gè)“層次結(jié)構(gòu)”中。比如devices控制器是用來(lái)限定進(jìn)程組對(duì)設(shè)備文件的訪問(wèn)權(quán)限的,它對(duì)應(yīng)的層次結(jié)構(gòu)的頂層節(jié)點(diǎn)文件列表如下:
# ls -p /sys/fs/cgroup/devices
cgroup.clone_children? cgroup.procs? devices.allow? devices.list? devices.deny release_agent? notify_on_release? cgroup.event_control? cgroup.sane_behavior? tasks docker/? system.slice/? user.slice/
其中與device控制器相關(guān)的節(jié)點(diǎn)文件以“devices.”開頭,如devices.allow和devices.deny,按照一定格式寫入設(shè)備號(hào)和權(quán)限控制串就能夠?qū)崿F(xiàn)設(shè)備訪問(wèn)控制,Docker中是以白名單方式來(lái)完成控制的。其他幾個(gè)文件和CGroup的進(jìn)程組管理功能有關(guān):tasks,可以向其寫入線程ID,將此線程納入該層次結(jié)構(gòu)內(nèi);cgroup.procs,可以向其寫入線程組ID,將線程組納入層次結(jié)構(gòu)內(nèi);notify_on_release,是控制當(dāng)前組銷毀時(shí)是否調(diào)用release_agent中登記的程序的開關(guān);release_agent,用于登記觸發(fā)程序,但是只有頂層才有此文件;cgroup.event_control,用于通過(guò)eventfd系統(tǒng)調(diào)用在用戶程序中得到控制器的事件通知;cgroup.clone_children,只用于cpuset控制器,控制子組是否在創(chuàng)建時(shí)復(fù)制父控制器的配置;cgroup.sane_behavior是一個(gè)過(guò)渡性文件,與是否啟用第二版CGroup功能有關(guān)。只要一個(gè)進(jìn)程被納入某個(gè)控制組,那么在后續(xù)的fork調(diào)用時(shí),新創(chuàng)建的進(jìn)程仍然在此控制組中,這樣就從進(jìn)程的角度確立了容器的邊界。
Docker在每個(gè)層次結(jié)構(gòu)中都創(chuàng)建了自己的節(jié)點(diǎn)目錄,該節(jié)點(diǎn)目錄下也有與頂層類似的節(jié)點(diǎn)文件,而每個(gè)容器在默認(rèn)情況下都有自己的子節(jié)點(diǎn)目錄,其下同樣有該層次的對(duì)應(yīng)節(jié)點(diǎn)文件。頂層中除了docker節(jié)點(diǎn)目錄外的另外兩個(gè)節(jié)點(diǎn)目錄是由systemd創(chuàng)建的,用于管理宿主機(jī)上的服務(wù)和用戶會(huì)話。
# ls -p /sys/fs/cgroup/devices/docker
b61e023569ba3a0.../? tasks cgroup.procs notify_on_release cgroup.event_control? devices.allow? devices.list? cgroup.clone_children? devices.deny
其他控制器與devices控制器一樣,也有自己的節(jié)點(diǎn)文件,限于篇幅,這里不再一一羅列,只簡(jiǎn)單說(shuō)明一下前面第一個(gè)列表中顯示出的各個(gè)控制器的主要功能:cpu,用于限制組中進(jìn)程的CPU使用量;cpuacct,用于對(duì)組中進(jìn)程的CPU使用進(jìn)行計(jì)量;cpuset,用于限定組中進(jìn)程可用的CPU和NUMA類型內(nèi)存節(jié)點(diǎn);memory,用于限定和報(bào)告組中進(jìn)程的內(nèi)存使用量;blkio,用于限制組中進(jìn)程對(duì)塊設(shè)備的I/O操作;freezer,用于掛起或者解凍組和子組中所有進(jìn)程;net_cls,用于設(shè)置組中進(jìn)程發(fā)送的網(wǎng)絡(luò)數(shù)據(jù)包的類別ID;net_prio,用于設(shè)置與該組相關(guān)網(wǎng)絡(luò)數(shù)據(jù)包的優(yōu)先級(jí);perf_event,用于控制是否對(duì)組中進(jìn)程執(zhí)行perf監(jiān)控;hugetlb,用于限制和報(bào)告組中進(jìn)程對(duì)大頁(yè)面的使用量。
從上面的介紹中可以看出,CGroup功能劃定了容器的進(jìn)程組邊界,并且也能夠執(zhí)行一定資源限制功能,但是組中的進(jìn)程仍然可以看到與宿主機(jī)上進(jìn)程相同的東西,也就是這些組之間還沒有相互“隔離”。能夠支持“隔離”功能的是內(nèi)核中的命名空間(namespace)特性。
已經(jīng)被Docker所利用的Linux內(nèi)核的命名空間特性包括:
1)PID namespace:每當(dāng)在此命名空間中啟動(dòng)一個(gè)程序,內(nèi)核就為其分配一個(gè)唯一的ID,它與從宿主機(jī)中所見的不同。每個(gè)容器中的進(jìn)程都有自己?jiǎn)为?dú)的進(jìn)程ID空間。
2)MNT namespace:每個(gè)容器都有自己的目錄掛載路徑的命名空間。
3)NET namespace:每個(gè)容器都有自己?jiǎn)为?dú)的網(wǎng)絡(luò)棧,其中的socket和網(wǎng)卡設(shè)備都是其他容器不能訪問(wèn)的。
4)UTS namespace:在此命名空間中的進(jìn)程擁有自己的主機(jī)名和NIS域名。
5)IPC namespace:只有在相同的IPC命名空間中的進(jìn)程才可以利用共享內(nèi)存、信號(hào)量和消息隊(duì)列相互通信。
6)User namespace:用戶命名空間被內(nèi)核用于隔離容器中用戶ID、組ID以及根目錄、key和capabilities,用戶還能通過(guò)配置來(lái)映射宿主機(jī)和容器中的用戶ID和組ID。
與CGroup的實(shí)現(xiàn)不同,該特性的實(shí)現(xiàn)不是通過(guò)虛擬文件系統(tǒng)接口,而是通過(guò)實(shí)際的系統(tǒng)調(diào)用完成的。與此特性相關(guān)的系統(tǒng)調(diào)用有三個(gè):clone(fork函數(shù)實(shí)際是通過(guò)該系統(tǒng)調(diào)用實(shí)現(xiàn)的),在創(chuàng)建進(jìn)程的同時(shí)根據(jù)參數(shù)中的標(biāo)記為其新建命名空間,而沒有新建標(biāo)記時(shí),子進(jìn)程自動(dòng)繼承父進(jìn)程的命名空間,這樣由命名空間構(gòu)建的沙箱邊界在應(yīng)用中得到保持;setns,用于加入一個(gè)已經(jīng)存在的命名空間;unshare,根據(jù)參數(shù)標(biāo)記為調(diào)用進(jìn)程新建命名空間,并將調(diào)用進(jìn)程加入此空間中。由這些系統(tǒng)調(diào)用創(chuàng)建出的命名空間構(gòu)成樹形結(jié)構(gòu),宿主機(jī)初始命名空間是根,新建的MNT和UTS命名空間復(fù)制了父命名空間的內(nèi)容。對(duì)于setns調(diào)用來(lái)說(shuō),無(wú)疑需要一個(gè)已經(jīng)存在的命名空間的標(biāo)識(shí),而這是通過(guò)打開/proc/
這些調(diào)用都是與進(jìn)程相關(guān)的,那么命名空間的生命周期是否完全與創(chuàng)建它的進(jìn)程綁定呢?其實(shí)只要將/proc/
上面提到的各種命名空間引入內(nèi)核的時(shí)間并不相同,其中User namespace不僅引入最遲,并且直到4.15版本內(nèi)核還在進(jìn)行較大功能改進(jìn)。該特性與安全控制相關(guān),不僅語(yǔ)義復(fù)雜,而且還需借助一些特殊機(jī)制來(lái)減少漏洞,如User ID和Group ID映射。在創(chuàng)建用戶命名空間時(shí)可以對(duì)/proc/
新建的網(wǎng)絡(luò)命名空間中除了loopback設(shè)備之外沒有任何網(wǎng)卡設(shè)備、路由表等資源,需要專門為其進(jìn)行配置。一個(gè)網(wǎng)卡設(shè)備只能歸屬于一個(gè)網(wǎng)絡(luò)命名空間,但是像veth這種虛擬網(wǎng)絡(luò)設(shè)備則可以提供類似于管道的功能,以溝通不同的網(wǎng)絡(luò)命名空間。
雖然新建的MNT命名空間自動(dòng)復(fù)制了父命名空間的全部?jī)?nèi)容,但是在容器創(chuàng)建過(guò)程中,容器運(yùn)行時(shí)首先根據(jù)鏡像和配置參數(shù)為容器準(zhǔn)備好一個(gè)根文件系統(tǒng)的目錄樹,然后執(zhí)行pivot_root系統(tǒng)調(diào)用將新命名空間中的根文件系統(tǒng)切換到這個(gè)目錄樹上,再執(zhí)行umount調(diào)用卸載原有內(nèi)容,最終為容器環(huán)境準(zhǔn)備好一個(gè)隔離的文件系統(tǒng)視圖。
接下來(lái)需要特別提到的是,Docker容器鏡像的構(gòu)建基于一系列的鏡像層,這些鏡像本身是只讀的,在容器運(yùn)行時(shí)根據(jù)鏡像創(chuàng)建容器時(shí)才為每個(gè)容器提供相互獨(dú)立的讀寫層。Docker引擎提供的容器鏡像構(gòu)建工具還可以將某個(gè)鏡像作為基礎(chǔ)鏡像來(lái)創(chuàng)建新鏡像,當(dāng)然這是分層技術(shù)的一個(gè)合理擴(kuò)展。從讀取的角度看,虛擬文件系統(tǒng)將多層鏡像中的目錄結(jié)構(gòu)匯聚起來(lái)向用戶提供單一的視圖,并且上層文件覆蓋下層;而從寫入角度看,實(shí)現(xiàn)這種鏡像分層的關(guān)鍵在于COW(Copy On Write)技術(shù),簡(jiǎn)單地說(shuō),就是虛擬文件系統(tǒng)在用戶更改某個(gè)文件時(shí),才將原本共享的只讀內(nèi)容復(fù)制到讀寫層,供用戶操作。這種通過(guò)堆棧式的只讀鏡像層來(lái)創(chuàng)建容器的方式帶來(lái)的明顯好處就是,在存儲(chǔ)和傳輸鏡像的時(shí)候,許多已經(jīng)被緩存的共享鏡像層就可以通過(guò)引用的形式來(lái)標(biāo)注,無(wú)需再占用存儲(chǔ)空間和網(wǎng)絡(luò)帶寬了。這種對(duì)資源的有效利用可以幫助Docker引擎更快地下載鏡像,也能夠幫助管理員在同一臺(tái)設(shè)備上規(guī)劃更多的應(yīng)用容器。
對(duì)于容器的運(yùn)行來(lái)說(shuō),有時(shí)僅僅提供隔離性是不夠的。比如上面已經(jīng)提到的CGroup技術(shù),對(duì)它的管理是在宿主機(jī)上的/sys/fs/cgroup路徑下某些節(jié)點(diǎn)中進(jìn)行的,但是新建了MNT命名空間之后,這些節(jié)點(diǎn)路徑和容器文件系統(tǒng)視圖中的節(jié)點(diǎn)如何關(guān)聯(lián)呢?這就不能不提到Linux下mount系統(tǒng)調(diào)用中的綁定掛載功能。
在Linux下可以采用綁定掛載的方式將一個(gè)文件或者目錄綁定到某個(gè)掛載點(diǎn)上,使得在那個(gè)掛載點(diǎn)上可以看到這個(gè)文件或者目錄的內(nèi)容。并且這種綁定處理的效果可以跨越文件系統(tǒng)和命名空間的邊界。顯然,容器運(yùn)行時(shí)正是利用了這個(gè)技術(shù)將容器內(nèi)外環(huán)境拼接起來(lái)。另外,這種綁定掛載功能設(shè)計(jì)中支持單向和雙向的共享設(shè)定,還能夠進(jìn)行遞歸性質(zhì)和多級(jí)模式的設(shè)定,這些設(shè)定被稱為傳播模式。目前的容器運(yùn)行時(shí)接口上已經(jīng)能夠完整支持這些參數(shù)設(shè)定。
在Docker中得到運(yùn)用的不僅包括上述這些技術(shù),還集成了Capabilities設(shè)置、Seccomp、SELinux/AppArmor等其他與安全控制相關(guān)的技術(shù),它們都是操作系統(tǒng)通過(guò)一系列分離的API實(shí)現(xiàn)的,它們被Docker引擎通過(guò)標(biāo)準(zhǔn)化的配置和對(duì)外管理接口集成起來(lái),為用戶提供了一整套方便使用、持續(xù)演進(jìn)的容器化應(yīng)用構(gòu)建、發(fā)布和運(yùn)行工具。
Docker 任務(wù)調(diào)度 容器 Kubernetes
版權(quán)聲明:本文內(nèi)容由網(wǎng)絡(luò)用戶投稿,版權(quán)歸原作者所有,本站不擁有其著作權(quán),亦不承擔(dān)相應(yīng)法律責(zé)任。如果您發(fā)現(xiàn)本站中有涉嫌抄襲或描述失實(shí)的內(nèi)容,請(qǐng)聯(lián)系我們jiasou666@gmail.com 處理,核實(shí)后本網(wǎng)站將在24小時(shí)內(nèi)刪除侵權(quán)內(nèi)容。
版權(quán)聲明:本文內(nèi)容由網(wǎng)絡(luò)用戶投稿,版權(quán)歸原作者所有,本站不擁有其著作權(quán),亦不承擔(dān)相應(yīng)法律責(zé)任。如果您發(fā)現(xiàn)本站中有涉嫌抄襲或描述失實(shí)的內(nèi)容,請(qǐng)聯(lián)系我們jiasou666@gmail.com 處理,核實(shí)后本網(wǎng)站將在24小時(shí)內(nèi)刪除侵權(quán)內(nèi)容。