自拍偷在线精品自拍偷,亚洲欧美中文日韩v在线观看不卡

架構(gòu)解密從分布式到微服務(wù):深入Kubernetes微服務(wù)平臺(tái)

新聞 架構(gòu) 分布式
架構(gòu)師普遍有這樣的愿景:在系統(tǒng)中有ServiceA、ServiceB、ServiceC這3種服務(wù),其中ServiceA需要部署3個(gè)實(shí)例,ServiceB與ServiceC各自需要部署5個(gè)實(shí)例,希望有一個(gè)平臺(tái)(或工具)自動(dòng)完成上述13個(gè)實(shí)例的分布式部署,并且持續(xù)監(jiān)控它們。

 深入Kubernetes微服務(wù)平臺(tái)

Kubernetes的概念與功能

架構(gòu)師普遍有這樣的愿景:在系統(tǒng)中有ServiceA、ServiceB、ServiceC這3種服務(wù),其中ServiceA需要部署3個(gè)實(shí)例,ServiceB與ServiceC各自需要部署5個(gè)實(shí)例,希望有一個(gè)平臺(tái)(或工具)自動(dòng)完成上述13個(gè)實(shí)例的分布式部署,并且持續(xù)監(jiān)控它們。當(dāng)發(fā)現(xiàn)某個(gè)服務(wù)器宕機(jī)或者某個(gè)服務(wù)實(shí)例發(fā)生故障時(shí),平臺(tái)能夠自我修復(fù),從而確保在任何時(shí)間點(diǎn)正在運(yùn)行的服務(wù)實(shí)例的數(shù)量都符合預(yù)期。這樣一來(lái),團(tuán)隊(duì)只需關(guān)注服務(wù)開發(fā)本身,無(wú)須再為基礎(chǔ)設(shè)施和運(yùn)維監(jiān)控的事情頭疼了。

架構(gòu)解密從分布式到微服務(wù):深入Kubernetes微服務(wù)平臺(tái)

在 Kubernetes出現(xiàn)之前,沒(méi)有一個(gè)平臺(tái)公開聲稱實(shí)現(xiàn)了上面的愿景。Kubernetes是業(yè)界第一個(gè)將服務(wù)這個(gè)概念真正提升到第一位的平臺(tái)。在Kubernetes的世界里,所有概念與組件都是圍繞Service運(yùn)轉(zhuǎn)的。正是這種突破性的設(shè)計(jì),使Kubernetes真正解決了多年來(lái)困擾我們的分布式系統(tǒng)里的眾多難題,讓團(tuán)隊(duì)有更多的時(shí)間去關(guān)注與業(yè)務(wù)需求和業(yè)務(wù)相關(guān)的代碼本身,從而在很大程度上提高整個(gè)軟件團(tuán)隊(duì)的工作效率與投入產(chǎn)出比。

Kubernetes里的Service其實(shí)就是微服務(wù)架構(gòu)中微服務(wù)的概念,它有以下明顯特點(diǎn)。

  • 每個(gè)Service都分配了一個(gè)固定不變的虛擬IP地址——Cluster IP。
  • 每個(gè)Service都以TCP/UDP方式在一個(gè)或多個(gè)端口 (Service Port)上提供服務(wù)。
  • 客戶端訪問(wèn)一個(gè) Service時(shí),就好像訪問(wèn)一個(gè)遠(yuǎn)程的TCP/UDP服務(wù),只要與Cluster IP建立連接即可,目標(biāo)端口就是某個(gè)Service Port。

Service既然有了IP地址,就可以順理成章地采用DNS域名的方式來(lái)避免IP地址的變動(dòng)了。Kubernetes 的 DNS組件自動(dòng)為每個(gè)Service都建立了一個(gè)域名與IP的映射表,其中的域名就是Service的Name,IP就是對(duì)應(yīng)的Cluster IP,并且在Kubernetes的每個(gè)Pod(類似于Docker'容器)里都設(shè)置了DNS Server為 Kubernetes 的 DNS Server,這樣一來(lái),微服務(wù)架構(gòu)中的服務(wù)發(fā)現(xiàn)這個(gè)基本問(wèn)題得以巧妙解決,不但不用復(fù)雜的服務(wù)發(fā)現(xiàn)API供客戶端調(diào)用,還使所有以TCP/IP方式通信的分布式系統(tǒng)都能方便地遷移到Kubernetes平臺(tái)上,僅從這個(gè)設(shè)計(jì)來(lái)看,Kubernetes就遠(yuǎn)勝過(guò)其他產(chǎn)品。

我們知道,在每個(gè)微服務(wù)的背后都有多個(gè)進(jìn)程實(shí)例來(lái)提供服務(wù),在Kubernetes平臺(tái)上,這些進(jìn)程實(shí)例被封裝在Pod中,Pod基本上等同于Docker容器,稍有不同的是,Pod其實(shí)是一組密切捆綁在一起并且“同生共死”的 Docker 容器,這組容器共享同一個(gè)網(wǎng)絡(luò)棧與文件系統(tǒng),相互之間沒(méi)有隔離,可以直接在進(jìn)程間通信。最典型的例子是Kubenetes Sky DNS Pod,在這個(gè)Pod里有4個(gè)Docker '容器。

那么,Kubernetes里的 Service 與 Pod 是如何對(duì)應(yīng)的呢?我們?cè)趺粗滥男㏄od 為某個(gè)Service提供具體的服務(wù)?下圖給出了答案——“貼標(biāo)簽”。

架構(gòu)解密從分布式到微服務(wù):深入Kubernetes微服務(wù)平臺(tái)

每個(gè)Pod都可以貼一個(gè)或多個(gè)不同的標(biāo)簽(Label),而每個(gè)Service都有一個(gè)“標(biāo)簽選擇器”(Label Selector),標(biāo)簽選擇器確定了要選擇擁有哪些標(biāo)簽的對(duì)象。下面這段YAML格式的內(nèi)容定義了一個(gè)被稱為ku8-redis-master的Service,它的標(biāo)簽選擇器的內(nèi)容為“app: ku8-redis-master",表明擁有“app= ku8-redis-master”這個(gè)標(biāo)簽的Pod都是為它服務(wù)的:

  1. apiversion: v1 
  2. kind: Service 
  3. metadata: 
  4. name: ku8-redis-masterspec: 
  5. ports: 
  6. - port: 6379selector: 
  7. app: ku8-redis-master 

下面是 ku8-redis-master這個(gè) Pod 的定義,它的 labels屬性的內(nèi)容剛好匹配Service 的標(biāo)簽選擇器的內(nèi)容:

  1. apiversion: v1kind: Pod 
  2. metadata: 
  3. name: ku8-redis-masterlabels: 
  4. app: ku8-redis-master 
  5. spec: 
  6. containers: 
  7. name: serverimage: redisports: 
  8. -containerPort:6379 
  9. restartPolicy: Never 

如果我們需要一個(gè)Service在任意時(shí)刻都有N個(gè)Pod實(shí)例來(lái)提供服務(wù),并且在其中1個(gè)Pod實(shí)例發(fā)生故障后,及時(shí)發(fā)現(xiàn)并且自動(dòng)產(chǎn)生一個(gè)新的Pod實(shí)例以彌補(bǔ)空缺,那么我們要怎么做呢?答案就是采用 Deployment/RC,它的作用是告訴Kubernetes,擁有某個(gè)特定標(biāo)簽的 Pod需要在Kubernetes集群中創(chuàng)建幾個(gè)副本實(shí)例。Deployment/RC的定義包括如下兩部分內(nèi)容。

