本文是《深入剖析k8s》學(xué)習(xí)筆記的第一篇内列,主要幫助深入理解容器的發(fā)展歷史和底層原理,順便了解k8s區(qū)別于Docker、Mesos的的地方及優(yōu)勢概行。
一、容器的歷史介紹
k8s難以理解的原因在于從過去物理機和虛擬機為主體的開發(fā)運維環(huán)境弧岳,向以容器為核心的基礎(chǔ)設(shè)施轉(zhuǎn)變的過程凳忙,并不是一次溫和的改革,而是涵蓋了對網(wǎng)絡(luò)禽炬、存儲涧卵、調(diào)度、操作系統(tǒng)和分布式原理等各個方面的容器化改造腹尖。
Docker之所以能擊敗其它Paas產(chǎn)品的殺手锏就是Docker鏡像柳恐。大家雖然都是用namespace和cgroups技術(shù)創(chuàng)建沙盒來實現(xiàn)應(yīng)用隔離,但是Paas是對應(yīng)用程序打包热幔,這個包可以在本地運行不代表在其它環(huán)境也能正常運行乐设,會受限于各種各樣的環(huán)境因素。Docker直接基于本地運行時的操作系統(tǒng)環(huán)境打包绎巨,把應(yīng)用程序近尚、所有運行依賴、環(huán)境變量都打包了场勤,從而保證了本地和遠端環(huán)境的高度一致戈锻,實現(xiàn)了只要本地能跑歼跟,部署到其它任何環(huán)境下肯定也能跑的終極目標。
Docker為什么會想出Docker鏡像這一創(chuàng)新概念格遭,是由其目標客戶的定位所決定的哈街。Paas的用戶是運維人員,這也就決定了它不會考慮把系統(tǒng)依賴和環(huán)境變量作為考慮的焦點如庭;而Docker的目標客戶是開發(fā)叹卷,開發(fā)人員不一定懂得操作系統(tǒng)、網(wǎng)絡(luò)原理等運維技術(shù)坪它,他們只需要簡單骤竹、便捷、可靠地隨處運行自己的代碼往毡,為了實現(xiàn)這一目標蒙揣,Docker鏡像便出現(xiàn)了。
Docker Compose和Docker Swarm开瞭,前者是容器編排懒震,后者是集群管理,是Docker公司走向Paas平臺化的兩大重要工具嗤详。
Docker个扰、Mesos、k8s三者之爭中葱色,Docker將其開源項目和商業(yè)產(chǎn)品緊密綁定递宅,造就了一個極端封閉的生態(tài),違背了為其開發(fā)者用戶考慮的初衷苍狰;Mesos則是因為其所屬的Apache社區(qū)的封閉性办龄,鮮有創(chuàng)新;最終后來的k8s依靠其開放淋昭、可靠俐填、強大成為了最終的贏家。
二翔忽、容器的概念介紹
容器本質(zhì)上是一種特殊的進程英融,操作系統(tǒng)使用了Namespace技術(shù),為容器的運行創(chuàng)造一個新的進程空間歇式,這個進程空間包含一組限定的資源矢赁,比如文件、設(shè)備贬丛、配置等,使得容器以為這個空間就是一個全新的操作系統(tǒng)给涕。容器無法看到宿主機豺憔、其它進程空間的任何資源额获。
和虛擬機相比,Docker Engine在使用效果上確實等同Hypervisor恭应,它們看起來都是為了創(chuàng)建和管理沙盒的抄邀。但實際上,Docker Engine只是旁路式的輔助和管理昼榛,并不像Hypervisor一樣對沙盒的隔離性負責(zé)境肾,真正為容器負責(zé)隔離性的是宿主機的操作系統(tǒng)。
虛擬機Hypervisor創(chuàng)建的每一個沙盒都有獨立的Guest OS胆屿,所以隔離性是能夠得到保障的奥喻,但缺點就是笨重、效率低下非迹。Docker Engine與之相比依靠的是操作系統(tǒng)的namespace环鲤,因此更加敏捷和高性能,但是問題就是沙盒之間隔離地不夠徹底憎兽,比如它們共享宿主機的操作系統(tǒng)內(nèi)核冷离、無法隔離時間這樣的特殊資源。
因為容器只是一種特殊的進程纯命,因此就存在會和宿主機其它進程競爭資源的情形西剥,Cgroups技術(shù)就是為了限制某些進程能夠使用的資源上限而存在的,是容器沙盒資源隔離的重要實現(xiàn)手段亿汞,通過進行一系列的配置瞭空,就能限制容器使用CPU、內(nèi)存留夜、磁盤匙铡、網(wǎng)絡(luò)帶寬的用量。
容器本身的設(shè)計就是希望容器能和應(yīng)用同生命周期碍粥,而容器作為一個進程鳖眼,就意味著我們在啟動容器時,沒法同時啟動兩個應(yīng)用嚼摩,除非能事先找到這兩個應(yīng)用的共同父進程作為啟動進程钦讳,比如systemd、supervisord等枕面,但是問題也隨之而來愿卒,如果出現(xiàn)容器正常、父進程正常潮秘,但是應(yīng)用掛掉的情形琼开,就無法進行健康監(jiān)控了。
容器進程在創(chuàng)建之后枕荞,為了能和宿主機的文件系統(tǒng)相互隔離而又保持各個容器的文件目錄一致(各環(huán)境下的高度一致性)柜候,才有了容器鏡像這個概念搞动,其作用就是在容器的根目錄(var/lib/docker/aufs/mnt/***)下掛載一個標準且完整的rootfs。rootfs只是包含一個操作系統(tǒng)所擁有的文件渣刷、配置和目錄而已鹦肿,并不包含操作系統(tǒng)的內(nèi)核。形象地說辅柴,每一個新建容器的rootfs僅是操作系統(tǒng)的分身軀殼箩溃,操作系統(tǒng)的內(nèi)核靈魂仍然只有一個,就是宿主機的操作系統(tǒng)內(nèi)核碌嘀。
以上總結(jié)下來涣旨,Namespace決定了容器內(nèi)的應(yīng)用能看到什么資源(四周的墻),Cgroups決定了容器內(nèi)的應(yīng)用使用某種資源能用多少(天空)筏餐,rootfs保證了各個容器使用的文件系統(tǒng)都是一致的(大地)开泽,從這三個維度限制了容器內(nèi)應(yīng)用的運行,從而模擬出了一個任意環(huán)境下都高度一致的沙盒運行環(huán)境魁瞪。
在下圖中穆律,容器進程“python app.py”運行在由 Linux Namespace 和 Cgroups 構(gòu)成的隔離環(huán)境里;而它運行所需要的各種文件导俘,比如 python峦耘,app.py,以及整個操作系統(tǒng)文件,則由多個聯(lián)合掛載在一起的 rootfs 層提供。這些 rootfs 層的最下層缎罢,是來自 Docker 鏡像的只讀層。在只讀層之上洛口,是 Docker 自己添加的 Init 層,用來存放被臨時修改過的 /etc/hosts 等文件凯沪。而 rootfs 的最上層是一個可讀寫層第焰,它以 Copy-on-Write 的方式存放任何對只讀層的修改,容器聲明的 Volume 的掛載點妨马,也出現(xiàn)在這一層挺举。
Copy-on-Write簡稱寫時復(fù)制,是一種為了滿足讀多寫少高并發(fā)場景下的延時程序設(shè)計策略烘跺。其基本策略時當(dāng)多個對象共享同一塊內(nèi)容時湘纵,并不給所有對象都復(fù)制該內(nèi)容,而是采用延時策略滤淳,多個對象都引用到該內(nèi)容上梧喷,如此對象的復(fù)制和讀寫都很快,能承受較高的并發(fā),只有當(dāng)某個對象需要對該內(nèi)容進行修改的時候铺敌,才將內(nèi)容真的復(fù)制給該對象绊困。在Docker中的應(yīng)用就體現(xiàn)在可讀寫層和只讀層的關(guān)系上。
容器本身沒有價值适刀,容器編排才有意義。容器編排是指定義容器組織形式和管理規(guī)范的技術(shù)煤蹭。k8s不僅僅是為了拉取鏡像笔喉、運行鏡像和做一些集群運維工作,這些工作使用Mesos硝皂、Docker Compose&Swarm都可以實現(xiàn)常挚,k8s更重要的是它能定義和解決大規(guī)模集群中各種任務(wù)之間的復(fù)雜關(guān)系。比如Pod可以將緊密的容器結(jié)合在一起稽物;Service可以屏蔽后端Pod的細節(jié)奄毡,固定對外暴露的訪問方式;還有Job贝或、StatefulSet吼过、DaemonSet、HPA等API對象咪奖,都是為了實現(xiàn)不同場景下容器編排和集群管理的需求盗忱。