隨着下一代非侵入式微服務技術 Service Mesh 服務網格的興起,其解決了侵入式微服務框架的相關問題,實現了語言無關、對應用透明等能力。所以愈來愈多的開發者逐漸由傳統的侵入式微服務解決方案(典型的技術方案爲 Spring Cloud )轉變爲 Service Mesh 微服務解決方案。node
做爲 Service Mesh 領域的熱門開源項目,Istio 爲微服務提供無侵入的流量管理、安全通訊、服務可見性等服務治理能力,目前 Istio 也基本成爲了 Service Mesh 領域的事實標準。目前愈來愈多的微服務項目開始考慮將本身的微服務應用向 Istio 進行遷移。git
基於上述背景,Istio 中的默認服務發現主要基於 Kubernetes Service 來實現,同時結合百度雲原生技術團隊在內外部實踐落地的場景,即發現部分開發者仍然但願使用第三方註冊中心的現狀, 那麼對於非 Kubernetes Service 上的服務數據應該如何歸入到 Istio 中呢?github
爲解決此類問題,首要須要解決的問題爲【服務發現】,即 Service Mesh 中微服務可以發現非 Kubernetes Service 中的服務,Istio 則須要對接支持第三方註冊中心。bootstrap
本文以 Istio 控制面對接第三方註冊中心 Consul 爲例,爲讀者介紹 Istio 如何對接 Consul 註冊中心以及具體的實踐過程,同時爲 Istio 如何對接第三方註冊中心提供技術思路。安全
本文假設讀者對 Kubernetes、Service Mesh 、Helm 等有必定的瞭解,若您還還未了解,請查閱相關資料。同時本文主要講解 Istio 對接 Consul 註冊中心,所以但願讀者對 Consul 做爲註冊中心等基礎知識有必定的瞭解。微信
若您還未了解 Consul 相關內容,請參考咱們以前的公衆號文章:Consul做爲註冊中心在雲環境的實踐與應用。架構
Istio 中服務發現機制
默認服務發現機制
咱們先看看Istio的主要架構:框架
-
Control Panel(控制平面):負責數據下發,如服務/服務實例數據、服務治理配置數據。ide
-
Data Panel(數據平面):高性能Proxy負責具體的流量治理。微服務
以下圖,Istio 部署在 Kubernetes 平臺後,默認的服務/服務實例數據來源於 Kubernetes Service,Istio Control Panel(控制平面) List Watch Kubernetes 中 服務/服務實例數據,當數據發生變化後,Istio 控制平面將數據經過 XDS 方式推送至 Data Panel(數據平面)中的 Proxy 。註冊在 Kubernetes Service 的服務能夠正常互通訪問,但對於傳統的 Consul 註冊中心上的服務暫沒法歸入到 Istio 當中,也就形成了 Kubernetes 中部署的服務沒法調用 Consul 中部署的服務 。
對接第三方註冊中心的方式
經過查閱 Istio 官方文檔及相應代碼,發現 Istio 目前有以下三種方式對接第三方註冊中心:
方式 |
說明 |
Service Registry Adapter |
自定義適配器集成第三方註冊中心,配器從第三方服務註冊表中獲取服務和服務實例,轉換爲Istio 內部的標準模型,官方已支持Consul。 |
MCP Server |
自定義的 MCP Server 從第三方註冊表中獲取服務和服務實例,而後轉換爲 ServiceEntry 和 WorkloadEntry 資源,經過 MCP 協議提供給 Istio。 |
ServiceEntry / WorkloadEntry |
從第三方法服務註冊中心獲取服務和服務實例數據,而後轉換爲 Istio 的 ServiceEntry 和 WorkloadEntry 資源,經過 Kubernetes API Server 的接口寫入到 API Server 中。 |
對接 Consul 註冊中心方式
-
總體架構
如本文前言所述,現存的應用程序對接的註冊中心可能仍爲第三方註冊中心 Consul ,所以如何將Consul 上的服務/服務實例數據歸入到 Istio 中呢?
這要求 Istio 控制平面可以對接 Consul 註冊中心,考慮到成本最小化,本文使用 官方提供的Consul Registry Adapter。Istio 啓動後控制平面從 Consul 獲取服務/服務實例數據,考慮到 Consul 中服務/服務實例的變動時效性,Istio 控制面經過 Long Polling 的方式監聽 Consul 註冊中心上的數據變化。以下圖所示將 Consul 上的服務數據歸入到了Istio 中。
-
Consul 註冊模型適配 Istio
在K8S中資源均可以綁定 label 信息,那麼在 Consul 中服務/服務實例的 label 信息具體怎樣添加呢?
經過查看 Consul API Register Service 接口,咱們發現服務註冊模型中有兩個位置能夠攜帶上述 label 信息,分別爲:
-
Tags
(array<string>: nil)
- Specifies a list of tags to assign to the service. These tags can be used for later filtering and are exposed via the APIs. We recommend using valid DNS labels for compatibility with external DNS -
Meta
(map<string|string>: nil)
- Specifies arbitrary KV metadata linked to the service instance.
經過官方文檔說明,咱們還不能徹底知道 label 應該具體如何攜帶,但經過查閱 Istio Pilot 代碼後,咱們發現 label 可攜帶在 Tags 中而且每一個 label 的 Key 和 Value 按照分割符 "|" 分割,具體的實現代碼邏輯(代碼位置:consul.conversion.go)以下:
func convertLabels(labelsStr []string) labels.Instance { out := make(labels.Instance, len(labelsStr)) for _, tag := range labelsStr { // 按照 | 分割符號進行分割KV信息 vals := strings.Split(tag, "|") // Labels not of form "key|value" are ignored to avoid possible collisions if len(vals) > 1 { out[vals[0]] = vals[1] } else { log.Debugf("Tag %v ignored since it is not of form key|value", tag) } } return out}func convertLabels(labelsStr []string) labels.Instance { out := make(labels.Instance, len(labelsStr)) for _, tag := range labelsStr { // 按照 | 分割符號進行分割KV信息 vals := strings.Split(tag, "|") // Labels not of form "key|value" are ignored to avoid possible collisions if len(vals) > 1 { out[vals[0]] = vals[1] } else { log.Debugf("Tag %v ignored since it is not of form key|value", tag) } } return out }
所以,在服務註冊時,須要將 label 信息存放在 Tags 中,同時按照分割符 "|" 分割,如 " tag1|value1 ",以下爲具體服務註冊 Register Service 接口 的一個例子:
{ "ID": "instance-c7ac82ae14ef42d1a4ffa3b2ececa17f-local-provider-demo-172-22-204-83-provider-demo-10001", #Instance ID確保一個region惟一 "Name": "provider-demo", # 服務名 "Tags": [ "tag1|value1", # 標籤 "protocol|http" # 標明其爲http服務 ], "Address": "127.0.0.1", # 服務ip地址 "Port": 9999, # 服務提供服務端口號 "Meta": { # metadata信息,kv形式 "protocol": "http" # 標明其爲http服務 }, "Check": { "TTL": "30s", # TTL健康檢查 "deregisterCriticalServiceAfter": "30s" # 異常服務下線 } }
實踐篇
本文實踐部署的版本分別爲:
-
Consul 1.6.1
-
Istio 1.6.8
Ⅰ. Consul 部署
Consul 部署安裝的途徑有多種,本文中採用 Helm 在K8S環境中安裝 Consul ,其餘方式請參考官方安裝文檔。
-
下載 Helm 包
K8S 環境中安裝 Consul 時,官方推薦的方式爲經過Helm來進行安裝,爲保證安裝的順利進行,建議您安裝 Helm 3,Helm 安裝完成後,下載 consul-helm Helm 包來安裝 Consul 。
-
安裝 Consul
一般默認的配置沒法知足實際的需求,所以能夠經過自定義配置 config.yaml 文件覆蓋默認配置以此達到定製化安裝的目的:
# 經過覆蓋默認配置達到定製化安裝目的 $ helm install consul ./consul-helm -f config.yaml -n test
下面給出一個筆者實踐的配置 config.yaml :
ui: service: type: 'NodePort' # Consul UI界面經過NodePort的形式訪問 connectInject: enabled: false # 關閉consul connectInject功能 client: enabled: false # 關閉consul client節點模式,即全部的節點爲consul server # Use only one Consul server for local development server: enabled: true storage: 1Gi # 自定義的strage信息 storageClass: rook-ceph-block replicas: 1 # 定義的副本信息,生產環境中建議爲3個 bootstrapExpect: 1 # Consul集羣正常啓動時預期的節點數量,即集羣中節點數目達到該數目時才正常選舉啓動 disruptionBudget: enabled: true maxUnavailable: 0
注:若您想要配置更多 Consul 的功能,請參考:Helm Chart Reference。
安裝後查看服務信息,能夠看到 consul-consul-ui 的訪問方式爲 NodePort ,其對應的端口爲 30267 ,即後續能夠經過 http://{node_ip}:30267 訪問註冊中心。
$kubectl get service -n test consul-consul-dns ClusterIP 10.20.62.108 <none> 53/TCP,53/UDP 8m38s consul-consul-server ClusterIP None <none> 8500/TCP,8301/TCP,8301/UDP,8302/TCP,8302/UDP,8300/TCP,8600/TCP,8600/UDP 8m38s consul-consul-ui NodePort 10.20.154.128 <none> 80:30267/TCP
Ⅱ. Istio 部署
-
下載安裝包
在下載頁下載安裝包,注意選擇對應的操做系統安裝包,本文以 MacOS 爲例下載了 istio-1.6.8-osx.tar.gz ,解壓後進入 istio 目錄 。
# 進入istio目錄,其中目錄samples目錄用於存放示例Bookinfo Application,bin目錄存放istioctl命令,manifests用於存放的安裝清單文件 $ cd istio-1.6.8
將 istioctl 命令加入 path
$ export PATH=$PWD/bin:$PATH
-
安裝 Istio 並集成 Consul
Istio 1.6中組件已經完成了精簡,即 Istio 以前版本的多種組件已經徹底統一至 Istiod 中,所以咱們經過查閱 Istio 官方文檔對 pilot-discovery(控制面主要實現)命令參數說明,發現了對接 Consul 註冊中心的參數說明:
參數 |
描述 |
--registries <stringSlice> |
Comma separated list of platform service registries to read from (choose one or more from {Kubernetes, Consul, Mock}) (default `[Kubernetes]`) |
--consulserverURL <string> |
URL for the Consul server (default ``) |
即經過 pilot -discovery --registries = Consul ---consulserverURL = http://{{node_ip}}:39267/ ,可是這些參數具體在哪裏配置呢?
經過對官方文檔查閱,發現能夠自定義清單來完成安裝,咱們修改清單 yaml 來指定參數:
# 文件位置:istio-1.6.8/manifests/charts/istio-control/istio-discovery/templates ... containers: - name: discovery image: pilot:dev # 本文中修復了Consul數據變動後Istio推送失效的問題,所以從新構建了鏡像 {{- if .Values.global.imagePullPolicy }} imagePullPolicy: {{ .Values.global.imagePullPolicy }} {{- end }} args: - "discovery" - --monitoringAddr=:15014 - --registries=Kubernetes,Consul # 考慮後面要部署BookInfo Application,所以能夠對接多個註冊中心,即Kubernetes和Consul,讀者可根據實際狀況選擇集成那種註冊中心 - --consulserverURL=http://{node_ip}:30267 # 注意{node_ip}須要替換爲具體的地址 ...
修改完成後完成最終部署:
# 注意此處profile=demo本質上對應了一系列的安裝清單文件,manifests 目錄中的清單文件夾manifests中文件會對默認的profile demo的內容進行覆蓋配置安裝 $ istioctl install --charts=./manifests --set profile=demo
最終咱們在 default 命令空間下開啓自動注入 Sidecar 功能:
$ kubectl label namespace default istio-injection=enabled
爲驗證 XDS 規則等下發狀況,咱們參考官方 Bookinfo Application 文檔部署了示例。同時部署了服務 provider-demo ,其註冊在 Consul 註冊中心上。
踩坑篇
對接過程發現了兩個問題:
-
XDS 變動推送失效,即 Consul 註冊中心上的服務服務/服務實例發生變化後,Istio 控制面沒有經過 XDS 推送。
-
Istio 沒法對接開啓了 ACL 鑑權認證的 Consul 註冊中心。
XDS 變動推送爲什麼失效
當部署完 BookInfo Application 示例後,經過頻繁修改 Consul 上的服務 provider-demo 實例信息,筆者滿心歡喜進入 istio-proxy 容器訪問 http://127.0.0.1:15000/config_dump 查詢 envoy configdump 中的數據,預期可以將 Consul 註冊中心上變動的服務 provider-demo 在 envoy configdump 中查詢到,但查詢數據發現變動的服務數據 provider-demo 並未經過XDS完成變動推送,這是什麼緣由呢?帶着這樣的疑問,筆者決定調試一下代碼。
經過代碼調試發現(代碼位置: bootstrap.server.go ),Consul 服務數據發生變化後,已經引發數據變動事件,但對應的 PushRequest.ConfigUpdated中ConfigKey.Name 字段不正確,該字段主要代表具體的那個服務發生了變化,以服務 provier-demo 變動爲例,預期該字段的值爲 "provider-demo.service.consul" ,而實際倒是 ".service.consul" ,最終致使該數據被 push 前【被誤判爲不該該下發該數據】,最終致使變動數據沒有經過 XDS 進行下發。
該問題筆者在 Istio 代碼的基礎上完成了修改並完成從新構建鏡像驗證,目前該問題已經修改, 後續筆者也將會將提PR反饋給 Istio 社區。
如何對接開啓了 ACL 認證鑑權的 Consul 註冊中心
生產環境中的 Consul 註冊中心每每都開啓了 ACL 認證鑑權,但筆者在對接過程發現中 Istio 控制面代碼層面並沒預留設置 Consul ACL Token 的配置項,筆者修改了 Istio 代碼設置 Consul Token,用於處理從 Consul 註冊中心獲取數據,目前已經可以支持對接開啓了 ACL 鑑權認證的 Consul 註冊中心, 後續筆者也會將 PR 反饋給 Istio 社區。
筆者經過親身實踐,發現 Istio 對接第三方註冊中心尤爲是對接 Consul 註冊中心目前還存在一些功能問題待解決,後續筆者也將問題及解決方案及時反饋給社區,推進該問題的解決,同時但願更多的人能參與其中共建繁榮的 Istio 社區。
筆者有幸經歷了百度由傳統的微服務框架 Spring Cloud(Java生態中微服務一體化解決方案)向 Service Mesh(服務網格,下一代微服務一體化解決方案)架構的轉變,實踐了將第三方註冊中心 Consul 集成至 Istio 的生態中,望本文可以讓讀者對 Istio 集成第三方註冊中心 Consul 有必定的瞭解。
附錄
-
《What is Istio?》:https://istio.io/v1.6/docs/concepts/what-is-istio/
-
《Installing Consul On Kubernetes》:https://www.consul.io/docs/k8s/installation/install
-
《Getting Started》:https://istio.io/v1.6/docs/setup/getting-started/
做者簡介:劉超,百度研發工程師,現就任於百度基礎架構部雲原生團隊,主導和參與百度內外部多項大規模微服務化改造,專一於微服務及雲原生領域相關技術,對 Spring Cloud、Service Mesh、Istio、Consul 等方向有深刻的研究和實踐。
瞭解更多微服務、雲原生技術的相關信息,請關注咱們的微信公衆號【雲原生計算】!