●目標(biāo)Pod的副本數(shù)量(replicas)。

●目標(biāo)Pod的創(chuàng)建模板(Template)。

下面這個(gè)例子定義了一個(gè)RC,目標(biāo)是確保在集群中任意時(shí)刻都有兩個(gè) Pod,其標(biāo)簽為“ app:ku8-redis-slave”,對(duì)應(yīng)的容器鏡像為redis slave,這兩個(gè) Pod 與ku8-redis-master構(gòu)成了Redis主從集群(一主二從):

  1. apiversion :v1 
  2. kind: ReplicationControllermetadata: 
  3. name: ku8-redis-slavespec: 
  4. replicas: 2template: 
  5. metadata: 
  6. labels: 
  7. app: ku8-redis-slavespec: 
  8. containers: 
  9. name: server 
  10. image: devopsbq/redis-slave 
  11. env: 
  12. name: MASTER ADDR 
  13. value: ku8-redis-masterports: 
  14. -containerPort:6379 

至此,上述YAML文件創(chuàng)建了一個(gè)一主二從的Redis集群,其中Redis Master被定義為一個(gè)微服務(wù),可以被其他Pod或 Service訪問(wèn),如下圖所示。

架構(gòu)解密從分布式到微服務(wù):深入Kubernetes微服務(wù)平臺(tái)

注意上圖在 ku8-reids-slave的容器中有MASTER_ADDR的環(huán)境變量,這是Redis Master 的地址,這里填寫的是“ku8-redis-master”,它是Redis Master Service 的名稱,之前說(shuō)過(guò):Service的名稱就是它的DNS域名,所以Redis Slave容器可以通過(guò)這個(gè)DNS與Redis Master Service進(jìn)行通信,以實(shí)現(xiàn)Redis 主從同步功能。

Kubernetes 的核心概念就是Service、Pod 及 RC/Deployment。圍繞著這三個(gè)核心概念,Kubernetes實(shí)現(xiàn)了有史以來(lái)最強(qiáng)大的基于容器技術(shù)的微服務(wù)架構(gòu)平臺(tái)。比如,在上述Redis集群中,如果我們希望組成一主三從的集群,則只要將控制Redis Slave的 ReplicationController中的replicas改為3,或者用kubectrl scale命令行功能實(shí)現(xiàn)擴(kuò)容即可。命令如下,我們發(fā)現(xiàn),服務(wù)的水平擴(kuò)容變得如此方便:

  1. kubectl scale --replicas=3 rc/ku8-redis-slave 

不僅如此,Kubernetes還實(shí)現(xiàn)了水平自動(dòng)擴(kuò)容的高級(jí)特性——HPA ( Horizontal PodAutoscaling ),其原理是基于Pod 的性能度量參數(shù)(CPU utilization和 custom metrics)對(duì)RC/Deployment管理的Pod進(jìn)行自動(dòng)伸縮。舉個(gè)例子,假如我們認(rèn)為上述Redis Slave集群對(duì)應(yīng)的Pod也對(duì)外提供查詢服務(wù),服務(wù)期間Pod的 CPU利用率會(huì)不斷變化,在這些Pod 的CPU平均利用率超過(guò)80%后,就會(huì)自動(dòng)擴(kuò)容,直到CPU利用率下降到80%以下或者最多達(dá)到5個(gè)副本位置,而在請(qǐng)求的壓力減小后,Pod的副本數(shù)減少為1個(gè),用下面的HPA命令即可實(shí)現(xiàn)這一目標(biāo):

  1. kubectl autoscale rc ku8-redis-slave --min=1 --max=5 --cpu-percent=80 

除了很方便地實(shí)現(xiàn)微服務(wù)的水平擴(kuò)容功能,Kubernetes還提供了使用簡(jiǎn)單、功能強(qiáng)大的微服務(wù)滾動(dòng)升級(jí)功能(rolling update),只要一個(gè)簡(jiǎn)單的命令即可快速完成任務(wù)。舉個(gè)例子,假如我們要將上述Redis Slave服務(wù)的鏡像版本從devopsbq/redis-slave升級(jí)為leader/redis-slave,則只要執(zhí)行下面這條命令即可:

  1. kubectl rolling-update ku8-redis-slave --image=leader/redis-slave 

滾動(dòng)升級(jí)的原理如下圖所示,Kubernetes在執(zhí)行滾動(dòng)升級(jí)的過(guò)程中,會(huì)創(chuàng)建一個(gè)新的RC,這個(gè)新的RC使用了新的Pod鏡像,然后Kubernetes每隔一段時(shí)間就將舊RC的replicas數(shù)減少一個(gè),導(dǎo)致舊版本的Pod副本數(shù)減少一個(gè),然后將新RC的replicas數(shù)增加一個(gè),于是多出一個(gè)新版本的Pod副本,在升級(jí)的過(guò)程中 Pod副本數(shù)基本保持不變,直到最后所有的副本都變成新的版本,升級(jí)才結(jié)束。

架構(gòu)解密從分布式到微服務(wù):深入Kubernetes微服務(wù)平臺(tái)

Kubernetes的組成與原理

Kubernetes集群本身作為一個(gè)分布式系統(tǒng),也采用了經(jīng)典的Master-Slave架構(gòu),如下圖所示,集群中有一個(gè)節(jié)點(diǎn)是Master節(jié)點(diǎn),在其上部署了3個(gè)主要的控制程序:API Sever、ControllerManager 及 Scheduler,還部署了Etcd進(jìn)程,用來(lái)持久化存儲(chǔ)Kubernetes管理的資源對(duì)象(如Service、Pod、RC/Deployment)等。

架構(gòu)解密從分布式到微服務(wù):深入Kubernetes微服務(wù)平臺(tái)

集群中的其他節(jié)點(diǎn)被稱為Node節(jié)點(diǎn),屬于工人(Worker 節(jié)點(diǎn)),它們都由Master 節(jié)點(diǎn)領(lǐng)導(dǎo),主要負(fù)責(zé)照顧各自節(jié)點(diǎn)上分配的Pod副本。下面這張圖更加清晰地表明了Kubernetes各個(gè)進(jìn)程之間的交互關(guān)系。

架構(gòu)解密從分布式到微服務(wù):深入Kubernetes微服務(wù)平臺(tái)

從上圖可以看到,位于中心地位的進(jìn)程是API Server,所有其他進(jìn)程都與它直接交互,其他進(jìn)程之間并不存在直接的交互關(guān)系。那么,APl Server的作用是什么呢?它其實(shí)是Kubernetes的數(shù)據(jù)網(wǎng)關(guān),即所有進(jìn)入Kubernetes 的數(shù)據(jù)都是通過(guò)這個(gè)網(wǎng)關(guān)保存到Etcd數(shù)據(jù)庫(kù)中的,同時(shí)通過(guò)API Server將Eted里變化的數(shù)據(jù)實(shí)時(shí)發(fā)給其他相關(guān)的Kubernetes進(jìn)程。API Server 以REST方式對(duì)外提供接口,這些接口基本上分為以下兩類。

  • 所有資源對(duì)象的CRUD API:資源對(duì)象會(huì)被保存到Etcd中存儲(chǔ)并提供Query接口,比如針對(duì)Pod、Service及RC等的操作。
  • 資源對(duì)象的 Watch API:客戶端用此API來(lái)及時(shí)得到資源變化的相關(guān)通知,比如某個(gè)Service 相關(guān)的Pod實(shí)例被創(chuàng)建成功,或者某個(gè)Pod 狀態(tài)發(fā)生變化等通知,Watch API主要用于Kubernetes 中的高效自動(dòng)控制邏輯。

