Dubbo-gok8s注册中心设计方案与实现
Dubbo-go k8s注冊中心設計方案與實現
隨著云原生的推廣,越來越多的公司或組織將服務容器化,并將容器化后的服務部署在k8s集群中。
今天這篇文章將會介紹dubbo-go將k8s作為服務注冊中心的方案設計,以及具體實現。到目前為止該方案的實現已經被合并到dubbo-go的master分支。具體實現為關于Kubernetes的PullRequest。
k8s管理資源的哲學
k8s作為容器集群化管理方案可以將管理資源的維度可主觀的分為服務實例管理和服務接入管理。
服務實例管理,主要體現方式為Pod設計模式加控制器模式。控制器保證具有特定標簽(Label)的Pod保持在恒定的數量(多刪,少補)。
服務接入管理,主要為Service,該Service默認為具有特定標簽(Label)的一批Pod提供一個VIP(ClusterIP)作為服務的接入點,默認會按照round-robin的負載均衡策略將請求轉發到真正提供服務的Pod。并且CoreDNS為該Service提供集群內唯一的域名。
k8s服務發現模型
為了明確k8s在服務接入管理提供的解決方案,我們以kube-apiserver 提供的API(HTTPS)服務為例。k8s集群為該服務分配了一個集群內有效的ClusterIP,并通過CoreDNS為其分配了唯一的域名 kubernetes 。如果集群內的Pod需要訪問該服務時直接通過https://kubernetes:443即可完成。
lADPD2eDMWswXhPNBEXNBEs_1099_1093_jpg_720x720q90g
具體流程如上圖所示(紅色為客戶端,綠色為kube-apiserver):
首先客戶端通過CoreDNS解析域名為kubernetes的服務獲得對應的ClusterIP為10.96.0.1。
客戶端向10.96.0.1發起HTTPS請求。
HTTPS之下的TCP連接被kube-proxy創建的iptables的PREROUTING鏈攔截并DNAT 為 10.0.2.16或10.0.2.15。
Client與最終提供服務的Pod建立連接并交互。
由此可見,k8s提供的服務發現為域名解析級別。
Dubbo服務發現模型
同樣為了明確Dubbo服務發現的模型,以一個簡單的Dubbo-Consumer發現并訪問Provider的具體流程為例。
lALPD4Bhp_yd3sTNAarNA_A_992_426_png_720x720q90g
具體流程如上圖所示:
Provider將本進程的元數據注冊到Registry中,包括IP,Port,以及服務名稱等。
Consumer通過Registry獲取Provider的接入信息,直接發起請求
由此可見,Dubbo當前的服務發現模型是針對Endpoint級別的,并且注冊的信息不只IP和端口還包括其他的一些元數據。
K8s service vs dubbo-go 服務
通過上述兩個小節,答案基本已經比較清晰了??偨Y一下,無法直接使用k8s的服務發現模型的原因主要為以下幾點:
k8s的Service標準的資源對象具有的服務描述字段 中并未提供完整的Dubbo進程元數據字段因此,無法直接使用該標準對象進行服務注冊與發現。
dubbo-do的服務注冊是基于每個進程的,每個Dubbo進程均需進行獨立的注冊。
k8s的Service默認為服務創建VIP,提供round-robin的負載策略也與Dubbo-go自有的Cluster模塊的負載策略形成了沖突。
Dubbo-go 當前的方案
服務注冊
K8s基于Service對象實現服務注冊/發現。可是dubbo現有方案為每個dubbo-go進程獨立注冊,因此dubbo-go選擇將該進程具有的獨有的元數據寫入運行該dubbo-go進程的Pod在k8s中的Pod資源對象的描述信息中。每個運行dubbo進程的Pod將本進程的元數據寫入Pod的Annotations字段。為了避免與其他使用Annotations字段的Operator或者其他類型的控制器(istio)的字段沖突。dubbo-go使用Key為 dubbo.io/annotation value為具體存儲的K/V對的數組的json編碼后的base64編碼。
樣例為:
apiVersion: v1
kind: Pod
metadata:
? annotations:
? ? dubbo.io/annotation: W3siayI6Ii9kdWJibyIsInYiOiIifSx7ImsiOiIvZHViYm8vY29tLmlrdXJlbnRvLnVzZXIuVXNlclByb3ZpZGVyIiwidiI6IiJ9LHsiayI6Ii9kdWJiby9jb20uaWt1cmVudG8udXNlci5Vc2VyUHJvdmlkZXIvY29uc3VtZXJzIiwidiI6IiJ9LHsiayI6Ii9kdWJibyIsInYiOiIifSx7ImsiOiIvZHViYm8vY29tLmlrdXJlbnRvLnVzZXIuVXNlclByb3ZpZGVyIiwidiI6IiJ9LHsiayI6Ii9kdWJiby9jb20uaWt1cmVudG8udXNlci5Vc2VyUHJvdmlkZXIvcHJvdmlkZXJzIiwidiI6IiJ9LHsiayI6Ii9kdWJiby9jb20uaWt1cmVudG8udXNlci5Vc2VyUHJvdmlkZXIvY29uc3VtZXJzL2NvbnN1bWVyJTNBJTJGJTJGMTcyLjE3LjAuOCUyRlVzZXJQcm92aWRlciUzRmNhdGVnb3J5JTNEY29uc3VtZXJzJTI2ZHViYm8lM0RkdWJib2dvLWNvbnN1bWVyLTIuNi4wJTI2cHJvdG9jb2wlM0RkdWJibyIsInYiOiIifV0=
由于每個dubbo-go的Pod均只負責注冊本進程的元數據,因此Annotations字段長度也不會因為運行dubbo-go進程的Pod數量增加而增加。
服務發現
依賴kube-apiserver 提供了WATCH的功能??梢杂^察特定namespace內各Pod對象的變化。dubbo-go為了避免dubbo-go進程WATCH到與dubbo-go進程無關的Pod的變化,dubbo-go將WATCH的條件限制在當前Pod所在的namespace,以及僅WATCH具有Key為 dubbo.io/label Value為 dubbo.io-value 的Pod。在WATCH到對應Pod的變化后實時更新本地Cache,并通過Registry提供的Subscribe接口通知建立在注冊中心之上的服務集群管理其他模塊。
總體設計圖
lALPD4d8pTZEENfNA1PNBQA_1280_851_png_720x720q90g
具體流程如上圖所示:
啟動dubbo-go的Deployment或其他類型控制器使用k8s Downward-Api將本Pod所在namespace通過環境變量的形式注入dubbo-go進程。
Consumer/Provider進程所在的Pod啟動后通過環境變量獲得當前的namespace以及該Pod名稱, 調用kube-apiserver PATCH 功能為本Pod添加Key為dubbo.io/label Value為 dubbo.io-value 的label。
Consumer/Provider進程所在的Pod啟動后調用kube-apiserver將本進程的元數據通過PATCH接口寫入當前Pod的Annotations字段。
Consumer進程通過kube-apiserver LIST 當前namespace下其他具有同樣標簽的Pod,并解碼對應的Annotations字段獲取Provider的信息。
Consumer進程通過kube-apiserver WATCH 當前namespace下其他具有同樣label的Pod的Annotations的字段變化,動態更新本地Cache。
總結
k8s已經為其承載的服務提供了一套服務發現,服務注冊,以及服務集群管理機制。而dubbo-go的同時也擁有自成體系的服務集群管理。這兩個功能點形成了沖突,在無法調諧兩者的情況,dubbo-go團隊決定保持dubbo自有的服務集群管理系,而選擇性的放棄了Service功能,將元數據直接寫入到Pod對象的Annotations中。
當然這只是dubbo-go在將k8s作為服務注冊中心的方案之一,后續社區會以更加“云原生”的形式對接k8s,讓我們拭目以待吧。
dubbo-go 社區釘釘群 :23331795 ,歡迎你的加入。
作者信息:王翔,GithubID: sxllwx,就職于成都達闥科技有限公司,golang開發工程師。
原文鏈接
本文為云棲社區原創內容,未經允許不得轉載。
總結
以上是生活随笔為你收集整理的Dubbo-gok8s注册中心设计方案与实现的全部內容,希望文章能夠幫你解決所遇到的問題。
- 上一篇: 互联网全域降维攻击战略概述
- 下一篇: 联手友盟+打造云上数据增长“样板间”,