Consul Service Mesh實戰(zhàn)
在最近發(fā)布的Consul1.2中袖肥,HashiCorp宣布支持Service Mesh胧弛。作為一個優(yōu)秀的分布式服務發(fā)現(xiàn)解決方案犬辰,Consul是如何支持Service Mesh的呢稀轨?本文將帶讀者一探究竟。
在Consul 1.2的release blog中肠仪,Consul定義了Service Mesh的3個要素:
- Discovery:服務可以互相找到
- Configuration:服務在運行時肖抱,可以從一個集中的源頭獲取配置
- Segmentation:服務之間的通信必須是加密并通過認證的
實際上,Consul本身已經支持服務發(fā)現(xiàn)藤韵,并且實現(xiàn)了一個集群共享的KV存儲方案虐沥,可以實現(xiàn)服務配置的存儲。而最新的Consul 1.2中,新發(fā)布的Connect功能欲险,可以為服務創(chuàng)建一個網絡層的代理镐依,這成為Consul Service Mesh方案中,數(shù)據(jù)面代理的基礎天试。接下來槐壳,我們從這三個方面一一對Consul進行解析。
Discovery
Consul是一個跨數(shù)據(jù)中心的分布式服務發(fā)現(xiàn)解決方案喜每。在Consul集群的每一個節(jié)點上务唐,都運行一個Consul進程,成為一個Consul agent带兜,一個agent可以以server或client兩種模式運行枫笛。Client agent非常輕量,只需與Server agent交互刚照,并維護Client自身很少的狀態(tài)刑巧。而Server agent除了Client agent的所有功能,還提供額外的能力來完成基于Raft的一致性方案无畔,因此Server agent的負載會更高啊楚,也需要更多的資源,運行在更加穩(wěn)定的節(jié)點上浑彰。Consul agent可以通過join命令恭理,指定集群中任意一個agent的IP,以加入集群郭变,形成一個Consul cluster颜价。如下圖所示:
在單個節(jié)點上,Consul agent讀取該節(jié)點服務的配置文件诉濒,獲取該節(jié)點上服務的信息拍嵌,并與cluster中其他agent通過gossip協(xié)議互相通信,完成集群內的服務注冊與發(fā)現(xiàn)循诉。當Consul cluster中的服務需要調用另一個服務時,可以通過API和DNS解析兩種方式撇他,向所在節(jié)點的Consul agent獲取目標服務的具體地址茄猫,然后調用目標服務。
Configuration
除了服務注冊與發(fā)現(xiàn)困肩,Consul還內置了一個KV存儲系統(tǒng)划纽,用于Cluster之間共享數(shù)據(jù)。KV的Key是分層的锌畸,通過斜線/
分隔勇劣,這樣,可以在概念上對key進行組織和管理,用來保存不同的配置比默,并把配置分配給集群內的所有服務幻捏。例如,在一個集群內命咐,運行了webfront
服務篡九,webfront
服務需要獲知當前是開發(fā)環(huán)境還是測試環(huán)境,以提供不同的頁面表現(xiàn)醋奠。那么榛臼,我們在可以在節(jié)點A上用KV存儲保存環(huán)境信息:
nodeA$ consul kv put services/webapi/metadata/env dev #假設env=dev表示測試環(huán)境
服務運行過程中,假設任務調度器將webfront
服務的實例調度到節(jié)點B和節(jié)點C窜司,那么在節(jié)點B和C上可以通過Consul agent訪問到環(huán)境信息:
nodeB$ consul kv get services/webapi/metadata/env
nodeB$ dev
當然沛善,在實際的使用中,我們不僅可以通過命令行來獲取KV數(shù)據(jù)塞祈,也可以通過RESTful API金刁,向所在節(jié)點的Consul agent發(fā)送HTTP請求來獲取數(shù)據(jù)。
Segmentation
按照Consul的說明织咧,Segmentation的意義在于使服務之間的網絡請求都是經過TLS加密并認證的胀葱。那么,Consul是如何做到請求的自動TLS加密和認證的呢笙蒙?
Consul 1.2新增了Connect功能抵屿,只需要在服務中增加一個connect
配置,即可為該服務啟動一個代理:
{
"service": {
"name": "webfront",
"connect": {
"proxy": {}
}
}
}
這樣捅位,Consul agent就會為webfront
服務啟動一個內置的proxy轧葛,proxy啟動時,向所在節(jié)點的Consul agent(為了便于說明艇搀,假設為Client agent尿扯,其實Client/Server都是可能的)請求webfront
所需要的root證書和leaf證書。Client agent檢查本地的緩存焰雕,若已有所需證書衷笋,則直接將證書和私鑰返回。否則就會生成一個新的私鑰矩屁,并向Server agent發(fā)送CSR辟宗。Server對CSR進行驗證,并返回簽名的證書吝秕,Client agent拿到證書泊脐,把證書和私鑰返回給proxy。這樣烁峭,proxy就可以接受TLS請求了容客。這個過程如下:
并且秕铛,Consul中還有一個自動更新的機制,當Server中的根證書變化時缩挑,Client重新生成私鑰但两,向Server發(fā)送CSR,獲取簽名的證書调煎,并把簽名的證書和私鑰再發(fā)給proxy镜遣,完成證書的更新。
了解了Consul Connect士袄,我們會發(fā)現(xiàn)悲关,其實Connect功能幫每個服務啟動了一個Proxy,對服務的inbound/outbound請求進行了TLS加密和認證娄柳,這個場景是否似曾相識寓辱?沒錯,就是Service Mesh中數(shù)據(jù)面sidecar的概念赤拒。只是這個Consul內建的sidecar目前能實現(xiàn)的功能還比較單一秫筏,只有TLS加密和認證。
現(xiàn)在挎挖,我們對Consul Service Mesh的三個要素都有了較為具體了解这敬,那么,相比于一般意義上的Service Mesh方案蕉朵,例如Istio崔涂,Conduit等,Consul的Service Mesh有何不同呢始衅?我們不妨以Istio為例冷蚂,看看Istio中是如何實現(xiàn)這三個要素的:
Discovery:由Pilot結合服務發(fā)現(xiàn)機制(kubernetes,eureka汛闸,consul等)完成
Configuration:由Pilot結合Kubernetes完成蝙茶,用戶使用kubectl定義Istio所需的Kubernetes資源,Pilot讀取到這些資源后诸老,轉換為自己的Model隆夯,并通過xDS API將配置信息下發(fā)給Envoy
Segmentation:Citadel結合Envoy完成,Citadel將證書頒發(fā)給每個服務的Envoy
因此别伏,Istio的結構是這樣的:
可以看到Discovery和Configuration都是在Istio控制面完成的吮廉。Segmentation是由控制面的Citadel+數(shù)據(jù)面的Envoy代理完成的。
根據(jù)HashiCorp的說明畸肆,在Consul的Service Mesh方案中,Consul作為控制面運行宙址,Consul agent實現(xiàn)了服務發(fā)現(xiàn)和配置存儲轴脐。同時,Consul agent再結合Connect啟動的Proxy,完成了網絡流量的加密與認證大咱。如下圖所示:
請注意恬涧,Consul的KV系統(tǒng)只完成了配置的存儲,并沒有像Istio一樣碴巾,可以對配置進行動態(tài)修改并下發(fā)到數(shù)據(jù)面溯捆,目前Proxy的配置也是通過讀取文件,然后在啟動或重啟代理時傳入的厦瓢,因此我們認為Consul的配置管理能力還需要完善提揍。此外,因為Consul Connect啟動的Proxy是一個4層代理煮仇,無法提供路由劳跃、熔斷、重試等更高級的微服務治理能力浙垫,因此也不需要獲取服務治理的配置刨仑。這是Consul Service Mesh的方案中治理能力欠缺的地方。不過夹姥,HashiCorp也表示Connect在1.2版本中只是Beta狀態(tài)杉武,未來會繼續(xù)圍繞Connect開發(fā)新的功能,包括UI的增強辙售,支持Envoy作為proxy轻抱,與Nomad和Kubernetes的集成等。
等等圾亏,聽說Consul已經可以集成Envoy了十拣?
沒錯!其實志鹃,在Consul1.2中夭问,Connect已經可以通過指定一個可執(zhí)行文件的路徑來啟動第三方代理了。Consul會以daemon模式啟動第三方代理曹铃,在后臺運行:
{
"service": {
"name": "webfront",
"connect": {
"proxy": {
"exec_mode": "daemon",
"command": ["/usr/bin/my-proxy", "--listen", "8800"]
}
}
}
}
那么缰趋,按照通常的思路,是不是可以直接指定Envoy陕见,讓Consul啟動Envoy來實現(xiàn)集成呢秘血?理論上確實可行,但是Consul是無法管理第三方代理的配置的评甜,Envoy的配置只能由用戶自行定義灰粮,增加了運維成本,也不便于管理忍坷。
這時粘舟,就輪到HashiCorp好基友solo.io出品的Gloo Connect閃亮登場了熔脂!solo.io是一家提供Cloud Native工具和集成方案的公司,例如支持Kubernetes和Istio的微服務debugger squash柑肴,基于Envoy的function gateway解決方案Gloo霞揉。在剛剛過去的HashiDay 2018上,solo.io和HashiCorp聯(lián)合發(fā)布了Gloo Connect晰骑。Gloo產品線本身很有意思适秩,Gloo與英文單詞”膠水”(Glue)的發(fā)音一樣,暗示著Gloo會作為”膠水”硕舆,將Cloud Native中的各種服務粘合在一起秽荞,那么,Gloo Connect是如何把Consul和Envoy粘合在一起的呢岗宣?
Gloo Connect作為Consul的第三方代理蚂会,在啟動時會把Consul Connect proxy的配置和Gloo的配置轉換成Envoy的配置,并啟動Envoy實例耗式。同時胁住,Gloo Connect也可以通過命令行對Envoy的配置進行動態(tài)修改。下面刊咳,我們根據(jù)Gloo Connect的官方示例來演示如何將Consul與Envoy集成彪见。
Tips
根據(jù)Gloo Connect的Getting Started文檔,Consul 1.2.0中娱挨,存在一個已知bug余指,運行示例需要下載一個預先編譯的Consul版本,或者使用1.2.1版本跷坝,并把Consul配置到系統(tǒng)路徑酵镜,或者當前目錄。
首先柴钻,我們將gloo-connect項目clone到本地淮韭,進入getting-started目錄,并編譯運行service.go
:
$ git clone https://github.com/solo-io/gloo-connect/
$ cd gloo-connect/docs/getting-started
$ go run service.go &
service.go
運行后監(jiān)聽8080端口贴届,交替返回200和500狀態(tài)碼靠粪。接下來,我們執(zhí)行當前目錄下的run-consul.sh
腳本毫蚓,該腳本會在./run-data/consul-config
目錄下生成兩個配置信息connect.json
和service.json
占键,前者將gloo-connect指定為Consul Connect默認的proxy,后者定義了兩個服務microsvc1
(即我們運行的service.go) 和test
元潘,并定義了兩者之間的代理:microsvc1
配置了一個空規(guī)則的代理畔乙,test
配置了一個監(jiān)聽1234端口的代理,任何訪問1234端口的請求翩概,都將被當作test
向microsvc1
的訪問啸澡。最后袖订,腳本啟動consul,并設定consul的配置目錄為./run-data/consul-config
嗅虏。此外,腳本還會運行gloo-connect和envoy上沐,需要確保兩者在系統(tǒng)路徑或當前目錄下并具有執(zhí)行權限皮服,gloo-connect項目的發(fā)布頁面可以下載編譯好的gloo-connect和envoy
腳本啟動后,我們通過進程管理工具参咙,可以看到Consul為每個服務啟動了第三方代理gloo-connect龄广,而每個gloo-connect又啟動了一個Envoy進程,并把轉換好的配置傳給Envoy:
此時蕴侧,真正監(jiān)聽1234端口的就是Envoy進程了择同。下面,我們訪問1234端口净宵,會看到服務交替返回狀態(tài)碼200和500:
我們用gloo-connect命令為microsvc1
的Envoy sidecar配置一條retry規(guī)則:
$ ./gloo-connect set service microsvc1 --http --retries=3
這樣敲才,當通過Envoy代理訪問microsvc1
時,如果遇到500择葡,會重試3次紧武,其實在第一次重試時就會返回200了,因此我們訪問1234端口敏储,每次都會返回200:
這樣阻星,我們就借助一個第三方工具gloo-connect,實現(xiàn)了Consul和Envoy的集成已添!需要說明的是妥箕,gloo-connect也處于早期階段,目前支持的配置還比較少更舞,除了retries
畦幢,只支持http
(是否使用http模式,默認為false)和timeout
疏哗。
總結
目前來看呛讲,Consul Connect雖然還剛剛起步,但是已經讓我們非常驚喜的看到了一個相對完整返奉、簡單易用的Service Mesh方案贝搁,通過第三方的集成,未來也許會有更多優(yōu)秀的代理芽偏,甚至是用戶自己定義的代理雷逆,不斷加入到Consul的陣營中。隨著Consul Connect的不斷演進和HashiCorp的持續(xù)投入污尉,我們相信膀哲,Consul會在未來的Service Mesh競爭中占有一席之地往产,也希望業(yè)界不斷涌現(xiàn)Consul這樣優(yōu)秀的方案,給用戶更多選擇某宪,讓Service Mesh的世界越來越精彩仿村。
后記
不同于Istio、Conduit等“天生Service Mesh”的微服務方案兴喂,Consul本身是一個成熟的服務發(fā)現(xiàn)工具蔼囊,其實現(xiàn)Service Mesh的思路非常有意思。在筆者看來衣迷,除去“控制面”“數(shù)據(jù)面”這種基于大的框架角度的劃分畏鼓,Service Mesh從功能上要完成三件事情:服務注冊與發(fā)現(xiàn),配置管理(存儲壶谒、下發(fā))云矫,服務治理。Consul在第一點已經做得非常好了汗菜,配置方面让禀,Consul的集群內共享KV為實現(xiàn)配置管理奠定了堅實的基礎,完全可以通過第三方工具呵俏、或者Consul自身增強的特性堆缘,基于KV實現(xiàn)配置的下發(fā)。服務治理方面與Consul本身關系不大普碎,但是通過Connect吼肥,Consul具備了為服務配置代理或者集成第三方代理的能力,完全可以用已有的優(yōu)秀代理來實現(xiàn)Service Mesh數(shù)據(jù)面麻车,補足服務治理的能力缀皱。
Consul的方案,也給已經在業(yè)界流行并經過生產環(huán)境驗證的“上一代”微服務框架帶來很多啟發(fā)动猬。在Service Mesh概念流行之前啤斗,已有很多基于SDK的侵入式微服務框架。這些框架往往提供服務發(fā)現(xiàn)機制或者或者兼容開源的服務發(fā)現(xiàn)機制赁咙,有一些也提供配置的管理钮莲,只是需要在應用程序中引入SDK來實現(xiàn)服務治理,因此對于不同的語言彼水,都要提供相應的SDK崔拥。但是相對于Consul,畢竟這些框架已經具備了微服務治理的能力凤覆,它們向Service Mesh轉型的過程中链瓦,更需要的是將治理能力從SDK轉移到網絡層面的代理中。在這一點上,華為開源的微服務框架ServiceComb的做法非常值得參考慈俯。在ServiceComb中渤刃,已有Service Center實現(xiàn)服務的注冊與發(fā)現(xiàn),基于archaius的配置更新機制贴膘,以及提供治理能力的SDK(支持Java和Go兩種語言)卖子,為了實現(xiàn)數(shù)據(jù)面的代理,ServiceComb團隊將SDK中實現(xiàn)治理能力的代碼剝離出來刑峡,基于此開發(fā)了網絡代理Mesher揪胃,Mesher的治理能力與SDK是基本對等的,并且共享同一套配置氛琢。這樣,已經使用SDK的服務随闪,不需要做任何修改阳似,而使用其他語言開發(fā)的新應用,則可以通過Mesher獲得ServiceComb的服務治理能力铐伴。最終撮奏,ServiceComb成為同時支持SDK和網絡代理的混合式微服務方案,也是一個真正意義上的Service Mesh方案当宴。