下面是上圖中其他Kubernetes進(jìn)程的主要功能。

  • controller manager:負(fù)責(zé)所有自動(dòng)化控制事物,比如RC/Deployment的自動(dòng)控制、HPA自動(dòng)水平擴(kuò)容的控制、磁盤定期清理等各種事務(wù)。
  • scheduler:負(fù)責(zé)Pod 的調(diào)度算法,在一個(gè)新的Pod被創(chuàng)建后,Scheduler根據(jù)算法找到最佳 Node節(jié)點(diǎn),這個(gè)過(guò)程也被稱為Pod Binding。
  • kubelet:負(fù)責(zé)本Node節(jié)點(diǎn)上Pod實(shí)例的創(chuàng)建、監(jiān)控、重啟、刪除、狀態(tài)更新、性能采集并定期上報(bào) Pod 及本機(jī) Node節(jié)點(diǎn)的信息給Master節(jié)點(diǎn),由于Pod實(shí)例最終體現(xiàn)為Docker'容器,所以Kubelet還會(huì)與Docker交互。
  • kube-proxy:為 Service的負(fù)載均衡器,負(fù)責(zé)建立Service Cluster IP 到對(duì)應(yīng)的Pod實(shí)例之間的NAT轉(zhuǎn)發(fā)規(guī)則,這是通過(guò)Linux iptables實(shí)現(xiàn)的。

在理解了Kubernetes各個(gè)進(jìn)程的功能后,我們來(lái)看看一個(gè)RC 從YAML定義到最終被部署成多個(gè)Pod 及容器背后所發(fā)生的事情。為了很清晰地說(shuō)明這個(gè)復(fù)雜的流程,這里給出一張示意圖。

架構(gòu)解密從分布式到微服務(wù):深入Kubernetes微服務(wù)平臺(tái)

首先,在我們通過(guò)kubectrl create命令創(chuàng)建一個(gè)RC(資源對(duì)象)時(shí),kubectrl通過(guò)Create RC這個(gè)REST接口將數(shù)據(jù)提交到APl Server,隨后API Server將數(shù)據(jù)寫入Etcd里持久保存。與此同時(shí),Controller Manager監(jiān)聽(tīng)(Watch)所有RC,一旦有RC被寫入Etcd中,Controller Manager就得到了通知,它會(huì)讀取RC的定義,然后比較在RC中所控制的Pod 的實(shí)際副本數(shù)與期待值的差異,然后采取對(duì)應(yīng)的行動(dòng)。此刻,Controller Manager 發(fā)現(xiàn)在集群中還沒(méi)有對(duì)應(yīng)的Pod實(shí)例,就根據(jù)RC里的Pod模板(Template)定義,創(chuàng)建一個(gè)Pod并通過(guò)API Server保存到Etcd中。類似地,Scheduler進(jìn)程監(jiān)聽(tīng)所有 Pod,一旦發(fā)現(xiàn)系統(tǒng)產(chǎn)生了一個(gè)新生的Pod,就開始執(zhí)行調(diào)度邏輯,為該P(yáng)od 安排一個(gè)新家(Node),如果一切順利,該P(yáng)od就被安排到某個(gè)Node節(jié)點(diǎn)上,即Binding to a Node。接下來(lái),Scheduler進(jìn)程就把這個(gè)信息及 Pod狀態(tài)更新到Etcd里,最后,目標(biāo)Node節(jié)點(diǎn)上的Kubelet監(jiān)聽(tīng)到有新的Pod被安排到自己這里來(lái)了,就按照Pod里的定義,拉取容器的鏡像并且創(chuàng)建對(duì)應(yīng)的容器。在容器成功創(chuàng)建后,Kubelet進(jìn)程再把 Pod的狀態(tài)更新為Running 并通過(guò)API Server更新到 Etcd 中。如果此 Pod還有對(duì)應(yīng)的Service,每個(gè)Node上的Kube-proxy進(jìn)程就會(huì)監(jiān)聽(tīng)所有Service及這些Service對(duì)應(yīng)的Pod實(shí)例的變化,一旦發(fā)現(xiàn)有變化,就會(huì)在所在 Node節(jié)點(diǎn)上的 iptables 里增加或者刪除對(duì)應(yīng)的NAT轉(zhuǎn)發(fā)規(guī)則,最終實(shí)現(xiàn)了Service的智能負(fù)載均衡功能,這一切都是自動(dòng)完成的,無(wú)須人工干預(yù)。

那么,如果某個(gè)Node'宕機(jī),則會(huì)發(fā)生什么事情呢?假如某個(gè)Node宕機(jī)一段時(shí)間,則因?yàn)樵诖斯?jié)點(diǎn)上沒(méi)有Kubelet進(jìn)程定時(shí)匯報(bào)這些Pod 的狀態(tài),因此這個(gè)Node 上的所有Pod'實(shí)例都會(huì)被判定為失敗狀態(tài),此時(shí)Controller Manager會(huì)將這些Pod刪除并產(chǎn)生新的Pod實(shí)例,于是這些Pod被調(diào)度到其他 Node 上創(chuàng)建出來(lái),系統(tǒng)自動(dòng)恢復(fù)。

本節(jié)最后說(shuō)說(shuō)Kube-proxy的演變,如下圖所示。

架構(gòu)解密從分布式到微服務(wù):深入Kubernetes微服務(wù)平臺(tái)

Kube-proxy一開始是一個(gè)類似于HAProxy的代理服務(wù)器,實(shí)現(xiàn)了基于軟件的負(fù)載均衡功能,將Client 發(fā)起的請(qǐng)求代理到后端的某個(gè)Pod 上,可以將其理解為Kubernetes Service的負(fù)載均衡器。Kube-proxy最初的實(shí)現(xiàn)機(jī)制是操控 iptables規(guī)則,將訪問(wèn)Cluster IP 的流量通過(guò)NAT方式重定向到本機(jī)的Kube-proxy,在這個(gè)過(guò)程中涉及網(wǎng)絡(luò)報(bào)文從內(nèi)核態(tài)到用戶態(tài)的多次復(fù)制,因此效率不高。Kube-proxy 之后的版本改變了實(shí)現(xiàn)方式,在生成 iptables規(guī)則時(shí),直接NAT 到目標(biāo)Pod地址,不再通過(guò)Kube-proxy進(jìn)行轉(zhuǎn)發(fā),因此效率更高、速度更快,采用這種方式比采用客戶端負(fù)載均衡方式效率稍差一點(diǎn),但編程簡(jiǎn)單,而且與具體的通信協(xié)議無(wú)關(guān),適用范圍更廣。此時(shí),我們可以認(rèn)為Kubernetes Service基于 iptables機(jī)制來(lái)實(shí)現(xiàn)路由和負(fù)載均衡機(jī)制,從此以后,Kube-proxy已不再是一個(gè)真正的“proxy"”,僅僅是路由規(guī)則配置的一個(gè)工具類“代理”。

