我們的Rancher官方技術(shù)社區(qū)已經(jīng)創(chuàng)立些許時(shí)日了,相信通過(guò)我們的線下meetup和線上布道工作,很多朋友對(duì)Rancher的使用已經(jīng)掌握得很純熟了。一些高級(jí)用戶開始真正把自己的業(yè)務(wù)進(jìn)行微服務(wù)化并向Rancher遷移,在遷移的過(guò)程中,由于業(yè)務(wù)本身的復(fù)雜性特殊性,可能需要利用Rancher的一些高級(jí)特性甚至要對(duì)Rancher進(jìn)行一定的擴(kuò)展,這就需要對(duì)Rancher的一些組件的實(shí)現(xiàn)機(jī)制有些許了解。
城子河網(wǎng)站制作公司哪家好,找創(chuàng)新互聯(lián)建站!從網(wǎng)頁(yè)設(shè)計(jì)、網(wǎng)站建設(shè)、微信開發(fā)、APP開發(fā)、成都響應(yīng)式網(wǎng)站建設(shè)公司等網(wǎng)站項(xiàng)目制作,到程序開發(fā),運(yùn)營(yíng)維護(hù)。創(chuàng)新互聯(lián)建站從2013年開始到現(xiàn)在10年的時(shí)間,我們擁有了豐富的建站經(jīng)驗(yàn)和運(yùn)維經(jīng)驗(yàn),來(lái)保證我們的工作的順利進(jìn)行。專注于網(wǎng)站建設(shè)就選創(chuàng)新互聯(lián)建站。
本次分享就介紹一下Rancher的event機(jī)制,由于相關(guān)內(nèi)容文檔極其欠缺,本人也只是通過(guò)實(shí)踐和代碼閱讀分析其原理,如有謬誤歡迎指正。
在大規(guī)模系統(tǒng)架構(gòu)中,event機(jī)制通常采用消息驅(qū)動(dòng) ,它對(duì)提升分布式架構(gòu)的容錯(cuò)性靈活性有很大幫助,同時(shí)也是各個(gè)組件之間解耦的利器。Rancher能夠管理N多的agent同時(shí)又拆分出各種服務(wù)組件,event機(jī)制是必不可少的。為實(shí)現(xiàn)event機(jī)制,通常我們會(huì)采用RabbitMQ、ActiveMQ、ZeroMQ等中間件來(lái)實(shí)現(xiàn)。而Rancher則采用了基于websocket協(xié)議的一種非常輕量級(jí)的實(shí)現(xiàn)方式,它的好處就是極大程度的精簡(jiǎn)了Rancher的部署,Rancher無(wú)需額外維護(hù)一個(gè)MQ集群,畢竟websocket的消息收發(fā)實(shí)現(xiàn)是非常簡(jiǎn)單的,各種語(yǔ)言庫(kù)均可以支持。
這里我們會(huì)考慮一個(gè)問(wèn)題,websocket畢竟不是真正工業(yè)級(jí)MQ的實(shí)現(xiàn),消息不能持久化,一旦某個(gè)event的處理出現(xiàn)問(wèn)題,或者發(fā)生消息丟失,Rancher如何保證各個(gè)資源的原子性一致性?Rancher中有一個(gè)processpool的概念,它可以看做一個(gè)所有event的執(zhí)行池,當(dāng)API/UI/CLI有操作時(shí),Rancher會(huì)把操作分解成多個(gè)event并放入processpool中。比如刪除一個(gè)容器時(shí)會(huì)把 compute.instance.remove 放入processpool中,這個(gè)event會(huì)發(fā)送到對(duì)應(yīng)的host agent上,agent處理完成后會(huì)發(fā)送reply給rancher-server。如果在這個(gè)過(guò)程中,由于網(wǎng)絡(luò)問(wèn)題消息丟失,或者agent上執(zhí)行出現(xiàn)問(wèn)題,rancher-server沒(méi)有收到reply信息,cattle會(huì)把這個(gè)event重新放到processpool中再次重復(fù)上面的過(guò)程,直到 compute.instance.remove 完成操作,這個(gè)容器的狀態(tài)才會(huì)在DB中更新,否則該容器狀態(tài)會(huì)一直處于lock不能被其他服務(wù)更新。當(dāng)然cattle不會(huì)把這些event不停的重復(fù)執(zhí)行下去,通常會(huì)設(shè)置一下TIMEOUT超出后便不再執(zhí)行(有些資源沒(méi)有TIMEOUT機(jī)制)。
上面的表述,我們其實(shí)可以在UI上看到這個(gè)過(guò)程,RancherUI上的Processes的Running Tab頁(yè)上就能實(shí)時(shí)得看到這些信息,Processes 在排查一些Rancher的相關(guān)問(wèn)題是非常有用的,大家可以養(yǎng)成 ”查問(wèn)題先查Processes“的好習(xí)慣:
那么監(jiān)聽(tīng)event的URL怎么設(shè)定呢?非常簡(jiǎn)單:
ws://:8080/v1/projects/ /subscribe?eventNames=xxxx
除此之外還需要加上basic-auth的header信息
Authorization: Basic +base64encode(: )
如果是Host上的agent組件,還需要添加agentId參數(shù)
ws://:8080/v1/projects/ /subscribe?eventNames=xxxx&agentId=xxxx
agentId 是注冊(cè)Host時(shí)生成的,如果沒(méi)有agentId參數(shù),任何有關(guān)無(wú)關(guān)的event都會(huì)發(fā)送到所有的Host agent上,這樣就會(huì)發(fā)生類似“廣播風(fēng)暴”的效果。
Host agent上運(yùn)行很多組件,其中python-agent是負(fù)責(zé)接收和回執(zhí)event信息的,其運(yùn)行日志可以在Host上的/var/log/rancher/agent.log文件中查看。
細(xì)心的朋友可能會(huì)有疑問(wèn),我們?cè)谔砑親ost時(shí)執(zhí)行agent容器時(shí)并沒(méi)有指定cattle-access-key和cattle-secret-key,也就是說(shuō)python-agent運(yùn)行時(shí)如何獲取這兩個(gè)秘鑰信息呢?
其實(shí)Rancher有兩種apikey:一種是我們熟知的在UI上手動(dòng)創(chuàng)建的apikey;另外一種就是agentApikey,它是系統(tǒng)級(jí)的,專門為agent設(shè)定,添加Host時(shí)會(huì)先把a(bǔ)gentApikey發(fā)送到Host上。在cattle的credential表中可以查詢到相關(guān)信息:
eventNames都定義了哪些呢?下面兩個(gè)文件可以參考:
https://github.com/rancher/cattle/blob/master/code/iaas/events/src/main/java/io/cattle/platform/iaas/event/IaasEvents.java 系統(tǒng)級(jí)的event定義
https://github.com/rancher/cattle/blob/master/code/packaging/app-config/src/main/resources/META-INF/cattle/process/spring-process-context.xml 詳細(xì)到每種資源(host、volume、instance、stack、service等)的event定義。
此外,一旦我們?cè)赨I/CLI/API上的某個(gè)操作都會(huì)被分解成多個(gè)event來(lái)執(zhí)行,每個(gè)event信息都會(huì)被保存在MySQL中,每個(gè)event執(zhí)行成功后會(huì)設(shè)置成purged狀態(tài),所以表中記錄并不會(huì)真正刪除,這就會(huì)導(dǎo)致相應(yīng)的表(container_event表、service_event表、process_instance表)會(huì)無(wú)限膨脹下去。
Rancher為解決此問(wèn)題提供了周期性清理機(jī)制
events.purge.after.seconds 可以清理container_event和service_event,每?jī)芍芮謇硪淮危籶rocess_instance.purge.after.seconds可以清理process_instance,每天清理一次。這兩個(gè)配置我們都可以在 http://
下面我們來(lái)實(shí)踐一下,看看如何在程序中實(shí)現(xiàn)對(duì)Rancher event的監(jiān)聽(tīng)。
Rancher提供了resource.change事件,這個(gè)事件是不用reply的,就是說(shuō)不會(huì)影響Rancher系統(tǒng)的運(yùn)行,它是專門開放給開發(fā)者用來(lái)實(shí)現(xiàn)一些自己的定制功能,所以我們就以resource.change作為例子實(shí)踐一下。
Rancher的組件大部分都是基于Golang編寫,所以我們也采用相同的語(yǔ)言。
為了能夠快速實(shí)現(xiàn)這個(gè)程序,我們需要了解一些輔助快速開發(fā)的小工具。
Trash,Golang package管理的小工具,可以幫助我們定義依賴包的路徑和版本,非常輕量且方便
Dapper,這個(gè)是基于容器實(shí)現(xiàn)Golang編譯的工具,主要是可以幫助我們統(tǒng)一編譯環(huán)境
go-skel,它可以幫我們快速創(chuàng)建一個(gè)Rancher式的微服務(wù)程序,可以為我們省去很多的基本代碼,同時(shí)還集成了Trash和Dapper這兩個(gè)實(shí)用的小工具
使用詳情可以參考我之前寫的一篇內(nèi)容:
扒一扒Rancher社區(qū)中的小工具
回到本文的主題,首先我們基于go-skel創(chuàng)建一個(gè)工程名為 scale-subscriber (名字很隨意),執(zhí)行過(guò)程需要耐心的等待:
執(zhí)行完畢后,我們把工程放到GOPATH中,開始添加相關(guān)的邏輯代碼。
在這之前我們可以考慮添加一個(gè)healthcheck的服務(wù)端口,其實(shí)縱觀Rancher所有的微服務(wù)組件,基本上除了主程序之外都會(huì)添加 healthcheck port,這個(gè)主要是為了與Rancher中的healthcheck功能配合,通過(guò)設(shè)定對(duì)這個(gè)端口的檢查機(jī)制來(lái)保證微服務(wù)的可靠性。
我們利用Golang的goroutine機(jī)制,分別添加主服務(wù)和healthcheck服務(wù):
主服務(wù)的核心就是監(jiān)聽(tīng)resource.change的信息,同時(shí)注冊(cè)handler來(lái)獲取event的payload信息,從而可以定制擴(kuò)展自己的邏輯,這里需要利用Rancher提供的 https://github.com/rancher/event-subscriber 庫(kù)來(lái)快速實(shí)現(xiàn)。
如下圖,在 reventhandlers.NewResourceChangeHandler().Handler 中就可以實(shí)現(xiàn)自己的邏輯:
這里我們只是演示監(jiān)聽(tīng)event的機(jī)制,所以我們就不做過(guò)多的業(yè)務(wù)邏輯處理,打印輸出event信息即可。
然后在項(xiàng)目根目錄下執(zhí)行make,make會(huì)自動(dòng)調(diào)用dapper,在bin目錄下生成scale-subscriber,我們執(zhí)行scale-subscriber就可以監(jiān)聽(tīng)resource.change的信息:
這里我們可以看到分別啟動(dòng)了healthcheck功能和event listener。然后可以在UI上隨意刪除一個(gè)stack,scale-subsciber就可以獲取event信息:
如要將其部署在Rancher中,那就可以將scale-subsciber執(zhí)行程序打包放到鏡像中,通過(guò)compose來(lái)啟動(dòng)。
但是我們知道scale-subsciber啟動(dòng)需要指定CATTLE_URL、CATTLE_ACCESS_KEY、CATTLE_SECRET_KEY,正常的做法就是我們需要先生成好apikey,然后啟動(dòng)service的時(shí)候設(shè)置對(duì)應(yīng)的環(huán)境變量。
這樣做就會(huì)有弊端,就是apikey這種私密的信息不得不對(duì)外暴露,而且還要手動(dòng)維護(hù)這些apikey,非常不方便。
Rancher提供了一個(gè)非常方便的做法,就是在service中添加兩個(gè)label,
io.rancher.container.create_agent: true
io.rancher.container.agent.role: environment
設(shè)定這兩個(gè)label后,Rancher引擎會(huì)自動(dòng)創(chuàng)建apikey,并把相應(yīng)的值設(shè)置到容器的ENV中,只要你的程序通過(guò)系統(tǒng)環(huán)境變量來(lái)讀取這些值,就會(huì)非常順利的運(yùn)行起來(lái)。
原文來(lái)源:RancherLabs