如何將第三方服務注冊集成到 Istio ?
本文轉載自微信公眾號「趙化冰」,轉載本文請聯系趙化冰公眾號。
目錄
- Istio 服務模型
- Pilot 服務模型源碼分析
- 第三方服務注冊表集成
- Consul 集成
- 其他服務注冊表的集成
- 小結
- 參考文檔
作為云原生服務網格領域的熱門開源項目,Istio 可以為微服務提供無侵入的流量管理、安全通信、服務可見性等服務治理能力。目前越來越多的微服務項目開始考慮將自己的微服務基礎設施向 Istio 進行遷移。
Istio 對 Kubernetes 具有較強的依賴性,其服務發現就是基于 Kubernetes 實現的。大量現存的微服務項目要么還沒有遷移到 Kubernetes 上;要么雖然采用了 Kubernetes 來進行部署和管理,但還是使用了 Consul,Eureka 等其他服務注冊解決方案或者自建的服務注冊中心。
在這種情況下,我們如何能夠以最小的代價快速地將現有微服務項目和 Istio 進行集成,以享受 Istio 提供的各種服務治理能力呢?本文將分析 Istio 服務注冊機制的原理,并提出幾種 Istio 與第三方服務注冊中心集成的可行方案,以供讀者參考。
Istio 服務模型
我們先來看一下 Istio 內部的服務模型。在 Istio 控制面中,Pilot 組件負責管理服務網格內部的服務和流量策略。Pilot 將服務信息和路由策略轉換為 xDS 接口的標準數據結構,下發到數據面的 Envoy。
Pilot 自身并不負責網格中的服務注冊,而是通過集成其他服務注冊表來獲取網格中管理的服務。除此以外,Istio 還支持通過 API 向網格中添加注冊表之外的獨立服務。
圖1 Istio 服務模型數據來源
從上圖中可以得知, Pilot 中管理的服務數據有兩處數據來源:
- Service Registry:來源于各個服務注冊表,例如 Kubernetes 中的 Service 和 Consul Catalog 中注冊的服務。Istio 通過特定的適配器連接這些服務注冊表,由適配器將服務注冊表中的私有服務模型轉換為 Istio 內部支持的標準服務模型。
- Config Storage:來源于各種配置數據源中的獨立服務,通過 Istio 定義的 ServiceEntry 和 WorkloadEntry 資源類型加入到 Pilot 的內部服務模型中。
Pilot 服務模型源碼分析
Pilot 中涉及到服務模型的代碼模塊如下圖所示:
圖2 Pilot 服務模型相關的代碼結構
Pilot 的入口函數是 pilot/cmd/pilot-discovery/main.go 中的 main 方法。main方法中創建了 Discovery Server,Discovery Server 中和服務模型相關的主要包含三部分內容:
- Config Controller:用于管理各種配置數據,包括用戶創建的流量管理規則和策略。配置數據中有兩個 API 對象和服務模型相關,ServiceEntry 和 WorkloadEntry。Istio 目前支持三種類型的 Config Controller:
- Kubernetes:使用 Kubernetes 來作為配置數據的存儲,該方式的直接依附于 Kubernetes 強大的 CRD 機制來存儲配置數據,簡單方便,是 Istio 缺省使用的配置存儲方案。
- Memory:一個在內存中的 Config Controller 實現,可以監控一個文件目錄,加載該目錄中的 yaml 文件中定義的 Istio API 配置對象,該方式主要用于測試。
- MCP:通過 MCP(Mesh Configuration Protocol) 協議,可以接入一個到多個 MCP Server。Pilot 從 MCP server 中獲取網格的配置數據,包括 ServiceEntry 和 WorkloadEntry 定義的服務數據,以及 VirtualService,DestinationRule 等路由規則等其他配置。Istio 中有一個 Galley 組件,該組件實現為一個 MCP Server,從 Kubernetes API Server 中獲取配置數據,然后通過 MCP 協議提供給 Pilot。
- Service Controller:負責接入各種 Service Registry,從 Service Registry 同步需要在網格中進行管理的服務,目前Istio支持的Service Registry包括:
- Kubernetes:對接 Kubernetes Registry,可以將 Kubernetes 的 Service 和 Endpoint 采集到 Istio 中。
- Consul:對接Consul Catalog,將注冊到 Consul 中的服務數據采集到 Istio 中。
- External Service Discovery:該 Service Registry 比較特殊,后端并未對接到一個服務注冊表,而是會監聽 Config Controller 的配置變化消息,從 Config Controller 中獲取 ServiceEntry 和 WorkloadEntry 資源,然后以 Service Registry 的形式提供給 Service Controller。
Discovery Service:將服務模型和控制面配置轉換為數據面標準數據格式,通過 xDS 接口下發給數據面的代理。主要包含下述邏輯:
- 啟動GRPC Server并接收來自Envoy端的連接請求。
- 接收Envoy端的xDS請求,從Config Controller和Service Controller中獲取配置和服務信息,生成響應消息發送給Envoy。
- 監聽來自Config Controller的配置變化消息和來自Service Controller的服務變化消息,并將配置和服務變化內容通過xDS接口推送到Envoy。
第三方服務注冊表集成
Consul 集成
鑒于和 Kubernetes 的緊密關系,Istio 在最初只重點關注了 Kubernetes 服務注冊的集成。雖然在 Istio 最初的版本中也有 Consul 和 Eureka 的適配代碼,但這些代碼基本只是處于原型驗證的節點,存在較多的故障和性能問題。
由于在項目中采用了 Consul 作為自研服務注冊的后端存儲,我們在和 Istio 進行集成時對 Consul 的適配進行了大量測試和研究,并解決了一些功能和性能效率方面的問題。這些 Consul 適配的問題解決后已經合入了 Istio 版本中,參見這些 PR:
- Use watching instead of polling to get update from Consul catalog #17881
- Fix: Consul high CPU usage (#15509) #15510
- Avoid unnecessary service change events(#11971) #12148
- Use ServiceMeta to convey the protocol and other service properties #9713
這些問題處理后,Consul 注冊表的集成已經基本可用。要將 Consul 接入到 Pilot 中, 只需要在 pilot-discovery 的啟動命令中通過這兩個參數指定 registry 類型和 consul 的連接地址即可: --registries Consul --consulserverURL http://$consul-ip:$port。
其他服務注冊表的集成
雖然在 1.0 中還有 Eureka 的適配代碼框架,但在 Istio 后面的版本完全刪除了 Eureka 適配的相關代碼。除了 Kubernetes 和 Consul 之外,原生 Istio 代碼不支持其他服務注冊表。但我們可以采用以下三種方式將其集成到 Istio 的方式。
圖3 集成第三方服務注冊表的三種方式
上圖中分別用紅、綠、三種顏色標識了這三種不同的集成方式。
自定義 Service Registry 適配器
如圖3中紅色箭頭所示,我們可以編寫一個自定義的適配器來集成第三方服務注冊表。該自定義適配器從第三方服務注冊表中獲取服務和服務實例,轉換為 Pilot 內部的標準模型,集成到 Service Controller 中。自定義適配器需要實現 serviceregistry.Instance 接口。該方式的原理和 Consul Service Registry 的適配是類似的,可以參照 Consul Service Registry 的適配代碼進行編寫。
實施該方案需要熟悉 Pilot 內部服務模型和 Service Registry 適配相關 Istio 源碼,并且需要將自定義適配器代碼和 Pilot 代碼一起編譯生成定制的 Pilotd 二進制執行文件。該方案的問題是和 Istio 代碼耦合較強,后續 Istio 版本升級時可能需要修改適配器代碼并重新編譯。
自定義 MCP Server
這種集成方式的業務流程參見圖3中的藍色箭頭。該方案需要編寫自定義的 MCP Server 從第三方注冊表中獲取服務和服務實例,然后轉換為 ServiceEntry 和 WorkloadEntry 資源,通過 MCP 協議提供給 Pilot 中的 MCP config Controller。
采用這種方式,需要在 Global Mesh Options 中通過 configSources 參數設置自定義 MCP Server 的地址。需要注意的是,目前1.6的 Config Controller 實現不允許同時使用不同類型的Config controller。這意味著如果采用自定義 MCP Server 來獲取第三方注冊表中的服務數據,也必須同時采用 Galley 來獲取其他控制面的配置。
- configSources:
- - address:istio-galley.istio-system.svc:9901
- - address:${your-coustom-mcp-server}:9901
而從1.5版本開始,Galley 的功能以及被合并到 Istiod 中,并且缺省被禁用。從 Isito 控制面簡化的趨勢來看,Galley 后續很可能會被逐漸放棄,其自身功能的穩定性也值得懷疑。因此我不建議在產品中啟用 Galley。
除此以外,根據 Istio 社區中的這個 MCP over XDS proposal,社區正在討論使用 XDSv3/UDPA 代替目前的 MCP 協議來傳輸配置數據,因此 MCP server 和 Pilot 的通信機制在 1.7 版本中很可能變化。
向 API Server 寫入 ServiceEntry 和 WorkloadEntry
該集成方式的業務流程如圖3中綠色箭頭所示。我們只需要編寫一個獨立的服務,該服務從第三方法服務注冊表中獲取服務和服務實例數據,然后轉換為 Istio 的 ServiceEntry 和 WorkloadEntry 資源,通過 K8s API Server 的接口寫入到 API Server 中。Pilot 中自帶的 Kube Config Controller 會監聽 K8s API Server 中和 Istio 相關的資源對象的變化,并將 ServiceEntry 和 WorkloadEntry 轉換為 Piolt 的內部服務模型。
小結
本文分析了 Istio 和第三方服務注冊表集成的幾種可能的方式,包括自定義的 Service Registry 適配代碼,自定義 MCP Server 和采用一個獨立服務向 API Server 寫入 ServiceEntry 和 WorkloadEntry 三種方法。有需要的讀者可以根據項目的實際情況選擇采用哪一種方法。由于第一種和第二種方法目前都存在一些問題,個人建議先采用第三種方式,待 Istio 對 Galley 和 MCP 的改造徹底完成后再考慮向第二種方式遷移。
備注:本文的分析和建議都是基于使用 Istio 1.6 的前提下。隨著 Istio 版本的不斷發展,其服務模型和注冊相關機制可能發生變化,和第三方服務注冊表的集成方式也可能變化。
參考文檔
- Istio 服務注冊插件機制
- Istio Pilot代碼深度解析
- Istio and managing microservices
- Istio 1.6 Change Notes
- The recommended way to integrate a third-party service registry with Istio