基于iptables 實(shí)現(xiàn)的路由和負(fù)載均衡機(jī)制雖然在性能方面比普通Proxy提升了很多,但也存在自身的固有缺陷,因?yàn)槊總€(gè)Service都會(huì)產(chǎn)生一定數(shù)量的 iptables 規(guī)則。在Service數(shù)量比較多的情況下,iptables 的規(guī)則數(shù)量會(huì)激增,對(duì)iptables的轉(zhuǎn)發(fā)效率及對(duì)Linux內(nèi)核的穩(wěn)定性都造成一定的沖擊。因此很多人都在嘗試將IPVS(IP虛擬服務(wù)器)代替iptables。Kubernetes 從 1.8版本開始,新增了Kube-proxy對(duì)IPVS的支持,在1.11版本中正式納入 GA。與 iptables 不同, IPVS本身就被定位為L(zhǎng)inux官方標(biāo)準(zhǔn)中TCP/UDP服務(wù)的負(fù)載均衡器解決方案,因此非常適合代替iptables來(lái)實(shí)現(xiàn) Service的路由和負(fù)載均衡。

此外,也有一些機(jī)制來(lái)代替 Kube-proxy,比如Service Mesh 中的 SideCar 完全代替了Kube-proxy的功能。在 Service 都基于HTTP接口的情況下,我們會(huì)有更多的選擇方式,比如Ingress、Nginx 等。

基于Kubernetes 的 PaaS平臺(tái)

PaaS其實(shí)是一個(gè)重量級(jí)但不怎么成功的產(chǎn)品,受限于多語(yǔ)言支持和開發(fā)模式的僵硬,但近期又隨著容器技術(shù)及云計(jì)算的發(fā)展,重新引發(fā)了人們的關(guān)注,這是因?yàn)槿萜骷夹g(shù)徹底解決了應(yīng)用打包部署和自動(dòng)化的難題。基于容器技術(shù)重新設(shè)計(jì)和實(shí)現(xiàn)的PaaS平臺(tái),既提升了平臺(tái)的技術(shù)含量,又很好地彌補(bǔ)了之前PaaS平臺(tái)難用、復(fù)雜、自動(dòng)化水平低等缺點(diǎn)。

OpenShift是由 RedHat公司于2011年推出的PaaS云計(jì)算平臺(tái),在Kubernetes推出之前,OpenShift 就已經(jīng)演變?yōu)閮蓚€(gè)版本(v1與v2),但在 Kubernetes推出之后,OpenShift的第3個(gè)版本v3放棄了自己的容器引擎與容器編排模塊,轉(zhuǎn)而全面擁抱Kubernetes。

Kubernetes 擁有如下特性。

  • Pod(容器)可以讓開發(fā)者將一個(gè)或多個(gè)容器整體作為一個(gè)“原子單元”進(jìn)行部署。
  • 采用固定的Cluster IP及內(nèi)嵌的DNS這種獨(dú)特設(shè)計(jì)思路的服務(wù)發(fā)現(xiàn)機(jī)制,讓不同的Service很容易相互關(guān)聯(lián)(Link)。
  • RC可以保證我們關(guān)注的Pod副本的實(shí)例數(shù)量始終符合我們的預(yù)期。
  • 非常強(qiáng)大的網(wǎng)絡(luò)模型,讓不同主機(jī)上的Pod能夠相互通信。
  • 支持有狀態(tài)服務(wù)與無(wú)狀態(tài)服務(wù),能夠?qū)⒊志没鎯?chǔ)也編排到容器中以支持有狀態(tài)服務(wù)。
  • 簡(jiǎn)單易用的編排模型,讓用戶很容易編排一個(gè)復(fù)雜的應(yīng)用。

國(guó)內(nèi)外已經(jīng)有很多公司采用了Kubernetes作為它們的PaaS平臺(tái)的內(nèi)核,所以本節(jié)講解如何基于Kubernetes 設(shè)計(jì)和實(shí)現(xiàn)一個(gè)強(qiáng)大的 PaaS平臺(tái)。

一個(gè) PaaS平臺(tái)應(yīng)該具備如下關(guān)鍵特性。

  • 多租戶支持:這里的租戶可以是開發(fā)廠商或者應(yīng)用本身。
  • 應(yīng)用的全生命周期管理:比如對(duì)應(yīng)用的定義、部署、升級(jí)、下架等環(huán)節(jié)的支持。
  • 具有完備的基礎(chǔ)服務(wù)設(shè)施:比如單點(diǎn)登錄服務(wù)、基于角色的用戶權(quán)限服務(wù)、應(yīng)用配置服務(wù)、日志服務(wù)等,同時(shí)PaaS平臺(tái)集成了很多常見(jiàn)的中間件以方便應(yīng)用調(diào)用,這些常見(jiàn)的中間件有消息隊(duì)列、分布式文件系統(tǒng)、緩存中間件等。
  • 多語(yǔ)言支持:一個(gè)好的PaaS平臺(tái)可以支持多種常見(jiàn)的開發(fā)語(yǔ)言,例如Java、Node.js、PHP、Python、C++等。

接下來(lái),我們看看基于Kubernetes 設(shè)計(jì)和實(shí)現(xiàn)的PaaS平臺(tái)是如何支持上述關(guān)鍵特性的。

如何實(shí)現(xiàn)多租戶

Kubernetes通過(guò)Namespace特性來(lái)支持多租戶功能。

我們可以創(chuàng)建多個(gè)不同的Namespace資源對(duì)象,每個(gè)租戶都有一個(gè)Namespace,在不同的Namespace下創(chuàng)建的Pod、Service 與RC等資源對(duì)象是無(wú)法在另外一個(gè)Namespace下看到的,于是形成了邏輯上的多租戶隔離特性。但單純的Namespace隔離并不能阻止不同Namespace下的網(wǎng)絡(luò)隔離,如果知道其他Namespace中的某個(gè) Pod的IP地址,則我們還是可以發(fā)起訪問(wèn)的,如下圖所示。

架構(gòu)解密從分布式到微服務(wù):深入Kubernetes微服務(wù)平臺(tái)

針對(duì)多租戶的網(wǎng)絡(luò)隔離問(wèn)題,Kubernetes增加了Network Policy這一特性,我們簡(jiǎn)單地將它類比為網(wǎng)絡(luò)防火墻,通過(guò)定義Network Policy資源對(duì)象,我們可以控制一個(gè)Namespace(租戶)下的Pod被哪些Namespace訪問(wèn)。假如我們有兩個(gè)Namespace,分別為tenant2、tenant3,各自擁有一些Pod,如下圖所示。

架構(gòu)解密從分布式到微服務(wù):深入Kubernetes微服務(wù)平臺(tái)

假如我們需要實(shí)現(xiàn)這些網(wǎng)絡(luò)隔離目標(biāo): tenant3里擁有role:db標(biāo)簽的Pod只能被tenant3(本Namespace中)里擁有role:frontend標(biāo)簽的Pod訪問(wèn),或者被tenent2里的任意Pod訪問(wèn),則我們可以定義如下圖所示的一個(gè)Network Policy資源對(duì)象,并通過(guò)kubectrl工具發(fā)布到Kubernetes集群中生效即可。

