您好,登錄后才能下訂單哦!
??本來以為一篇就能搞定,還是低估了自己的廢話,好吧,只能通過兩篇文章向大家介紹K8s核心原理。
??kubernetes API server的和核心功能是提供了kubernetes各類資源對(duì)象(pod、RC 、service等)的增、刪、改、查以及watch等HTTP Rest接口,是整個(gè)系統(tǒng)的數(shù)據(jù)總線和數(shù)據(jù)中心。有時(shí)候我們使用kubectl創(chuàng)建或者查看pod等資源的時(shí)候,發(fā)現(xiàn)沒有反應(yīng),可能就是你的kube-apiservice服務(wù)異常退出導(dǎo)致的。
??Kubernetes API server通過一個(gè)名為kube-apiservice的進(jìn)程提供服務(wù),該進(jìn)程運(yùn)行與master節(jié)點(diǎn)上。默認(rèn)情況下該進(jìn)程的端口是本機(jī)的8080提供restful服務(wù)。(注意如果是HTTPS,則是6443端口)。
??接下來的一些操作,介紹一些如何通過rest 與kubernetes API server交互,這有便于后各k8s各個(gè)組件之間通信的理解:
[root@zy ~]# kubectl cluster-info #查看主節(jié)點(diǎn)信息
[root@zy ~]# curl localhost:8080/api #查看kubernetes API的版本信息
[root@zy ~]# curl localhost:8080/api #查看kubernetes API支持的所有的資源對(duì)象
當(dāng)然我們也可以訪問具體的資源
[root@zy ~]# curl localhost:8080/api/v1/pods
[root@zy ~]# curl localhost:8080/api/v1/services
[root@zy ~]# curl localhost:8080/api/v1/replicationcontrollers
當(dāng)我們在運(yùn)行kubectl get svc時(shí)會(huì)發(fā)現(xiàn):
??有一個(gè)以上話紅框的服務(wù),這個(gè)是什么呢,原來為了讓pod中的進(jìn)程能夠知道kubernetes API server的訪問地址,kubernetes API server本身也是一個(gè)service,名字就叫“kubernetes”,并且他的cluster IP 就是cluster IP地址池例的第一個(gè)地址,另外它服務(wù)的端口就是443。
??kubernetes API server還提供了一類很特殊的rest接口—proxy接口,這個(gè)結(jié)構(gòu)就是代理REST請(qǐng)求,即kubernetes API server把收到的rest請(qǐng)求轉(zhuǎn)發(fā)到某個(gè)node上的kubelet守護(hù)進(jìn)程的rest端口上,由該kubelet進(jìn)程負(fù)責(zé)相應(yīng)。
舉例:
masterIP:8080/api/v1/proxy/nodes/{node_name}/pods #某個(gè)節(jié)點(diǎn)下所有pod信息
masterIP:8080/api/v1/proxy/nodes/{node_name}/stats #某個(gè)節(jié)點(diǎn)內(nèi)物理資源的統(tǒng)計(jì)信息
masterIP:8080/api/v1/proxy/nodes/{node_name}/spec #某個(gè)節(jié)點(diǎn)的概要信息
#接下來說一下比較重要的pod的相關(guān)接口
masterIP:8080/api/v1/proxy/namespaces/{namespace}/pods/{pod_name}/{path:*} #訪問pod的某個(gè)服務(wù)接口
masterIP:8080/api/v1/proxy/namespaces/{namespace}/pods/{pod_name} #訪問pod
假如這里有一個(gè)名為myweb的Tomcat的pod
我們在瀏覽器中輸入masterIP:8080/api/v1/proxy/namespaces/{namespace}/pods/myweb就能訪問到該pod的http服務(wù)了。
如果這里是一個(gè)幾個(gè)web的pod組成的service的話:
masterIP:8080/api/v1/proxy/namespaces/{namespace}/services/{service_name}
就能訪問到其下面的服務(wù),當(dāng)然最終會(huì)通過kube-proxy被定位到相應(yīng)的pod下。
??Kubernetes API Server作為集群的和核心,負(fù)責(zé)集群各功能模塊之間的通信。集群內(nèi)的各個(gè)功能模塊通過API server將信息存入etcd,同樣的想要獲取和操作這些數(shù)據(jù)時(shí),也是通過API Server的REST接口(GET、LIST、WATCH)來實(shí)現(xiàn),從而實(shí)現(xiàn)各個(gè)模塊之間的交互。
接下來小編通過一張圖,簡單介紹一下幾種典型的交互場景:
??介紹:Controller Manager作為集群內(nèi)部管理控制中心,負(fù)責(zé)集群內(nèi)的Node、Pod副本、EndPoint、命名空間、服務(wù)賬號(hào)、資源定額等管理。當(dāng)某個(gè)Node意外宕機(jī)了,Controller Manager會(huì)及時(shí)發(fā)現(xiàn)此故障并執(zhí)行自動(dòng)修復(fù)流程,確保集群始終處于預(yù)期的工作狀態(tài)。
??由上圖所示,Controller Manager中包含很多個(gè)controller,每一種controller都負(fù)責(zé)一種具體的控制流程,而Controller Manager正是這些controller的核心管理者。一般來說,智能系統(tǒng)和自動(dòng)系統(tǒng)都被稱為一個(gè)“操縱系統(tǒng)”的機(jī)構(gòu)來不斷修正系統(tǒng)的工作狀態(tài)。在kubernetes集群中,每個(gè)controller都有這樣一個(gè)“操縱系統(tǒng)”,他們通過API Server提供的接口實(shí)時(shí)監(jiān)控整個(gè)集群里的每一個(gè)資源對(duì)象的當(dāng)前狀態(tài),當(dāng)發(fā)生各種故障導(dǎo)致系統(tǒng)狀態(tài)發(fā)生變化,這些controller會(huì)嘗試將系統(tǒng)從“現(xiàn)有裝態(tài)”修正到“期望狀態(tài)”。
接下來小編會(huì)介紹一些比較重要的Controller。
??在介紹replication controller時(shí)小編要強(qiáng)調(diào)一點(diǎn)的是,千萬不要把資源對(duì)象的那個(gè)RC和這個(gè)replication controller弄混淆了,我們這里介紹的replication controller是副本的控制器,RC只是一個(gè)資源對(duì)象,上層是replication controlle管理各個(gè)RC。(這里我們統(tǒng)一的將replication controller叫副本的控制器,資源對(duì)象RC叫RC)。
??副本的控制器的核心作用是確保任何使用集群中的一個(gè)RC所關(guān)聯(lián)的Pod副本數(shù)量保持預(yù)設(shè)的值。如果發(fā)現(xiàn)Pod副本數(shù)超過預(yù)設(shè)的值,則副本的控制器會(huì)銷毀一些Pod的副本,反之則創(chuàng)建一些新的Pod的副本以達(dá)到目標(biāo)值。值得注意的是只有當(dāng)Pod的重啟策略是always時(shí),副本的控制器才會(huì)管理該pod的操作。通常情況下,pod對(duì)象被成功的創(chuàng)建之后不會(huì)消失,唯一例外的是當(dāng)pod處于success或者failed狀態(tài)的時(shí)間過長(超時(shí)時(shí)間可以設(shè)定),該pod會(huì)被系統(tǒng)自動(dòng)回收,管理該pod的副本的控制器將在其他的工作節(jié)點(diǎn)上重新創(chuàng)建、啟動(dòng)該pod。
??RC中的Pod模板就像一個(gè)模具,模具制作出來的東西一旦離開模具,二者將毫無關(guān)系,一旦pod創(chuàng)建,無論模板如何變化都不會(huì)影響到已經(jīng)創(chuàng)建的pod,并且刪除一個(gè)RC 不會(huì)影響它所創(chuàng)建出來的Pod,當(dāng)然如果想在RC控制下,刪除所有的Pod,需要將RC中設(shè)置的pod的副本數(shù)該為0,這樣才會(huì)自動(dòng)刪除所有的Pod。
replication controller(副本的控制器)的職責(zé):
?? - 確保當(dāng)前管理的Pod的數(shù)量為預(yù)設(shè)值
?? - 通過調(diào)用RC的spec.replicas屬性實(shí)現(xiàn)系統(tǒng)擴(kuò)容和縮容
?? - 通過改變RC中的Pod的模板中的image,來實(shí)現(xiàn)系統(tǒng)的滾動(dòng)升級(jí)
replication controller(副本的控制器)的使用場景 :
?? - 重新調(diào)度:無論是否有節(jié)點(diǎn)宕機(jī),還是pod意外死亡,RC都可以保證自己所管理的正在運(yùn)行Pod的數(shù)量為預(yù)設(shè)值
?? - 彈性伸縮:實(shí)現(xiàn)集群的擴(kuò)容和縮容(根據(jù)集群的可用資源和負(fù)載壓力)
?? - 滾動(dòng)升級(jí):應(yīng)用服務(wù)升級(jí)新的版本,并且保證整個(gè)升級(jí)過程,應(yīng)用服務(wù)仍可對(duì)外提供服務(wù)。
??Kubelet進(jìn)程在啟動(dòng)時(shí)會(huì)通過API Server注冊自身的節(jié)點(diǎn)信息,并定時(shí)的向API Server匯報(bào)狀態(tài)信息,API Server在接受到這些信息后,將這些信息更新到etcd中。Etcd中存儲(chǔ)的節(jié)點(diǎn)信息包括:節(jié)點(diǎn)的健康狀態(tài)、節(jié)點(diǎn)資源、節(jié)點(diǎn)名稱、節(jié)點(diǎn)地址信息、操作系統(tǒng)版本、docker版本、kubelet版本等。而節(jié)點(diǎn)的健康狀態(tài)有三種:就緒(True)、未就緒(False)、未知(Unknown)。
接下來小編通過圖來介紹Node Controller的核心工作流程:
具體步驟
?- 如果controller manager在啟動(dòng)時(shí)設(shè)置了--cluster-cidr,那么為每一個(gè)沒有設(shè)置spec.PodCIDR的節(jié)點(diǎn)生成一個(gè)CIDR地址,并用該地址設(shè)置節(jié)點(diǎn)的spec.PodCIDR屬性。
?- 逐個(gè)讀取節(jié)點(diǎn)信息,此時(shí)node controller中有一個(gè)nodestatusMap,里面存儲(chǔ)了信息,與新發(fā)送過來的節(jié)點(diǎn)信息做比較,并更新nodestatusMap中的節(jié)點(diǎn)信息。Kubelet發(fā)送過來的節(jié)點(diǎn)信息,有三種情況:未發(fā)送、發(fā)送但節(jié)點(diǎn)信息未變化、發(fā)送并且節(jié)點(diǎn)信息變化。此時(shí)node controller根據(jù)發(fā)送的節(jié)點(diǎn)信息,更新nodestatusMap,如果判斷出在某段時(shí)間內(nèi)沒有接受到某個(gè)節(jié)點(diǎn)的信息,則設(shè)置節(jié)點(diǎn)狀態(tài)為“未知”。
?- 最后,將未就緒狀態(tài)的節(jié)點(diǎn)加入到待刪除隊(duì)列中,待刪除后,通過API Server將etcd中該節(jié)點(diǎn)的信息刪除。如果節(jié)點(diǎn)為就緒狀態(tài),那么就向etcd中同步該節(jié)點(diǎn)信息。
??Kubernetes提供了資源配額管理(resourceQuota controller)這里高級(jí)功能,資源配置管理確保了指定的資源對(duì)象在任何時(shí)候都不會(huì)超量占用系統(tǒng)物理資源,避免了由于某些業(yè)務(wù)進(jìn)程的設(shè)計(jì)或者實(shí)現(xiàn)的缺陷導(dǎo)致整個(gè)系統(tǒng)運(yùn)行紊亂設(shè)置意外宕機(jī),對(duì)整個(gè)集群的穩(wěn)定性有著至關(guān)重要的作用。
目前kubernetes支持如下三個(gè)層次的資源配額管理:
? - 容器級(jí)別:對(duì)CPU 和 memory的限制
? - Pod級(jí)別:可以對(duì)一個(gè)pod內(nèi)所有容器的可用資源進(jìn)行限制
? - Namespace級(jí)別:為namespace(多租戶)級(jí)別的資源限制,其中限制的資源包括:
? ? ? △ Pod數(shù)量
? ? ? △ RC數(shù)量
? ? ? △ Service數(shù)量
? ? ? △ ResourceQuota數(shù)量
? ? ? △ Secret數(shù)量
? ? ? △ 可持有的PV數(shù)量
? ? Kubernetes的配額管理是通過admission control(準(zhǔn)入控制)來控制的。admission control當(dāng)前提供了兩種方式的配額約束,分別是limitRanger和resourceQuota。其中l(wèi)imitRanger作用于pod和容器上。ResourceQuota作用于namespace上,用于限定一個(gè)namespace里的各類資源的使用總額。
Kubernetes的配額管理是通過admission control(準(zhǔn)入控制)來控制的。admission control當(dāng)前提供了兩種方式的配額約束,分別是limitRanger和resourceQuota。其中l(wèi)imitRanger作用于pod和容器上。ResourceQuota作用于namespace上,用于限定一個(gè)namespace里的各類資源的使用總額。
從上圖中,我們可以看出,大概有三條路線,resourceQuota controller在這三條路線中都起著重要的作用:
? ? 用戶通過API Server可以創(chuàng)建新的namespace并保存在etcd中,namespace controller定時(shí)通過API Server讀取這些namespace信息。如果namespace被API標(biāo)記為優(yōu)雅刪除(通過設(shè)置刪除周期),則將該namespace的狀態(tài)設(shè)置為“terminating”并保存到etcd中。同時(shí)namespace controller刪除該namespace下的serviceAccount,RC,pod,secret,PV,listRange,resourceQuota和event等資源對(duì)象。
? ? 當(dāng)namespace的狀態(tài)為“terminating”后,由admission controller的namespaceLifecycle插件來阻止為該namespace創(chuàng)建新的資源。同時(shí)在namespace controller刪除完該namespace中的所有資源對(duì)象后,namespace controller對(duì)該namespace 執(zhí)行finalize操作,刪除namespace的spec.finallizers域中的信息。
? ?當(dāng)然這里有一種特殊情況,當(dāng)個(gè)namespace controller發(fā)現(xiàn)namespace設(shè)置了刪除周期,并且該namespace 的spec.finalizers域值為空,那么namespace controller將通過API Server刪除該namespace 的資源。
? ?上圖所示了service和endpoint與pod的關(guān)系,endpoints表示一個(gè)service對(duì)應(yīng)的所有的pod副本的訪問地址,而endpoints controller就是負(fù)責(zé)生成和維護(hù)所有endpoints對(duì)象的控制器。
? ?它負(fù)責(zé)監(jiān)聽service和對(duì)應(yīng)的pod副本的變化,如果檢測到service被刪除,則刪除和該service同名的endpoints對(duì)象。如果檢測到新的service被創(chuàng)建或者修改,則根據(jù)該service的信息獲取到相關(guān)的pod列表,然后創(chuàng)建或者更新service對(duì)應(yīng)的endpoints對(duì)象。如果檢測到pod的事件,則更新它對(duì)應(yīng)service的endpoints對(duì)象(增加或者刪除或者修改對(duì)應(yīng)的endpoint條目)。
? ?kubernetes scheduler 在整個(gè)系統(tǒng)中承擔(dān)了“承上啟下”的作用,“承上”是指它負(fù)責(zé)接收controller manager創(chuàng)建的新的pod,為其安排一個(gè)落腳的“家”,“啟下”是指安置工作完成以后,目標(biāo)node上的kubelet服務(wù)進(jìn)程接管后繼工作,負(fù)責(zé)pod生命周期中的“下半生”。
我們都知道將service和pod通過label關(guān)聯(lián)之后,我們訪問service的clusterIP對(duì)應(yīng)的服務(wù),就能通過kube-proxy將路由轉(zhuǎn)發(fā)到對(duì)應(yīng)的后端的endpoint(pod IP +port)上,最終訪問到容器中的服務(wù),實(shí)現(xiàn)了service的負(fù)載均衡功能。
? ?那么接下來說一說service controller的作用,它其實(shí)是屬于kubernetes與外部的云平臺(tái)之間的一個(gè)接口控制器。Service controller監(jiān)聽service的變化,如果是一個(gè)loadBalancer類型的service,則service controller確保外部的云平臺(tái)上該service對(duì)應(yīng)的loadbalance實(shí)例被相應(yīng)的創(chuàng)建、刪除以及更新路由轉(zhuǎn)發(fā)表(根據(jù)endpoint的條目)。
? ?kubernetes scheduler 在整個(gè)系統(tǒng)中承擔(dān)了“承上啟下”的作用,“承上”是指它負(fù)責(zé)接收controller manager創(chuàng)建的新的pod,為其安排一個(gè)落腳的“家”,“啟下”是指安置工作完成以后,目標(biāo)node上的kubelet服務(wù)進(jìn)程接管后繼工作,負(fù)責(zé)pod生命周期中的“下半生”。
? ?具體的來說,kubernetes scheduler的作用就是將待調(diào)度的pod(新建的、補(bǔ)足副本而創(chuàng)建的)按照特定的調(diào)度算法和調(diào)度策略綁定到集群中某個(gè)合適的node上,并將綁定信息寫入到etcd中。整個(gè)調(diào)度過程分為三個(gè)對(duì)象,分別是:待調(diào)度的pod列表、可有的合適的node列表、調(diào)度算法和策略。一句話就是通過合適的調(diào)度算法和策略,將待調(diào)度的pod列表中的pod在合適的node上創(chuàng)建并啟動(dòng)。
接下來小編通過一幅圖簡單介紹一下scheduler的工作流程:
有圖可知:
? 遍歷所有目標(biāo)node,篩選出符合要求的候選節(jié)點(diǎn)。為此,kubernetes內(nèi)置了多種預(yù)選策略
? 確定優(yōu)先節(jié)點(diǎn),在第1步的基礎(chǔ)上,采用優(yōu)選策略,計(jì)算出每一個(gè)節(jié)點(diǎn)候選的積分,積分最高者勝出
? 最后通過API Server將待調(diào)度的Pod,通知給最優(yōu)node上的kubelet,將其創(chuàng)建并運(yùn)行
? ?在scheduler中可用的預(yù)選算有很多:NoDiskconflict、PodFitsResources、PodSelectorMatches、PodFitsHost、CheckNodeLabelPresence、CheckServiceAffinity、PodFitsPorts等策略。其中的5個(gè)默認(rèn)的預(yù)選策略:PodFitsPorts、PodFitsResources、NoDiskconflict、PodSelectorMatches、PodFitsHost每個(gè)節(jié)點(diǎn)只有通過這5個(gè)預(yù)選策略后,才能初步被選中,進(jìn)入下一個(gè)流程。
下面小編介紹幾個(gè)常用的預(yù)選策略:
? ?判斷備選pod的gcePersistentDisk或者AWSElasticBlockStore和備選的節(jié)點(diǎn)中已存在的pod是否存在沖突具體檢測過程如下:
? ?? - 首先,讀取備選pod的所有的volume信息,對(duì)每一個(gè)volume執(zhí)行一下步驟的沖突檢測
? ?? - 如果該volume是gcePersistentDisk,則將volume和備選節(jié)點(diǎn)上的所有pod的每個(gè)volume進(jìn)行比較,如果發(fā)現(xiàn)相同的gcePersistentDisk,則返回false,表明磁盤沖突,檢測結(jié)束,反饋給調(diào)度器該備選節(jié)點(diǎn)不合適作為備選的pod,如果volume是AWSElasticBlockStore,則將volume和備選節(jié)點(diǎn)上的所有pod的每個(gè)volume進(jìn)行比較,如果發(fā)現(xiàn)相同的AWSElasticBlockStore,則返回false,表明磁盤沖突,檢測結(jié)束,反饋給調(diào)度器該備選節(jié)點(diǎn)不合適作為備選的pod
? ?? - 最終,檢查備選pod的所有的volume均為發(fā)現(xiàn)沖突,則返回true,表明不存在磁盤沖突,反饋給調(diào)度器該備選節(jié)點(diǎn)合適備選pod
? ?判斷備選節(jié)點(diǎn)資源是否滿足備選pod的需求,檢測過程如下:
? ?? - 計(jì)算備選pod和節(jié)點(diǎn)中已存在的pod的所有容器的需求資源(CPU 和內(nèi)存)的總和
? ?? - 獲得備選節(jié)點(diǎn)的狀態(tài)信息,其中包括節(jié)點(diǎn)的資源信息
? ?? - 如果備選pod和節(jié)點(diǎn)中已存在pod的所有容器的需求資源(CPU和內(nèi)存)的總和超出了備選節(jié)點(diǎn)擁有的資源,則返回false,表明備選節(jié)點(diǎn)不適合備選pod,否則返回true,表明備選節(jié)點(diǎn)適合備選pod
? ?判斷備選節(jié)點(diǎn)是否包含備選pod的標(biāo)簽選擇器指定的標(biāo)簽:
? ?? - 如果pod沒有指定spec.nodeSelector標(biāo)簽選擇器,則返回true
? ?? - 如果獲得備選節(jié)點(diǎn)的標(biāo)簽信息,判斷節(jié)點(diǎn)是否包含備選pod的標(biāo)簽選擇器所指的標(biāo)簽,如果包含返回true,不包含返回false
??判斷備選pod的spec.nodeName域所指定的節(jié)點(diǎn)名稱和備選節(jié)點(diǎn)的名稱是否一致,如果一致返回true,否則返回false。
??判斷備選pod所用的端口列表匯中的端口是否在備選節(jié)點(diǎn)中被占用,如果被占用,則返回false,否則返回true。
??Scheduler中的優(yōu)選策略有:leastRequestedPriority、CalculateNodeLabelPriority和BalancedResourceAllocation等。每個(gè)節(jié)點(diǎn)通過優(yōu)先策略時(shí)都會(huì)算出一個(gè)得分,計(jì)算各項(xiàng)得分,最終選出得分值最大的節(jié)點(diǎn)作為優(yōu)選結(jié)果。
小編接下來就給大家介紹一下一些常用的優(yōu)選策略:
??該策略用于從備選節(jié)點(diǎn)列表中選出資源消耗最小的節(jié)點(diǎn):
? ?? - 計(jì)算出所有備選節(jié)點(diǎn)上運(yùn)行的pod和備選pod的CPU占用量
? ?? - 計(jì)算出所有備選節(jié)點(diǎn)上運(yùn)行的pod和備選pod的memory占用量
? ?? - 根據(jù)特定的算法,計(jì)算每個(gè)節(jié)點(diǎn)的得分
? ?如果用戶在配置中指定了該策略,則scheduler會(huì)通過registerCustomPriorityFunction方法注冊該策略。該策略用于判斷策略列出的標(biāo)簽在備選節(jié)點(diǎn)中存在時(shí),是否選擇該備選節(jié)點(diǎn)。如果備選節(jié)點(diǎn)的標(biāo)簽在優(yōu)選策略的標(biāo)簽列表中且優(yōu)選策略的presence值為true,或者備選節(jié)點(diǎn)的標(biāo)簽不在優(yōu)選策略的標(biāo)簽列表中且優(yōu)選策略的presence值為false,則備選節(jié)點(diǎn)score=10,否則等于0。
? ?該優(yōu)選策略用于從備選節(jié)點(diǎn)列表中選出各項(xiàng)資源使用率最均衡的節(jié)點(diǎn):
? ?? - 計(jì)算出所有備選節(jié)點(diǎn)上運(yùn)行的pod和備選pod的CPU占用量
? ?? - 計(jì)算出所有備選節(jié)點(diǎn)上運(yùn)行的pod和備選pod的memory占用量
? ?? - 根據(jù)特定的算法,計(jì)算每個(gè)節(jié)點(diǎn)的得分
? ?在kubernetes集群中,每個(gè)node上都會(huì)啟動(dòng)一個(gè)kubelet服務(wù)進(jìn)程。該進(jìn)程用于處理master節(jié)點(diǎn)下發(fā)到本節(jié)點(diǎn)的任務(wù),管理Pod以及Pod中的容器。每個(gè)kubelet進(jìn)程會(huì)在API Server上注冊節(jié)點(diǎn)信息,定期向master節(jié)點(diǎn)匯報(bào)節(jié)點(diǎn)資源的使用情況,并通過cAdvisor監(jiān)控容器和節(jié)點(diǎn)的資源。
? ?節(jié)點(diǎn)通過設(shè)置kubelet的啟動(dòng)參數(shù)“--register-node”來決定是否向API Server注冊自己。如果該參數(shù)為true,那么kubelet將試著通過API Server注冊自己。在自注冊時(shí),kubelet啟動(dòng)時(shí)還包括以下參數(shù):
? ? -api-servers:API Server的位置
? ? --kubeconfing:kubeconfig文件,用于訪問API Server的安全配置文件
? ? --cloud-provider:云服務(wù)商地址,僅用于共有云環(huán)境
? ?如果沒有選擇自注冊模式,用戶需要手動(dòng)去配置node的資源信息,同時(shí)告知ndoe上的kubelet API Server的位置。Kubelet在啟動(dòng)時(shí)通過API Server注冊節(jié)點(diǎn)信息,并定時(shí)向API Server發(fā)送節(jié)點(diǎn)新消息,API Server在接受到這些消息之后,將這些信息寫入etcd中。通過kubelet的啟動(dòng)參數(shù)“--node-status-update-frequency”設(shè)置kubelet每個(gè)多長時(shí)間向API Server報(bào)告節(jié)點(diǎn)狀態(tài),默認(rèn)為10s。
? ? kubelet通過以下幾種方式獲取自身node上所要運(yùn)行的pod清單:
? ?? 文件:kubelet啟動(dòng)參數(shù)“--config”指定的配置文件目錄下的文件(默認(rèn)為“/etc/Kubernetes/manifests”)通過--file-check-frequency設(shè)置檢查該文件的時(shí)間間隔,默認(rèn)為20s
? ?? HTTP端點(diǎn):通過“--manifest-url”參數(shù)設(shè)置。通過“--http-check-frequency”設(shè)置檢查該HTTP端點(diǎn)數(shù)據(jù)的時(shí)間間隔,默認(rèn)為20s。
? ?? API Server:kubelet通過API server監(jiān)聽etcd目錄,同步pod列表
注意:這里static pod,不是被API Server創(chuàng)建的,而是被kubelet創(chuàng)建,之前文章中提到了靜態(tài)的pod是在kubelet的配置文件中編寫,并且總在kubelet所在node上運(yùn)行。
? ?Kubelet監(jiān)聽etcd,所有針對(duì)pod的操作將會(huì)被kubelet監(jiān)聽到。如果是新的綁定到本節(jié)點(diǎn)的pod,則按照pod清單的要求創(chuàng)建pod,如果是刪除pod,則kubelet通過docker client去刪除pod中的容器,并刪除該pod。
? ?具體的針對(duì)創(chuàng)建和修改pod任務(wù),流程為:
? ?? - 為該pod創(chuàng)建一個(gè)目錄
? ?? - 從API Server讀取該pod清單
? ?? - 為該pod掛載外部volume
? ?? - 下載pod用到的secret
? ?? - 檢查已經(jīng)運(yùn)行在節(jié)點(diǎn)中的pod,如果該pod沒有容器或者Pause容器沒有啟動(dòng),則先停止pod里的所有容器的進(jìn)程。如果pod中有需要?jiǎng)h除的容器,則刪除這些容器
? ?? - 檢查已經(jīng)運(yùn)行在節(jié)點(diǎn)中的pod,如果該pod沒有容器或者Pause容器沒有啟動(dòng),則先停止pod里的所有容器的進(jìn)程。如果pod中有需要?jiǎng)h除的容器,則刪除這些容器
? ?? - 為pod中的每個(gè)容器做如下操作
? ?? ? ?△ 為容器計(jì)算一個(gè)hash值,然后用容器的名字去查詢docker容器的hash值。若查找到容器,且兩者得到hash不同,則停止docker中的容器的進(jìn)程,并且停止與之關(guān)聯(lián)pause容器的進(jìn)程;若兩個(gè)相同,則不做任何處理
? ?? ? ?△ 如果容器被停止了,且容器沒有指定restartPolicy(重啟策略),則不做任何處理
? ?? ? ?△調(diào)用docker client 下載容器鏡像,調(diào)用docker client 運(yùn)行容器
? ?Pod通過兩類探針來檢查容器的健康狀態(tài)。一個(gè)是livenessProbe探針,用于判斷容器是否健康,告訴kubelet一個(gè)容器什么時(shí)候處于不健康狀態(tài),如果livenessProbe探針探測到容器不健康,則kubelet將刪除該容器,并根據(jù)容器的重啟策略做相應(yīng)的處理;如果一個(gè)容器不包含livenessProbe探針,那么kubelet認(rèn)為livenessProbe探針的返回值永遠(yuǎn)為“success”。另一個(gè)探針為ReadinessProbe,用于判斷容器是否啟動(dòng)完成,且準(zhǔn)備接受請(qǐng)求。如果ReadinessProbe探針檢測到失敗,則pod的狀態(tài)將被修改,endpoint controller將從service的endpoints中刪除包含該容器所在pod的IP地址的endpoint條目。
? ?Kubelet定期調(diào)用容器中的livenessProbe探針來診斷容器的健康狀態(tài)。livenessProbe包括以下三種實(shí)現(xiàn)方式:
? ? - Execaction:在容器內(nèi)執(zhí)行一個(gè)命令,如果該命令的退出狀態(tài)碼為0,表示容器健康
? ? - TCPSocketAction:通過容器的IP地址和端口執(zhí)行一個(gè)TCP檢查,如果端口能被訪問,則表明該容器正常
? ? - TCPSocketAction:通過容器的IP地址和端口執(zhí)行一個(gè)TCP檢查,如果端口能被訪問,則表明該容器正常
具體的配置小編之前的文章中有詳細(xì)說明:https://blog.51cto.com/14048416/2396640
? ? 介紹kube-proxy,不得不說service,這里小編先帶大家回顧一下service,由于pod每次創(chuàng)建時(shí)它的IP地址是不固定的,為了訪問方便以及負(fù)載均衡,這里引入了service的概念,service在創(chuàng)建后有一個(gè)clusterIP,這個(gè)IP是固定的,通過labelselector與后端的pod關(guān)聯(lián),這樣我們?nèi)绻朐L問后端的應(yīng)用服務(wù),只需要通過service的clusterIP,然后就會(huì)將請(qǐng)求轉(zhuǎn)發(fā)到后端的pod上,即使一個(gè)反向代理,又是一個(gè)負(fù)載均衡。
? ? 但是在很多情況下service只是一個(gè)概念,而真正將service的作用落實(shí)的這是背后的kube-proxy服務(wù)進(jìn)程。那么接下來就具體的介紹kube-proxy。
? ? 在kubernetes集群中的每一個(gè)node上都有一個(gè)kube-proxy進(jìn)程,這個(gè)進(jìn)程可以看做service的透明代理兼負(fù)載均衡,其核心功能就是將到某個(gè)service的訪問請(qǐng)求轉(zhuǎn)發(fā)到后端的多個(gè)pod實(shí)例上。對(duì)每一個(gè)TCP類型的kubernetes service,kube-proxy都會(huì)在本地node上建立一個(gè)socketserver來負(fù)責(zé)接收請(qǐng)求,然后均勻發(fā)送到后端的某個(gè)pod的端口上,這個(gè)過程默認(rèn)采用round robin負(fù)載均衡算法。另外,kubernetes也提供通過修改service的service.spec.sessionAffinity參數(shù)的值來實(shí)現(xiàn)會(huì)話保持特性的定向發(fā)送,如果設(shè)置的值為“clientIP”,那么則將來來自同一個(gè)clientIP的請(qǐng)求都轉(zhuǎn)發(fā)到同一個(gè)后端的pod上。
? ? 此外,service的clusterIP和nodePort等概念是kube-proxy服務(wù)通過Iptables的NAT轉(zhuǎn)換實(shí)現(xiàn)的,kube-proxy在運(yùn)行過程中動(dòng)態(tài)創(chuàng)建于service相關(guān)的Iptable規(guī)則,這些規(guī)則實(shí)現(xiàn)了clusterIP以及nodePort的請(qǐng)求流量重定向到kube-proxy進(jìn)程上對(duì)應(yīng)的服務(wù)的代理端口的功能。由于Iptable機(jī)制針對(duì)的是本地的kube-proxy端口,所有每一個(gè)node上都要運(yùn)行kube-proxy組件,這樣一來,在kubernetes集群內(nèi)部,我們可以在任意node上發(fā)起對(duì)service的訪問。由此看來,由于kube-proxy的作用,在service的調(diào)用過程中客戶端無序關(guān)心后端有幾個(gè)pod,中間過程的通信,負(fù)載均衡以及故障恢復(fù)都是透明。
? ? 目前kube-proxy的負(fù)載均衡只支持round robin算法。round robin算法按照成員列表逐個(gè)選取成員,如果一輪循環(huán)結(jié)束,便從頭開始下一輪循環(huán),如此循環(huán)往復(fù)。Kube-proxy的負(fù)載均衡器在round robin算法得到基礎(chǔ)上還支持session保持。如果service在定義中指定了session保持,則kube-proxy接受請(qǐng)求時(shí)會(huì)從本地內(nèi)存中查找是否存在來自該請(qǐng)求IP的affinitystate對(duì)象,如果存在該對(duì)象,且session沒有超時(shí),則kube-proxy將請(qǐng)求轉(zhuǎn)向該affinitystate所指向的后端的pod。如果本地存在沒有來自該請(qǐng)求IP的affinitystate對(duì)象,則按照round robin算法算法為該請(qǐng)求挑選一個(gè)endpoint,并創(chuàng)建一個(gè)affinitystate對(duì)象,記錄請(qǐng)求的IP和指向的endpoint。后面請(qǐng)求就會(huì)“黏連”到這個(gè)創(chuàng)建好的affinitystate對(duì)象上,這就實(shí)現(xiàn)了客戶端IP會(huì)話保持的功能。
? ?kube-proxy通過查詢和監(jiān)聽API Server中service與endpoint的變換,為每一個(gè)service都建立一個(gè)“服務(wù)代理對(duì)象“,并自動(dòng)同步。服務(wù)代理對(duì)相關(guān)是kube-proxy程序內(nèi)部的一種數(shù)據(jù)結(jié)構(gòu),它包括一個(gè)用于監(jiān)聽此務(wù)請(qǐng)求的socketServer, socketServer的端口是隨機(jī)指定的是本地一個(gè)空閑端口。此外,kube-proxy內(nèi)部也創(chuàng)建了一個(gè)負(fù)載均衡器—loadBalancer, loadBalancer上保存了service到對(duì)應(yīng)的后端endpoint列表的動(dòng)態(tài)路由轉(zhuǎn)發(fā)表,而具體的路由選擇則取決于round robin算法和service的session會(huì)話保持。
? ?針對(duì)發(fā)生變化的service列表,kube-proxy會(huì)逐個(gè)處理,下面是具體的處理流程:
? ?- 如果service沒有設(shè)置集群IP,這不做任何處理,否則,獲取該service的所有端口定義列表
? ?- 逐個(gè)讀取服務(wù)端口定義列表中的端口信息,根據(jù)端口名稱、service名稱和namespace判斷本地是否已經(jīng)存在對(duì)應(yīng)的服務(wù)代理對(duì)象,如果不存在則創(chuàng)建,如果存在并且service端口被修改過,則先刪除Iptables中和該service端口相關(guān)的規(guī)則,關(guān)閉服務(wù)代理對(duì)象,然后走新建流程并為該service創(chuàng)建相關(guān)的Iptables規(guī)則
? ?- 更新負(fù)載均衡組件中對(duì)應(yīng)service的轉(zhuǎn)發(fā)地址列表,對(duì)于新建的service,確定轉(zhuǎn)發(fā)時(shí)的會(huì)話保持策略
? ?- 對(duì)于已刪除的service則進(jìn)行清理
接下來小編通過一個(gè)具體的案例,實(shí)際的給大家介紹一下kube-proxy的原理:
#首先創(chuàng)建一個(gè)service:
apiVersion: v1
kind: Service
metadata:
labels:
name: mysql
role: service
name: mysql-service
spec:
ports:
- port: 3306
targetPort: 3306
nodePort: 30964
type: NodePort
selector:
mysql-service: "true"
? ?mysql-service對(duì)應(yīng)的nodePort暴露出來的端口為30964,對(duì)應(yīng)的cluster IP(10.254.162.44)的端口為3306,進(jìn)一步對(duì)應(yīng)于后端的pod的端口為3306。這里的暴露出來的30964也就是為mysql-service服務(wù)創(chuàng)建的代理對(duì)象在本地的端口,在ndoe上訪問該端口,則會(huì)將路由轉(zhuǎn)發(fā)到service上。
? ?mysql-service后端代理了兩個(gè)pod,ip分別是192.168.125.129和192.168.125.131。先來看一下iptables。
[root@localhost ~]# iptables -S -t nat
首先如果是通過node的30964端口訪問,則會(huì)進(jìn)入到以下鏈:
-A KUBE-NODEPORTS -p tcp -m comment --comment "default/mysql-service:" -m tcp --dport 30964 -j KUBE-MARK-MASQ
-A KUBE-NODEPORTS -p tcp -m comment --comment "default/mysql-service:" -m tcp --dport 30964 -j KUBE-SVC-67RL4FN6JRUPOJYM
然后進(jìn)一步跳轉(zhuǎn)到KUBE-SVC-67RL4FN6JRUPOJYM的鏈
-A KUBE-SVC-67RL4FN6JRUPOJYM -m comment --comment "default/mysql-service:" -m statistic --mode random --probability 0.50000000000 -j KUBE-SEP-ID6YWIT3F6WNZ47P
-A KUBE-SVC-67RL4FN6JRUPOJYM -m comment --comment "default/mysql-service:" -j KUBE-SEP-IN2YML2VIFH5RO2T
這里利用了iptables的--probability的特性,使連接有50%的概率進(jìn)入到KUBE-SEP-ID6YWIT3F6WNZ47P鏈,50%的概率進(jìn)入到KUBE-SEP-IN2YML2VIFH5RO2T鏈。
KUBE-SEP-ID6YWIT3F6WNZ47P的鏈的具體作用就是將請(qǐng)求通過DNAT發(fā)送到192.168.125.129的3306端口。
-A KUBE-SEP-ID6YWIT3F6WNZ47P -s 192.168.125.129/32 -m comment --comment "default/mysql-service:" -j KUBE-MARK-MASQ
-A KUBE-SEP-ID6YWIT3F6WNZ47P -p tcp -m comment --comment "default/mysql-service:" -m tcp -j DNAT --to-destination 192.168.125.129:3306
同理KUBE-SEP-IN2YML2VIFH5RO2T的作用是通過DNAT發(fā)送到192.168.125.131的3306端口。
-A KUBE-SEP-IN2YML2VIFH5RO2T -s 192.168.125.131/32 -m comment --comment "default/mysql-service:" -j KUBE-MARK-MASQ
-A KUBE-SEP-IN2YML2VIFH5RO2T -p tcp -m comment --comment "default/mysql-service:" -m tcp -j DNAT --to-destination 192.168.125.131:3306
? ?總的來說就是:在創(chuàng)建service時(shí),如果不指定nodePort則為其創(chuàng)建代理對(duì)象時(shí)代理對(duì)象再本地監(jiān)聽一個(gè)隨機(jī)的空閑端口,如果設(shè)置了nodePort則以nodePort為本地代理對(duì)象的端口。客戶端在訪問本地代理對(duì)象的端口后此時(shí)會(huì)根據(jù)iptables轉(zhuǎn)發(fā)規(guī)則,將請(qǐng)求轉(zhuǎn)發(fā)到service的clusterIP+port上,然后根據(jù)負(fù)載均衡策略指定的轉(zhuǎn)發(fā)規(guī)則,將請(qǐng)求再次轉(zhuǎn)發(fā)到后端的endpoint的target Port上,最終訪問到具體pod中容器的應(yīng)用服務(wù),然后將響應(yīng)返回。
文章內(nèi)容參考至《kubernetes權(quán)威指南》
免責(zé)聲明:本站發(fā)布的內(nèi)容(圖片、視頻和文字)以原創(chuàng)、轉(zhuǎn)載和分享為主,文章觀點(diǎn)不代表本網(wǎng)站立場,如果涉及侵權(quán)請(qǐng)聯(lián)系站長郵箱:is@yisu.com進(jìn)行舉報(bào),并提供相關(guān)證據(jù),一經(jīng)查實(shí),將立刻刪除涉嫌侵權(quán)內(nèi)容。