Kubernetes应用部署模型解析(原理篇)
2019獨角獸企業(yè)重金招聘Python工程師標準>>>
Kubernetes應用部署模型解析(原理篇) 博客分類: Kubernetes【編者按】Kubernetes可用來管理Linux容器集群,加速開發(fā)和簡化運維(即DevOps)。但目前網(wǎng)絡上關于Kubernetes的文章介紹性遠多于實際使用。本系列文章著眼于實際部署,帶您快速掌握Kubernetes。本文為上篇,主要介紹部署之前需要了解的原理和概念,包括Kubernetes的組件結構,各個組件角色的功能,以及Kubernetes的應用模型等。
十多年來Google一直在生產(chǎn)環(huán)境中使用容器運行業(yè)務,負責管理其容器集群的系統(tǒng)就是Kubernetes的前身Borg。其實現(xiàn)在很多工作在Kubernetes項目上的Google開發(fā)者先前就在Borg這個項目上工作。多數(shù)Kubernetes的應用部署模型的思想都起源于Borg,了解這些模型是掌握Kubernetes的關鍵。Kubernetes的API版本目前是v1,本文以代碼0.18.2版為基礎來介紹它的應用部署模型,最后我們用一個簡單的用例來說明部署過程。在部署結束后,闡述了它是如何用Iptables規(guī)則來實現(xiàn)各種類型Service的。
?
Kubernetes架構
?
Kubernetes集群包括Kubernetes代理(agents )和Kubernetes服務(master node)兩種角色,代理角色的組件包括Kube-proxy?和Kubelet,它們同時部署在一個節(jié)點上,這個節(jié)點也就是代理節(jié)點。服務角色的組件包括kube-apiserver,kube-scheduler,kube-controller-manager,它們可以任意布屬,它們可以部署在同一個節(jié)點上,也可以部署在不同的節(jié)點上(目前版本好像不行)。Kubernetes集群依賴的第三方組件目前有etcd和docker兩個。前者提供狀態(tài)存儲,二者用來管理容器。集群還可以使用分布式存儲給容器提供存儲空間。下圖顯示了目前系統(tǒng)的組成部分:
?
Kubernetes代理節(jié)點
Kubelet和Kube-proxy運行在代理節(jié)點上。他們監(jiān)聽服務節(jié)點的信息來啟動容器和實現(xiàn)Kubernetes網(wǎng)絡和其它業(yè)務模型,比如Service、Pod等。當然每個代理節(jié)點都運行Docker。Docker負責下載容器鏡像和運行容器。
?
?
Kubelet
?
Kubelet組件管理Pods和它們的容器,鏡像和卷等信息。
?
Kube-Proxy
Kube-proxy是一個簡單的網(wǎng)絡代理和負載均衡器。它具體實現(xiàn)Service模型,每個Service都會在所有的Kube-proxy節(jié)點上體現(xiàn)。根據(jù)Service的selector所覆蓋的Pods, Kube-proxy會對這些Pods做負載均衡來服務于Service的訪問者。
?
?
Kubernetes服務節(jié)點
Kubernetes服務組件形成了Kubernetes的控制平面,目前他們運行在單一節(jié)點上,但是將來會分開來部署,以支持高可用性。
?
?
etcd
所有的持久性狀態(tài)都保存在etcd中。Etcd同時支持watch,這樣組件很容易得到系統(tǒng)狀態(tài)的變化,從而快速響應和協(xié)調(diào)工作。
?
?
Kubernetes API Server
這個組件提供對API的支持,響應REST操作,驗證API模型和更新etcd中的相應對象。
?
?
Scheduler
通過訪問Kubernetes中/binding API, Scheduler負責Pods在各個節(jié)點上的分配。Scheduler是插件式的,Kubernetes將來可以支持用戶自定義的scheduler。
?
?
Kubernetes Controller Manager Server
Controller Manager Server負責所有其它的功能,比如endpoints控制器負責Endpoints對象的創(chuàng)建,更新。node控制器負責節(jié)點的發(fā)現(xiàn),管理和監(jiān)控。將來可能會把這些控制器拆分并且提供插件式的實現(xiàn)。
?
?
Kubernetes模型
Kubernetes的偉大之處就在于它的應用部署模型,主要包括Pod、Replication controller、Label和Service。
?
?
Pod
Kubernetes的最小部署單元是Pod而不是容器。作為First class API公民,Pods能被創(chuàng)建,調(diào)度和管理。簡單地來說,像一個豌豆莢中的豌豆一樣,一個Pod中的應用容器同享同一個上下文:
?
?
?
從生命周期來說,Pod應該是短暫的而不是長久的應用。 Pods被調(diào)度到節(jié)點,保持在這個節(jié)點上直到被銷毀。當節(jié)點死亡時,分配到這個節(jié)點的Pods將會被刪掉。將來可能會實現(xiàn)Pod的遷移特性。在實際使用時,我們一般不直接創(chuàng)建Pods, 我們通過replication controller來負責Pods的創(chuàng)建,復制,監(jiān)控和銷毀。一個Pod可以包括多個容器,他們直接往往相互協(xié)作完成一個應用功能。
?
Replication controller
復制控制器確保Pod的一定數(shù)量的份數(shù)(replica)在運行。如果超過這個數(shù)量,控制器會殺死一些,如果少了,控制器會啟動一些。控制器也會在節(jié)點失效、維護的時候來保證這個數(shù)量。所以強烈建議即使我們的份數(shù)是1,也要使用復制控制器,而不是直接創(chuàng)建Pod。
?
在生命周期上講,復制控制器自己不會終止,但是跨度不會比Service強。Service能夠橫跨多個復制控制器管理的Pods。而且在一個Service的生命周期內(nèi),復制控制器能被刪除和創(chuàng)建。Service和客戶端程序是不知道復制控制器的存在的。
復制控制器創(chuàng)建的Pods應該是可以互相替換的和語義上相同的,這個對無狀態(tài)服務特別合適。
Pod是臨時性的對象,被創(chuàng)建和銷毀,而且不會恢復。復制器動態(tài)地創(chuàng)建和銷毀Pod。雖然Pod會分配到IP地址,但是這個IP地址都不是持久的。這樣就產(chǎn)生了一個疑問:外部如何消費Pod提供的服務呢?
?
Service
Service定義了一個Pod的邏輯集合和訪問這個集合的策略。集合是通過定義Service時提供的Label選擇器完成的。舉個例子,我們假定有3個Pod的備份來完成一個圖像處理的后端。這些后端備份邏輯上是相同的,前端不關心哪個后端在給它提供服務。雖然組成這個后端的實際Pod可能變化,前端客戶端不會意識到這個變化,也不會跟蹤后端。Service就是用來實現(xiàn)這種分離的抽象。
?
對于Service,我們還可以定義Endpoint,Endpoint把Service和Pod動態(tài)地連接起來。
?
Service Cluster IP和 kuber proxy
每個代理節(jié)點都運行了一個kube-proxy進程。這個進程從服務進程那邊拿到Service和Endpoint對象的變化。 對每一個Service, 它在本地打開一個端口。 到這個端口的任意連接都會代理到后端Pod集合中的一個Pod IP和端口。在創(chuàng)建了服務后,服務Endpoint模型會體現(xiàn)后端Pod的 IP和端口列表,kube-proxy就是從這個endpoint維護的列表中選擇服務后端的。另外Service對象的sessionAffinity屬性也會幫助kube-proxy來選擇哪個具體的后端。缺省情況下,后端Pod的選擇是隨機的。可以設置service.spec.sessionAffinity?成"ClientIP"來指定同一個ClientIP的流量代理到同一個后端。在實現(xiàn)上,kube-proxy會用IPtables規(guī)則把訪問Service的Cluster IP和端口的流量重定向到這個本地端口。下面的部分會講什么是service的Cluster IP。
?
注意:在0.18以前的版本中Cluster IP叫PortalNet IP。
?
內(nèi)部使用者的服務發(fā)現(xiàn)
Kubernetes在一個集群內(nèi)創(chuàng)建的對象或者在代理集群節(jié)點上發(fā)出訪問的客戶端我們稱之為內(nèi)部使用者。要把服務暴露給內(nèi)部使用者,Kubernetes支持兩種方式:環(huán)境變量和DNS。
?
?
環(huán)境變量
當kubelet在某個節(jié)點上啟動一個Pod時,它會給這個Pod的容器為當前運行的Service設置一系列環(huán)境變量,這樣Pod就可以訪問這些Service了。一般地情況是{SVCNAME}_SERVICE_HOSTh和{SVCNAME}_SERVICE_PORT變量, 其中{SVCNAME}是Service名字變成大寫,中劃線變成下劃線。比如Service "redis-master",它的端口是 TCP? 6379,分配到的Cluster IP地址是 10.0.0.11,kubelet可能會產(chǎn)生下面的變量給新創(chuàng)建的Pod容器:
?
REDIS_MASTER_SERVICE_HOST=?10.0.0.11
REDIS_MASTER_SERVICE_PORT=6379
REDIS_MASTER_PORT=tcp://10.0.0.11:6379
REDIS_MASTER_PORT_6379_TCP=tcp://10.0.0.11:6379
REDIS_MASTER_PORT_6379_TCP_PROTO=tcp
REDIS_MASTER_PORT_6379_TCP_PORT=6379
REDIS_MASTER_PORT_6379_TCP_ADDR=?10.0.0.11
注意,只有在某個Service后創(chuàng)建的Pod才會有這個Service的環(huán)境變量。
?
DNS
一個可選的Kubernetes附件(強烈建議用戶使用)是DNS服務。它跟蹤集群中Service對象,為每個Service對象創(chuàng)建DNS記錄。這樣所有的Pod就可以通過DNS訪問服務了。
?
比如說我們在Kubernetes 名字空間"my-ns"中有個叫my-service的服務,DNS服務會創(chuàng)建一條"my-service.my-ns"的DNS記錄。同在這個命名空間的Pod就可以通過"my-service"來得到這個Service分配到的Cluster IP,在其它命名空間的Pod則可以用全限定名"my-service.my-ns"來獲得這個Service的地址。
?
Pod IP and Service Cluster?IP
Pod IP 地址是實際存在于某個網(wǎng)卡(可以是虛擬設備)上的,但Service Cluster IP就不一樣了,沒有網(wǎng)絡設備為這個地址負責。它是由kube-proxy使用Iptables規(guī)則重新定向到其本地端口,再均衡到后端Pod的。我們前面說的Service環(huán)境變量和DNS都使用Service的Cluster IP和端口。
?
就拿上面我們提到的圖像處理程序為例。當我們的Service被創(chuàng)建時,Kubernetes給它分配一個地址10.0.0.1。這個地址從我們啟動API的service-cluster-ip-range參數(shù)(舊版本為portal_net參數(shù))指定的地址池中分配,比如--service-cluster-ip-range=10.0.0.0/16。假設這個Service的端口是1234。集群內(nèi)的所有kube-proxy都會注意到這個Service。當proxy發(fā)現(xiàn)一個新的service后,它會在本地節(jié)點打開一個任意端口,建相應的iptables規(guī)則,重定向服務的IP和port到這個新建的端口,開始接受到達這個服務的連接。
當一個客戶端訪問這個service時,這些iptable規(guī)則就開始起作用,客戶端的流量被重定向到kube-proxy為這個service打開的端口上,kube-proxy隨機選擇一個后端pod來服務客戶。這個流程如下圖所示:
根據(jù)Kubernetes的網(wǎng)絡模型,使用Service Cluster IP和Port訪問Service的客戶端可以坐落在任意代理節(jié)點上。外部要訪問Service,我們就需要給Service外部訪問IP。
?
外部訪問Service
Service對象在Cluster IP range池中分配到的IP只能在內(nèi)部訪問,如果服務作為一個應用程序內(nèi)部的層次,還是很合適的。如果這個Service作為前端服務,準備為集群外的客戶提供業(yè)務,我們就需要給這個服務提供公共IP了。
?
外部訪問者是訪問集群代理節(jié)點的訪問者。為這些訪問者提供服務,我們可以在定義Service時指定其spec.publicIPs,一般情況下publicIP 是代理節(jié)點的物理IP地址。和先前的Cluster IP range上分配到的虛擬的IP一樣,kube-proxy同樣會為這些publicIP提供Iptables 重定向規(guī)則,把流量轉發(fā)到后端的Pod上。有了publicIP,我們就可以使用load balancer等常用的互聯(lián)網(wǎng)技術來組織外部對服務的訪問了。
spec.publicIPs在新的版本中標記為過時了,代替它的是spec.type=NodePort,這個類型的service,系統(tǒng)會給它在集群的各個代理節(jié)點上分配一個節(jié)點級別的端口,能訪問到代理節(jié)點的客戶端都能訪問這個端口,從而訪問到服務。
?
Label和Label selector
Label標簽在Kubernetes模型中占著非常重要的作用。Label表現(xiàn)為key/value對,附加到Kubernetes管理的對象上,典型的就是Pods。它們定義了這些對象的識別屬性,用來組織和選擇這些對象。Label可以在對象創(chuàng)建時附加在對象上,也可以對象存在時通過API管理對象的Label。
?
在定義了對象的Label后,其它模型可以用Label 選擇器(selector)來定義其作用的對象。
Label選擇器有兩種,分別是Equality-based和Set-based。
比如如下Equality-based選擇器樣例:
?
environment = production tier != frontend environment = production,tier != frontend?
對于上面的選擇器,第一條匹配Label具有environment key且等于production的對象,第二條匹配具有tier key,但是值不等于frontend的對象。由于kubernetes使用AND邏輯,第三條匹配production但不是frontend的對象。
Set-based選擇器樣例:
?
environment in (production, qa) tier notin (frontend, backend) partition?
第一條選擇具有environment key,而且值是production或者qa的label附加的對象。第二條選擇具有tier key,但是其值不是frontend和backend。第三條選則具有partition key的對象,不對value進行校驗。
replication controller復制控制器和Service都用label和label selctor來動態(tài)地配備作用對象。復制控制器在定義的時候就指定了其要創(chuàng)建Pod的Label和自己要匹配這個Pod的selector,?API服務器應該校驗這個定義。我們可以動態(tài)地修改replication controller創(chuàng)建的Pod的Label用于調(diào)式,數(shù)據(jù)恢復等。一旦某個Pod由于Label改變從replication controller移出來后,replication controller會馬上啟動一個新的Pod來確保復制池子中的份數(shù)。對于Service,Label selector可以用來選擇一個Service的后端Pods。
?
http://www.csdn.net/article/2015-06-11/2824933
轉載于:https://my.oschina.net/xiaominmin/blog/1598568
總結
以上是生活随笔為你收集整理的Kubernetes应用部署模型解析(原理篇)的全部內(nèi)容,希望文章能夠幫你解決所遇到的問題。
- 上一篇: 21天实战人工智能系列:人工智能产品经理
- 下一篇: 在Kubernetes Pod中使用Se