架構(gòu)解密從分布式到微服務(wù):深入Kubernetes微服務(wù)平臺(tái)

需要注意的是,Kubernetes Network Policy需要配合特定的CNI網(wǎng)絡(luò)插件才能真正生效,目前支持Network Policy 的CNI 插件主要有以下幾種。

  • Calico:基于三層路由實(shí)現(xiàn)的容器網(wǎng)絡(luò)方案。
  • Weave Net:基于報(bào)文封裝的二層容器解決方案。
  • Romana:類似于Calico的容器網(wǎng)絡(luò)方案。

Network Policy目前也才剛剛起步,還有很多問(wèn)題需要去研究和解決,比如如何定義Service的訪問(wèn)策略?如果Service訪問(wèn)策略與Pod訪問(wèn)策略沖突又該如何解決﹖此外,外部服務(wù)的訪問(wèn)策略又該如何定義?總之,在容器領(lǐng)域,相對(duì)于計(jì)算虛擬化、存儲(chǔ)虛擬化來(lái)說(shuō),網(wǎng)絡(luò)虛擬化中的很多技術(shù)才剛剛起步。

Kubernetes 的 Namespace是從邏輯上隔離不同租戶的程序,但多個(gè)租戶的程序還是可能被調(diào)度到同一個(gè)物理機(jī)(Node)上的,如果我們希望不同租戶的應(yīng)用被調(diào)度到不同的Node 上,從而做到物理上的隔離,則可以通過(guò)集群分區(qū)的方式來(lái)實(shí)現(xiàn)。具體做法是我們先按照租戶將整個(gè)集群劃分為不同的分區(qū)(Partition),如下圖所示,對(duì)每個(gè)分區(qū)里的所有 Node 都打上同樣的標(biāo)簽,比如租戶 a(tanenta)的標(biāo)簽為partition=tenant,租戶 b( tanentb)的標(biāo)簽為partition= tenantb,我們?cè)谡{(diào)度Pod 的時(shí)候可以使用nodeSelector屬性來(lái)指定目標(biāo)Node的標(biāo)簽,比如下面的寫法表示Pod需要被調(diào)度到租戶 a的分區(qū)節(jié)點(diǎn)上:

  1. nodeSelector: 
  2. partition: tenanta 
架構(gòu)解密從分布式到微服務(wù):深入Kubernetes微服務(wù)平臺(tái)

Kubernetes 分區(qū)與租戶可以有多種對(duì)應(yīng)的設(shè)計(jì),上面所說(shuō)的一個(gè)分區(qū)一個(gè)租戶的設(shè)計(jì)是一種典型的設(shè)計(jì),也可以將租戶分為大客戶與普通客戶,每個(gè)大客戶都有一個(gè)單獨(dú)的資源分區(qū),而普通客戶可以以N個(gè)為一組,共享同一個(gè)分區(qū)的資源。

PaaS 平臺(tái)的領(lǐng)域模型設(shè)計(jì)

我們知道,微服務(wù)架構(gòu)下的一個(gè)應(yīng)用通常是由多個(gè)微服務(wù)所組成的,而我們的Kubernetes通常會(huì)部署多個(gè)獨(dú)立的應(yīng)用,因此,如果用 Kubernetes建模微服務(wù)應(yīng)用,則我們需要在 PaaS平臺(tái)的領(lǐng)域模型中設(shè)計(jì)出 Application這個(gè)領(lǐng)域?qū)ο螅粋€(gè)Application包括多個(gè)微服務(wù),并且最終在發(fā)布(部署)時(shí)會(huì)生成對(duì)應(yīng)的Pod、Deployment 及 Service對(duì)象,如下圖所示。

架構(gòu)解密從分布式到微服務(wù):深入Kubernetes微服務(wù)平臺(tái)

如下所示是有更多細(xì)節(jié)的領(lǐng)域模型圖,Kubernetes中的 Node、Namespace分別被建模為K8sNode與TanentNS,分區(qū)則被建模為ResPartition對(duì)象,每個(gè)分區(qū)都可以包括1到N個(gè)TanentNS,即一個(gè)或多個(gè)租戶(Tanent〉使用。每個(gè)租戶都包括一些用戶賬號(hào)(User),用來(lái)定義和維護(hù)本租戶的應(yīng)用(Application)。為了分離權(quán)限,可以使用用戶組(User Group)的方式,同時(shí)可以增加標(biāo)準(zhǔn)的基于角色的權(quán)限模型。

架構(gòu)解密從分布式到微服務(wù):深入Kubernetes微服務(wù)平臺(tái)

上圖中的Service領(lǐng)域?qū)ο蟛⒉皇荎ubernetes Service,而是包括了Kubernetes Service及相關(guān)RC/Deployment的一個(gè)“復(fù)合結(jié)構(gòu)”。在Service領(lǐng)域?qū)ο笾兄话吮匾娜繉傩?,在部署?yīng)用時(shí)會(huì)生成對(duì)應(yīng)的Kubernetes Service和RC/Deployment實(shí)例。下圖給出了Service的定義界面(原型)。

架構(gòu)解密從分布式到微服務(wù):深入Kubernetes微服務(wù)平臺(tái)

我們?cè)诮缑嫔贤瓿蓪?duì)一個(gè)Application的定義后,就可以發(fā)布應(yīng)用了。在發(fā)布應(yīng)用的過(guò)程中,先要選擇某個(gè)分區(qū),然后程序調(diào)用Kubernetes的 API接口,創(chuàng)建此 Application相關(guān)的所有Kubernetes資源對(duì)象,然后查詢Pod的狀態(tài)即可判斷是否發(fā)布成功及失敗的具體原因。下面給出了Application從定義到發(fā)布的關(guān)鍵模塊的設(shè)計(jì)示意圖。

架構(gòu)解密從分布式到微服務(wù):深入Kubernetes微服務(wù)平臺(tái)

我們知道Kubernetes是基于容器技術(shù)的微服務(wù)架構(gòu)平臺(tái),每個(gè)微服務(wù)的二進(jìn)制文件都被打包成標(biāo)準(zhǔn)的Docker鏡像,因此應(yīng)用的全生命周期管理過(guò)程的第一步,就是從源碼到Docker鏡像的打包,而這個(gè)過(guò)程很容易實(shí)現(xiàn)自動(dòng)化,我們既可以通過(guò)編程方式實(shí)現(xiàn),也可以通過(guò)成熟的第三方開源項(xiàng)目實(shí)現(xiàn),這里推薦使用Jenkins。下圖是Jenkins實(shí)現(xiàn)鏡像打包流程的示意圖,考慮到Jenkins的強(qiáng)大和用戶群廣泛,很多PaaS平臺(tái)都集成了Jenkins 以實(shí)現(xiàn)應(yīng)用的全生命周期管理功能。

架構(gòu)解密從分布式到微服務(wù):深入Kubernetes微服務(wù)平臺(tái)

PaaS 平臺(tái)的基礎(chǔ)中間件

