打開(kāi)這篇文章的同學(xué),想必對(duì) docker 都不會(huì)陌生。docker 是一種虛擬容器技術(shù),它上手比較簡(jiǎn)單,只需在宿主機(jī)上起一個(gè) docker engine,然后就能愉快的玩耍了,如:拉鏡像、起容器、掛載數(shù)據(jù)、映射端口等等。相對(duì)于 Kubernetes(K8S)的上手,可謂簡(jiǎn)單很多。那么 K8S 是什么,又為什么上手難度大?K8S 是一個(gè)基于容器技術(shù)的分布式集群管理系統(tǒng),是谷歌幾十年來(lái)大規(guī)模應(yīng)用容器技術(shù)的經(jīng)驗(yàn)積累和升華的一個(gè)重要成果。所以為了能夠支持大規(guī)模的集群管理,它承載了很多的組件,而且分布式本身的復(fù)雜度就很高。又因?yàn)?K8S 是谷歌出品的,依賴了很多谷歌自己的鏡像,所以對(duì)于國(guó)內(nèi)的同學(xué)環(huán)境搭建的難度又增加了一層。下面,我們帶著問(wèn)題,一步步來(lái)看 K8S 中到底有哪些東西?首先,既然是個(gè)分布式系統(tǒng),那勢(shì)必有多個(gè) Node 節(jié)點(diǎn)(物理主機(jī)或虛擬機(jī)),它們共同組成一個(gè)分布式集群,并且這些節(jié)點(diǎn)中會(huì)有一個(gè) Master 節(jié)點(diǎn),由它來(lái)統(tǒng)一管理 Node 節(jié)點(diǎn)。 如圖所示:
問(wèn)題一:主節(jié)點(diǎn)和工作節(jié)點(diǎn)是如何通信的呢?首先,Master 節(jié)點(diǎn)啟動(dòng)時(shí),會(huì)運(yùn)行一個(gè) kube-apiserver 進(jìn)程,它提供了集群管理的 API 接口,是集群內(nèi)各個(gè)功能模塊之間數(shù)據(jù)交互和通信的中心樞紐,并且它頁(yè)提供了完備的集群安全機(jī)制(后面還會(huì)講到)。在 Node 節(jié)點(diǎn)上,使用 K8S 中的 kubelet 組件,在每個(gè) Node 節(jié)點(diǎn)上都會(huì)運(yùn)行一個(gè) kubelet 進(jìn)程,它負(fù)責(zé)向 Master 匯報(bào)自身節(jié)點(diǎn)的運(yùn)行情況,如 Node 節(jié)點(diǎn)的注冊(cè)、終止、定時(shí)上報(bào)健康狀況等,以及接收 Master 發(fā)出的命令,創(chuàng)建相應(yīng) Pod。在 K8S 中,Pod 是最基本的操作單元,它與 docker 的容器有略微的不同,因?yàn)?Pod 可能包含一個(gè)或多個(gè)容器(可以是 docker 容器),這些內(nèi)部的容器是共享網(wǎng)絡(luò)資源的,即可以通過(guò) localhost 進(jìn)行相互訪問(wèn)。關(guān)于 Pod 內(nèi)是如何做到網(wǎng)絡(luò)共享的,每個(gè) Pod 啟動(dòng),內(nèi)部都會(huì)啟動(dòng)一個(gè) pause 容器(google的一個(gè)鏡像),它使用默認(rèn)的網(wǎng)絡(luò)模式,而其他容器的網(wǎng)絡(luò)都設(shè)置給它,以此來(lái)完成網(wǎng)絡(luò)的共享問(wèn)題。問(wèn)題二:Master 是如何將 Pod 調(diào)度到指定的 Node 上的?該工作由 kube-scheduler 來(lái)完成,整個(gè)調(diào)度過(guò)程通過(guò)執(zhí)行一些列復(fù)雜的算法最終為每個(gè) Pod 計(jì)算出一個(gè)最佳的目標(biāo) Node,該過(guò)程由 kube-scheduler 進(jìn)程自動(dòng)完成。常見(jiàn)的有輪詢調(diào)度(RR)。當(dāng)然也有可能,我們需要將 Pod 調(diào)度到一個(gè)指定的 Node 上,我們可以通過(guò)節(jié)點(diǎn)的標(biāo)簽(Label)和 Pod 的 nodeSelector 屬性的相互匹配,來(lái)達(dá)到指定的效果。如圖所示:
關(guān)于標(biāo)簽(Label)與選擇器(Selector)的概念,后面會(huì)進(jìn)一步介紹 ▲ 問(wèn)題三:各節(jié)點(diǎn)、Pod 的信息都是統(tǒng)一維護(hù)在哪里的,由誰(shuí)來(lái)維護(hù)?從上面的 Pod 調(diào)度的角度看,我們得有一個(gè)存儲(chǔ)中心,用來(lái)存儲(chǔ)各節(jié)點(diǎn)資源使用情況、健康狀態(tài)、以及各 Pod 的基本信息等,這樣 Pod 的調(diào)度來(lái)能正常進(jìn)行。在 K8S 中,采用 etcd 組件 作為一個(gè)高可用強(qiáng)一致性的存儲(chǔ)倉(cāng)庫(kù),該組件可以內(nèi)置在 K8S 中,也可以外部搭建供 K8S 使用。集群上的所有配置信息都存儲(chǔ)在了 etcd,為了考慮各個(gè)組件的相對(duì)獨(dú)立,以及整體的維護(hù)性,對(duì)于這些存儲(chǔ)數(shù)據(jù)的增、刪、改、查,統(tǒng)一由 kube-apiserver 來(lái)進(jìn)行調(diào)用,apiserver 也提供了 REST 的支持,不僅對(duì)各個(gè)內(nèi)部組件提供服務(wù)外,還對(duì)集群外部用戶暴露服務(wù)。外部用戶可以通過(guò) REST 接口,或者 kubectl 命令行工具進(jìn)行集群管理,其內(nèi)在都是與 apiserver 進(jìn)行通信。如圖所示:
問(wèn)題四:外部用戶如何訪問(wèn)集群內(nèi)運(yùn)行的 Pod ?前面講了外部用戶如何管理 K8S,而我們更關(guān)心的是內(nèi)部運(yùn)行的 Pod 如何對(duì)外訪問(wèn)。使用過(guò) docker 的同學(xué)應(yīng)該知道,如果使用 bridge 模式,在容器創(chuàng)建時(shí),都會(huì)分配一個(gè)虛擬 IP,該 IP 外部是沒(méi)法訪問(wèn)到的,我們需要做一層端口映射,將容器內(nèi)端口與宿主機(jī)端口進(jìn)行映射綁定,這樣外部通過(guò)訪問(wèn)宿主機(jī)的指定端口,就可以訪問(wèn)到內(nèi)部容器端口了。 那么,K8S 的外部訪問(wèn)是否也是這樣實(shí)現(xiàn)的?答案是否定的,K8S 中情況要復(fù)雜一些。因?yàn)樯厦嬷v的 docker 是單機(jī)模式下的,而且一個(gè)容器對(duì)外就暴露一個(gè)服務(wù)。在分布式集群下,一個(gè)服務(wù)往往由多個(gè) Application 提供,用來(lái)分擔(dān)訪問(wèn)壓力,而且這些 Application 可能會(huì)分布在多個(gè)節(jié)點(diǎn)上,這樣又涉及到了跨主機(jī)的通信。 這里,K8S 引入了 service 的概念,將多個(gè)相同的 Pod 包裝成一個(gè)完整的 service 對(duì)外提供服務(wù),至于獲取到這些相同的 Pod,每個(gè) Pod 啟動(dòng)時(shí)都會(huì)設(shè)置 labels 屬性,在 service 中我們通過(guò)選擇器 selector,選擇具有相同 name 標(biāo)簽屬性的 Pod,作為整體服務(wù),并將服務(wù)信息通過(guò) apiserver 存入 etcd 中,該工作由 Service Controller 來(lái)完成。同時(shí),每個(gè)節(jié)點(diǎn)上會(huì)啟動(dòng)一個(gè) kube-proxy 進(jìn)程,由它來(lái)負(fù)責(zé)服務(wù)地址到 Pod 地址的代理以及負(fù)載均衡等工作。如圖所示:
問(wèn)題五:Pod 如何動(dòng)態(tài)擴(kuò)容和縮放?既然知道了服務(wù)是由 Pod 組成的,那么服務(wù)的擴(kuò)容也就意味著 Pod 的擴(kuò)容。通俗點(diǎn)講,就是在需要時(shí)將 Pod 復(fù)制多份,在不需要后,將 Pod 縮減至指定份數(shù)。K8S 中通過(guò) Replication Controller 來(lái)進(jìn)行管理,為每個(gè) Pod 設(shè)置一個(gè)期望的副本數(shù),當(dāng)實(shí)際副本數(shù)與期望不符時(shí),就動(dòng)態(tài)的進(jìn)行數(shù)量調(diào)整,以達(dá)到期望值。期望數(shù)值可以由我們手動(dòng)更新,或自動(dòng)擴(kuò)容代理來(lái)完成。如圖所示:
問(wèn)題六:各個(gè)組件之間是如何相互協(xié)作的?最后,講一下 kube-controller-manager 這個(gè)進(jìn)程的作用。我們知道了 ectd 是作為集群數(shù)據(jù)的存儲(chǔ)中心, apiserver 是管理數(shù)據(jù)中心,作為其他進(jìn)程與數(shù)據(jù)中心通信的橋梁。 而 Service Controller、Replication Controller 這些統(tǒng)一交由 kube-controller-manager 來(lái)管理,kube-controller-manager 作為一個(gè)守護(hù)進(jìn)程,每個(gè) Controller 都是一個(gè)控制循環(huán),通過(guò) apiserver 監(jiān)視集群的共享狀態(tài),并嘗試將實(shí)際狀態(tài)與期望不符的進(jìn)行改變。 關(guān)于 Controller,manager 中還包含了 Node 節(jié)點(diǎn)控制器(Node Controller)、資源配額管控制器(ResourceQuota Controller)、命名空間控制器(Namespace Controller)等。 如圖所示:
總結(jié)本文通過(guò)問(wèn)答的方式,沒(méi)有涉及任何深入的實(shí)現(xiàn)細(xì)節(jié),從整體的角度,概念性的介紹了 K8S 中涉及的基本概念,其中使用相關(guān)的包括有:以及運(yùn)行進(jìn)程相關(guān)的有: kube-apiserver kube-controller-manager kube-scheduler kubelet kube-proxy pause 這也是我學(xué)習(xí) K8S 后對(duì)其整體架構(gòu)的一次總結(jié),因?yàn)樵趧偵鲜謺r(shí),閱讀官方文檔,確實(shí)被如此多的內(nèi)容搞得有點(diǎn)暈,所在在這里進(jìn)行了簡(jiǎn)單的梳理。文中有理解不到位的地方,歡迎指正!來(lái)源:https://github.com/jasonGeng88/blog
|