一個(gè)完備的PaaS平臺(tái)必須集成和提供一些常見(jiàn)的中間件,以方便應(yīng)用開發(fā)和托管運(yùn)行。首先,第1類重要的基礎(chǔ)中間件是 ZooKeeper,ZooKeeper非常容易被部署到Kubernetes集群中,在Kubernetes 的 GitHub上有一個(gè)YAML參考文件。ZooKeeper除了給應(yīng)用使用,也可以作為PaaS平臺(tái)面向應(yīng)用提供的“集中配置服務(wù)”的基礎(chǔ)組成部分,如下圖所示。

架構(gòu)解密從分布式到微服務(wù):深入Kubernetes微服務(wù)平臺(tái)

此外,考慮到很多開源分布式系統(tǒng)都采用了ZooKeeper來(lái)管理集群,所以我們也可以部署一個(gè)標(biāo)準(zhǔn)命名的ZooKeeper Service,以供這些集群共享使用。

第2類重要的中間件就是緩存中間件了,比如我們之前提到的Redis 及 Memcache,它們也很容易被部署到Kubernetes集群中,作為基礎(chǔ)服務(wù)提供給第三方應(yīng)用使用。在Kubernetes的入門案例中有一個(gè)GuestBook例子,演示了在PHP頁(yè)面中訪問(wèn)Redis主從集群的方法,即使是復(fù)雜的Codis集群,也可以被成功部署到Kubernetes集群中。此外,RedHat 的J2EE內(nèi)存緩存中間件Infinispan也有Kubernetes集群部署的案例。

第3類重要的中間件是消息隊(duì)列中間件,不管是經(jīng)典的ActiveMQ、RabbitMQ還是新一代的Kafka,這些消息中間件也很容易被部署到Kubernetes集群中提供服務(wù)。下圖是一個(gè)3節(jié)點(diǎn)的RabbitMQ集群在Kubernetes平臺(tái)上的建模示意圖。為了組成RabbitMQ集群,我們定義了3個(gè)Pod,每個(gè)Pod都對(duì)應(yīng)一個(gè)Kubernetes Service,從而映射到3個(gè)RabbitMQ Server 實(shí)例,此外,我們定義了一個(gè)單獨(dú)的Service,名為 ku8-rabbit-mq-server,此 Service對(duì)外提供服務(wù),并且對(duì)應(yīng)到上述3個(gè)Pod 上,于是每個(gè)Pod都有兩個(gè)標(biāo)簽。

架構(gòu)解密從分布式到微服務(wù):深入Kubernetes微服務(wù)平臺(tái)

第4類重要的中間件是分布式存儲(chǔ)中間件,目前在Kubernetes集群上可以使用Ceph集群提供的塊存儲(chǔ)服務(wù)及GlusterFS提供的分布式文件存儲(chǔ)服務(wù),其中 GlusterFS被RedHat的OpenShift平臺(tái)建議為文件存儲(chǔ)的標(biāo)配存儲(chǔ)系統(tǒng),下面是這種方案的示意圖。

架構(gòu)解密從分布式到微服務(wù):深入Kubernetes微服務(wù)平臺(tái)

在 RedHat的方案中,GlusterFS集群被部署在獨(dú)立的服務(wù)器集群上,這適用于較大的集群規(guī)模及對(duì)性能和存儲(chǔ)要求高的場(chǎng)景。在機(jī)器有限的情況下,我們也可以把Kubernetes集群的每個(gè)Node節(jié)點(diǎn)都當(dāng)作一個(gè)GlusterFS的存儲(chǔ)節(jié)點(diǎn),并采用DaemonSet的調(diào)度方式將GlusterFS部署到Kubernetes集群上,具體的部署方式在Kubernetes 的 GitHub網(wǎng)站中有詳細(xì)的說(shuō)明文檔,以Pod方式部署GlusterFS集群也使得GlusterFS 的部署和運(yùn)維都變得非常簡(jiǎn)單。

提供全文檢索能力的ElasticSearch集群也很容易被部署到Kubernetes中,前面提到的日志集中收集與查詢分析的三件套ELK目前基本上全部以Pod的方式部署,以實(shí)現(xiàn)Kubernetes集群日志與用戶應(yīng)用日志的統(tǒng)一收集、查詢、分析等功能。

在當(dāng)前熱門的大數(shù)據(jù)領(lǐng)域中,很多系統(tǒng)也都能以容器化方式部署到Kubernetes集群中,比如Hadoop、HBase、Spark 及 Storm等重量級(jí)集群。下一節(jié)將給出 Storm On Kubernetes 的建模方案,并且將其部署到Kubernetes集群中,最后提交第6章的WordCountTopology 作業(yè)并且觀察運(yùn)行結(jié)果。

Storm On Kubernetes 實(shí)戰(zhàn)

通過(guò)第6章的學(xué)習(xí),我們知道一個(gè) Storm集群是由ZooKeeper、Nimbus (Master)及一些Supervisor (Slave)節(jié)點(diǎn)組成的,集群的配置文件默認(rèn)保存在 conf/storm.yaml中,最關(guān)鍵的配置參數(shù)如下。

  • storm.zookeeper.servers: ZooKeeper集群的節(jié)點(diǎn)IP地址列表。
  • nimbus.seeds:Nimbus的IP地址。
  • supervisor.slots.ports:Supervisor 中的Worker 監(jiān)聽(tīng)端口列表。

從上述關(guān)鍵配置信息及Storm集群的工作原理來(lái)看,我們首先需要將ZooKeeper建模為Kubernetes Service,以便提供一個(gè)固定的域名地址,使得Nimbus 與Supervisor能夠訪問(wèn)它。下面是ZooKeeper 的建模過(guò)程(為了簡(jiǎn)單起見(jiàn),我們只建模一個(gè)ZooKeeper節(jié)點(diǎn))。

首先,定義ZooKeeper對(duì)應(yīng)的Service,Service名稱為ku8-zookeeper,關(guān)聯(lián)的標(biāo)簽為app=ku8-zookeeper 的Pod:

  1. apiVersion: v1kind: Servicemetadata: 
  2. name: ku8-zookeeperspec: 
  3. ports: 
  4. name: clientport: 2181selector: 
  5. app: ku8-zookeeper 

其次,定義ZooKeeper對(duì)應(yīng)的RC:

  1. apiversion: v1 
  2. kind: Replicationcontrollermetadata: 
  3. name: ku8-zookeeper-lspec: 
  4. replicas: 1template: 
  5. metadata: 
  6. labels: 
  7. app: ku8-zookeeperspec: 
  8. containers: 
  9. name: server 
  10. image: jplock/ zookeeper 
  11. imagePu1lPolicy: IfNotPresentports: 
  12. -containerPort: 2181 

接下來(lái),我們需要將Nimbus也建模為Kubernetes Service,因?yàn)镾torm客戶端需要直接訪問(wèn)Nimbus服務(wù)以提交拓?fù)淙蝿?wù),所以在conf/storm.yaml中存在nimbus.sceds參數(shù)。由于Nimbus在6627端口上提供了基于Thrift的 RPC服務(wù),因此對(duì)Nimbus服務(wù)的定義如下:

  1. apiversion: v1kind: Servicemetadata: 
  2. name: nimbusspec: 
  3. selector: 
  4. app: storm-nimbusports: 
  5. -name: nimbus-rpc 
  6. port: 6627 
  7. targetPort:6627 

考慮到在storm.yaml配置文件中有很多參數(shù),所以為了實(shí)現(xiàn)任意參數(shù)的可配置性,我們可以用Kubernetes的Config Map資源對(duì)象來(lái)保存storm.yaml,并映射到Nimbus(以及 Supervisor)節(jié)點(diǎn)對(duì)應(yīng)的Pod實(shí)例上。下面是在本案例中使用的storm.yaml 文件(storm-conf.yaml)的內(nèi)容:

  1. storm.zookeeper.servers: [ku8-zookeeper] 
  2. nimbus.seeds: [nimbus]storm.log.dir: "log" 
  3. storm. local.dir: "storm-data"supervisor.slots.ports: 
  4. -6700 
  5. 670167026703 

將上述配置文件創(chuàng)建為對(duì)應(yīng)的ConfigMap ( storm-config),可以執(zhí)行下面的命令:

  1. kubelet create configmap storm-config --from-file=storm-conf.yaml 

然后,storm-config 就可以被任意Pod 以 Volume方式掛載到容器內(nèi)的任意指定路徑上了。接下來(lái),我們可以繼續(xù)建模 Nimbus服務(wù)對(duì)應(yīng)的Pod。在從Docker Hub上搜尋相關(guān) Storm鏡像并進(jìn)行分析后,我們選擇了Docker 官方提供的鏡像storm:1.0。相對(duì)于其他Storm鏡像來(lái)說(shuō),官方維護(hù)的這個(gè)鏡像有以下優(yōu)點(diǎn)。

  • Storm版本新。
  • Storm整體只有一個(gè)鏡像,通過(guò)容器的command 命令參數(shù)來(lái)決定啟動(dòng)的是哪種類型的節(jié)點(diǎn),比如Nimbus主節(jié)點(diǎn)、Nimbus-ui管理器或者Supervisor 從節(jié)點(diǎn)。
  • 標(biāo)準(zhǔn)化的Storm進(jìn)程啟動(dòng)方式,可以將conf/storm.yaml配置文件映射到容器外,因此可以采用Kubernetes 的 ConfigMap特性。

采用storm:1.0鏡像定義Nimbus Pod的YAML文件如下:

  1. apiversion: v1kind: Pod 
  2. metadata: 
  3. name: nimbuslabels: 
  4. app: storm-nimbusspec: 
  5. volumes: 
  6. name: config-volumeconfigMap: 
  7. name: storm-configitems: 
  8. 一key:storm-conf.yaml 
  9. path:storm.yaml 
  10. containers: 
  11. - name: nimbus 
  12. image: storm: 1.0 
  13. imagePullPolicy: IfNotPresentports: 
  14. -containerPort: 6627 
  15. command:【"storm" ,"nimbus" ]volumeMounts: 
  16. - name: config-volumemountPath: /conf 
  17. restartPolicy: Always 

這里我們需要關(guān)注兩個(gè)細(xì)節(jié):第1個(gè)細(xì)節(jié)是ConfigMap 的使用方法,首先要把之前定義的ConfigMap ——storm-config映射為Pod的一個(gè)Volume,然后在容器中將此Volume掛接到某個(gè)具體的路徑上;第2個(gè)細(xì)節(jié)是容器的參數(shù) command,上面的command: [ "storm" , "nimbus"]表示此容器啟動(dòng)的是nimus進(jìn)程。

類似地,我們定義storm-ui服務(wù),這是一個(gè)Web管理程序,提供了圖形化的Storm管理功能,因?yàn)樾枰贙ubernetes集群之外訪問(wèn)它,所以我們通過(guò)NodePort方式映射8080端口到主機(jī)上的30010。storm-ui服務(wù)的YAML定義文件如下:

  1. apiversion: v1kind: Servicemetadata: 
  2. name: storm-uispec: 
  3. type: NodePortselector: 
  4. app:storm-uiports: 
  5. -name: web 
  6. port: 8080 
  7. targetPort: 8080nodePort:30010 

最后,我們來(lái)建模Supervisor。Supervisor看似不需要被建模為Service,因?yàn)镾upervisor 不會(huì)被主動(dòng)調(diào)用,但實(shí)際上Supervisor節(jié)點(diǎn)之間會(huì)相互發(fā)起通信,因此Supervisor節(jié)點(diǎn)注冊(cè)到ZooKeeper 上的地址必須能被相互訪問(wèn),在 Kubernetes平臺(tái)上有兩種方式解決此問(wèn)題。

第1種方式,Supervisor節(jié)點(diǎn)注冊(cè)到ZooKeeper上時(shí),不用主機(jī)名(Pod名稱),而是采用Pod的P地址。

第2種方式,用Headless Service模式,每個(gè)Supervisor節(jié)點(diǎn)都被建模為一個(gè)HeadlessService,并且確保Supervisor節(jié)點(diǎn)的容器名稱(主機(jī)名)與Headless Service的名稱一樣,此時(shí)Supervisor節(jié)點(diǎn)注冊(cè)到ZooKeeper 上的地址就跟Headless Service名稱一樣了,Supervisor節(jié)點(diǎn)之間都能用對(duì)方的Headless Service的域名進(jìn)行通信。

其中,第1種方式需要修改Supervisor的啟動(dòng)腳本和對(duì)應(yīng)的參數(shù)才能進(jìn)行,實(shí)現(xiàn)起來(lái)比較麻煩,第②種方式無(wú)須修改鏡像就能實(shí)現(xiàn),所以我們采用了第﹖種方式建模。下面是某個(gè)Supervisor節(jié)點(diǎn)的Service定義,注意 clusterIP: None的特殊寫法:

  1. apiversion: v1 
  2. kind: Servicemetadata: 
  3. name:storm-supervisorspec: 
  4. clusterIP:Noneselector: 
  5. app:storm-supervisorports: 
  6. - port: 8000 

storm-supervisor 這個(gè)節(jié)點(diǎn)對(duì)應(yīng)的 Pod定義如下,需要注意Pod 的名稱為storm-supervisor,并且command的值為[ "storm", "supervisor"]:

  1. apiversion: v1kind: Pod 
  2. metadata: 
  3. name: storm-supervisorlabels: 
  4. app: storm-supervisorspec: 
  5. volumes: 
  6. name: config-volumeconfigMap: 
  7. name: storm-configitems: 
  8. 一key:storm-conf.yaml 
  9. path: storm.yaml 
  10. containers: 
  11. name: storm-supervisorimage: storm: 1.0 
  12. imagePullPolicy: IfNotPresent 
  13. command:["storm""supervisor" ]volumeMounts: 
  14. -name: config-volumemountPath: /conf 
  15. restartPolicy:Always 

我們可以定義多個(gè)Supervisor 節(jié)點(diǎn),比如在本案例中定義了兩個(gè)Supervisor節(jié)點(diǎn)。在成功部署到Kubernetes集群后,我們通過(guò)Storm UI的30010端口進(jìn)入Storm的管理界面,可以看到如下界面。

架構(gòu)解密從分布式到微服務(wù):深入Kubernetes微服務(wù)平臺(tái)

下面這個(gè)截圖驗(yàn)證了兩個(gè)Supervisor 節(jié)點(diǎn)也可以被成功注冊(cè)在集群中,我們看到每個(gè)節(jié)點(diǎn)都有4個(gè)Slot,這符合我們?cè)趕torm.yaml中的配置。

架構(gòu)解密從分布式到微服務(wù):深入Kubernetes微服務(wù)平臺(tái)

至此,Storm集群在Kubernetes 上的建模和部署已經(jīng)順利完成了。接下來(lái)我們看看如何在Storm集群中提交之前學(xué)習(xí)過(guò)的WordCountTopology作業(yè)并且觀察它的運(yùn)行情況。

首先,我們可以去 https:/ljar-download.com/下載編譯好的 WordCountTopology 作業(yè)的JAR文件
storm-starter-topologies-1.0.3.jar,然后通過(guò)Storm Client工具將該Topology作業(yè)提交到Storm集群中,提交作業(yè)的命令如下:

  1. storm jar/userlib/storm-starter-topologies-1.0.3.jar org.apache.storm.starter.ordcountTopology topology 

由于在storm:1.0鏡像中已經(jīng)包括了Storm Client 工具,所以最簡(jiǎn)便的方式是定義一個(gè)Pod,然后把下載下來(lái)的
storm-starter-topologies-1.0.3.jar作為Volume映射到Pod里的/userlib/目錄下。將容器的啟動(dòng)命令設(shè)置為上述提交作業(yè)的命令即可實(shí)現(xiàn),下面是此Pod 的YAML定義:

  1. apiversion: v1 
  2. kind: Podmetadata: 
  3. name: storm-topo-examplespec: 
  4. volumes: 
  5. name:user-libhostPath: 
  6. path: /root/stormname: config-volumeconfigMap: 
  7. name:storm-configitems: 
  8. -key: storm-conf.yaml 
  9. path: storm. yaml 
  10. containers: 
  11. name: storm-topo-exampleimage: storm: 1.0 
  12. imagePullPolicy: IfNotPresent 
  13. command: [ "storm","jar""/userlib/storm-starter-topologies-1.0.3.jar"
  14. "org.apache.storm.starter.WordCountTopology""topology" ] 
  15. volumeMounts: 
  16. - name: config-volumemountPath: /conf 
  17. name:user-lib 
  18. mountPath: /userlib 
  19. restartPolicy: Never 

上述定義有如下關(guān)鍵點(diǎn)。

  • 將storm-starter-topologies-1.0.3.jar 放在主機(jī)的/root/storm目錄中。
  • 容器的啟動(dòng)命令是storm client,提交Topology 作業(yè)。
  • Pod重啟策略為Never,因?yàn)橹灰峤煌闠opology 作業(yè)即可。

創(chuàng)建上述 Pod以后,我們查看該P(yáng)od 的日志,如果看到下面這段輸出,則表明WordCountTopology的拓?fù)渥鳂I(yè)已經(jīng)被成功提交到Storm集群中了。

架構(gòu)解密從分布式到微服務(wù):深入Kubernetes微服務(wù)平臺(tái)

接下來(lái),我們進(jìn)入Storm UI去看看作業(yè)的執(zhí)行情況。下圖是WordCountTopology的匯總信息,狀態(tài)為Active,運(yùn)行了8分鐘,占用了3個(gè)Worker進(jìn)程,總共運(yùn)行了28個(gè)Task。

架構(gòu)解密從分布式到微服務(wù):深入Kubernetes微服務(wù)平臺(tái)

在成功提交到Storm集群后,我們可以進(jìn)入Supervisor節(jié)點(diǎn)(Pod)查看拓?fù)渥鳂I(yè)的日志輸出,作業(yè)的日志輸出在目錄/log/workers-artifacts下,每個(gè)拓?fù)渥鳂I(yè)都有一個(gè)單獨(dú)的文件夾存放日志,我們搜索WordCountTopology 的最后一個(gè) Bolt——統(tǒng)計(jì)發(fā)送Tuple的日志,可以看到如下結(jié)果,即每個(gè)Word(字)都被統(tǒng)計(jì)輸出了。

架構(gòu)解密從分布式到微服務(wù):深入Kubernetes微服務(wù)平臺(tái)

下面這個(gè)界面給出了WordCountTopology 的詳細(xì)信息,分別顯示了拓?fù)淅锼蠸pout的相關(guān)信息,例如生成了幾個(gè)Task、總共發(fā)送了多少個(gè)Tuple、失敗了多少個(gè),以及所有 Bolt 的相關(guān)信息,例如處理了多少個(gè) Tuple、處理的延時(shí)等統(tǒng)計(jì)信息,有助于我們分析Topology 作業(yè)的性能瓶頸和改進(jìn)的可能性。

架構(gòu)解密從分布式到微服務(wù):深入Kubernetes微服務(wù)平臺(tái)

除了上面的列表信息,Storm UI還提供了展示Stream運(yùn)行情況的拓?fù)鋱D,如下圖所示,我們看到數(shù)據(jù)流從spout節(jié)點(diǎn)發(fā)出,經(jīng)過(guò) split 節(jié)點(diǎn)處理時(shí)用了3.13ms,然后抵達(dá)count節(jié)點(diǎn),count節(jié)點(diǎn)的處理耗時(shí)為0.06ms。

架構(gòu)解密從分布式到微服務(wù):深入Kubernetes微服務(wù)平臺(tái)

Storm 的 Topology 作業(yè)一旦運(yùn)行起來(lái)就不會(huì)停止,所以你會(huì)看到下面界面中的Tuple 的統(tǒng)計(jì)數(shù)字在不斷增加,因?yàn)閃ordCountTopology的 Spout 節(jié)點(diǎn)在不斷生成Tuple,所以如果我們需要停止作業(yè),則可以單擊圖中的 Deactvate按鈕掛起作業(yè),或者終止作業(yè)。

架構(gòu)解密從分布式到微服務(wù):深入Kubernetes微服務(wù)平臺(tái)

 

 

責(zé)任編輯:張燕妮 來(lái)源: 今日頭條
相關(guān)推薦

2024-05-16 07:51:55

分布式系統(tǒng)架構(gòu)

2018-05-23 15:58:27

Spring Clou微服務(wù)架構(gòu)

2023-09-12 22:58:51

分布式架構(gòu)微服務(wù)

2018-03-02 16:11:29

Spring Clou分布式服務(wù)跟蹤

2017-02-22 11:52:49

微服務(wù)分布式Java開發(fā)者

2019-10-08 11:04:44

SOA微服務(wù)架構(gòu)

2018-04-16 14:56:56

微服務(wù)架構(gòu)分布式服務(wù)

2018-04-18 16:07:49

Spring Clou微服務(wù)分布式

2018-04-09 13:56:13

微服務(wù)架構(gòu)分布式

2018-03-13 16:42:26

分布式服務(wù)跟蹤

2018-04-02 15:01:31

微服務(wù)架構(gòu)分布式服務(wù)

2020-06-10 10:20:24

微服務(wù)架構(gòu)WEB2.0

2021-06-09 09:00:00

微服務(wù)架構(gòu)技術(shù)

2017-03-14 11:52:52

微服務(wù)架構(gòu)數(shù)據(jù)管理

2024-05-17 13:48:19

2019-05-24 14:45:17

分布式微服務(wù)運(yùn)維

2025-04-11 02:30:00

2021-09-28 09:43:11

微服務(wù)架構(gòu)技術(shù)

2017-07-28 16:41:53

Spring Clou微服務(wù)架構(gòu)

2023-11-20 15:32:29

點(diǎn)贊
收藏

51CTO技術(shù)棧公眾號(hào)