电竞比分网-中国电竞赛事及体育赛事平台

分享

石墨文檔基于 Kubernetes 的微服務(wù)實(shí)踐

 黃爸爸好 2021-09-24

在 2014 年 6 月 Google 開源了 Kubernetes 后,經(jīng)過(guò)這幾年的發(fā)展,已逐漸成為容器編排領(lǐng)域的事實(shí)標(biāo)準(zhǔn), 可以稱之為云原生時(shí)代的操作系統(tǒng),它使得基礎(chǔ)設(shè)施維護(hù)變得異常簡(jiǎn)單。在云原生時(shí)代,微服務(wù)依賴于 Kubernetes 的優(yōu)勢(shì)在哪,微服務(wù)的生命周期基于 Kubernetes 該如何實(shí)踐呢?本文整理自石墨文檔架構(gòu)負(fù)責(zé)人彭友順在 Gopher China Meetup 西安站的主題演講《石墨文檔基于 Kubernetes 的 Go 微服務(wù)實(shí)踐(上篇)》。下篇會(huì)在近期整理出來(lái),敬請(qǐng)期待。

架構(gòu)演進(jìn)

互聯(lián)網(wǎng)的 WEB 架構(gòu)演進(jìn)可以分為三個(gè)階段:?jiǎn)误w應(yīng)用時(shí)期、垂直應(yīng)用時(shí)期、微服務(wù)時(shí)期。

單體應(yīng)用時(shí)期一般處于一個(gè)公司的創(chuàng)業(yè)初期,他的好處就是運(yùn)維簡(jiǎn)單、開發(fā)快速、能夠快速適應(yīng)業(yè)務(wù)需求變化。但是當(dāng)業(yè)務(wù)發(fā)展到一定程度后,會(huì)發(fā)現(xiàn)許多業(yè)務(wù)會(huì)存在一些莫名奇妙的耦合,例如你修改了一個(gè)支付模塊的函數(shù),結(jié)果登錄功能掛了。為了避免這種耦合,會(huì)將一些功能模塊做一個(gè)垂直拆分,進(jìn)行業(yè)務(wù)隔離,彼此之間功能相互不影響。但是在業(yè)務(wù)發(fā)展過(guò)程中,會(huì)發(fā)現(xiàn)垂直應(yīng)用架構(gòu)有許多相同的功能,需要重復(fù)開發(fā)或者復(fù)制粘貼代碼。所以要解決以上復(fù)用功能的問(wèn)題,我們可以將同一個(gè)業(yè)務(wù)領(lǐng)域內(nèi)功能抽出來(lái)作為一個(gè)單獨(dú)的服務(wù),服務(wù)之間使用 RPC 進(jìn)行遠(yuǎn)程調(diào)用,這就是我們常所說(shuō)的微服務(wù)架構(gòu)。

總的來(lái)說(shuō),我們可以將這三個(gè)階段總結(jié)為以下幾點(diǎn)。單體應(yīng)用架構(gòu)快速、簡(jiǎn)單,但耦合性強(qiáng);垂直應(yīng)用架構(gòu)隔離性、穩(wěn)定性好,但復(fù)制粘貼代碼會(huì)比較多;微服務(wù)架構(gòu)可以說(shuō)是兼顧了垂直應(yīng)用架構(gòu)的隔離性、穩(wěn)定性,并且有很強(qiáng)的復(fù)用性能力??梢哉f(shuō)微服務(wù)架構(gòu)是公司發(fā)展壯大后,演進(jìn)到某種階段的必然趨勢(shì)。

圖片

但微服務(wù)真的那么美好嗎?我們可以看到一個(gè)單體架構(gòu)和微服務(wù)架構(gòu)的對(duì)比圖。在左圖我們可以看到一個(gè)業(yè)務(wù)可以通過(guò) Nginx+ 服務(wù)器 + 數(shù)據(jù)庫(kù)就能實(shí)現(xiàn)業(yè)務(wù)需求。但是在右圖微服務(wù)架構(gòu)中,我們完成一個(gè)業(yè)務(wù)需要引入大量的組件,比如在中間這一塊我們會(huì)引入 DNS、HPA、ConfigMap 等、下面部分引入了存儲(chǔ)組件 Redis、MySQL、Mongo 等。以前單體應(yīng)用時(shí)期我們可能直接上機(jī)器看日志或上機(jī)器上查看資源負(fù)載監(jiān)控,但是到了微服務(wù)階段,應(yīng)用太多了,肯定不能這么去操作,這個(gè)時(shí)候我們就需要引入 ELK、Prometheus、Grafana、Jaeger 等各種基礎(chǔ)設(shè)施,來(lái)更方便地對(duì)我們的服務(wù)進(jìn)行觀測(cè)。

圖片

微服務(wù)的組件增多、架構(gòu)復(fù)雜,使得我們運(yùn)維變得更加復(fù)雜。對(duì)于大廠而言,人多維護(hù)起來(lái)肯定沒(méi)什么太大問(wèn)題,可以自建完整的基礎(chǔ)設(shè)施,但對(duì)于小廠而言,研發(fā)資源有限,想自建會(huì)相當(dāng)困難。

不過(guò)微服務(wù)的基礎(chǔ)設(shè)施維護(hù)困難的問(wèn)題在 Kubernetes 出現(xiàn)后逐漸出現(xiàn)了轉(zhuǎn)機(jī)。在 2014 年 6 月 Google 開源了 Kubernetes 后,經(jīng)過(guò)這幾年的發(fā)展,已逐漸成為容器編排領(lǐng)域的事實(shí)標(biāo)準(zhǔn)。同時(shí) Kubernetes 已儼然成為云原生時(shí)代的超級(jí)操作系統(tǒng),它使得基礎(chǔ)設(shè)施維護(hù)變得異常簡(jiǎn)單。

在傳統(tǒng)模式下,我們不僅需要關(guān)注應(yīng)用開發(fā)階段存在的問(wèn)題,同時(shí)還需要關(guān)心應(yīng)用的測(cè)試、編譯、部署、觀測(cè)等問(wèn)題,例如程序是使用 systemd、supervisor 啟動(dòng)、還是寫 bash 腳本啟動(dòng)?日志是如何記錄、如何采集、如何滾動(dòng)?我們?nèi)绾螌?duì)服務(wù)進(jìn)行觀測(cè)?Metrics 指標(biāo)如何采集?采集后的指標(biāo)如何展示?服務(wù)如何實(shí)現(xiàn)健康檢查、存活檢查?服務(wù)如何滾動(dòng)更新?如何對(duì)流量進(jìn)行治理,比如實(shí)現(xiàn)金絲雀發(fā)布、流量鏡像?諸如此類的問(wèn)題。我們業(yè)務(wù)代碼沒(méi)寫幾行,全在考慮和權(quán)衡基礎(chǔ)設(shè)施問(wèn)題。然而使用 Kubernetes 后,可以發(fā)現(xiàn)大部分問(wèn)題都已經(jīng)被 Kubernetes 或周邊的生態(tài)工具解決了,我們僅僅只需要關(guān)心上層的應(yīng)用開發(fā)和維護(hù) Kubernetes 集群即可。

圖片

Kubernetes 在微服務(wù)中的作用就如同建高樓的地基,做了很多基礎(chǔ)工作,統(tǒng)一了大量的基礎(chǔ)設(shè)施標(biāo)準(zhǔn),以前我們要實(shí)現(xiàn)服務(wù)的啟動(dòng)、配置、日志采集、探活等功能需要寫很多中間件,現(xiàn)在我們只需要寫寫 yaml 文件,就可以享受這些基礎(chǔ)設(shè)施的能力。運(yùn)維更加簡(jiǎn)單這個(gè)也顯而易見,例如在以前出現(xiàn)流量高峰時(shí)研發(fā)提工單后增加副本數(shù),運(yùn)維處理工單,人肉擴(kuò)縮容,現(xiàn)在我們可以根據(jù)實(shí)際應(yīng)用的負(fù)載能力,合理的配置好副本 CPU、Mem 等資源及 HPA 規(guī)則,在流量高峰時(shí)由 Kubernetes 自動(dòng)擴(kuò)容、流量低谷時(shí)自動(dòng)縮容,省去了大量人工操作。

同時(shí)在框架層面,傳統(tǒng)模式下基礎(chǔ)設(shè)施組件很多都是自研的,基本上沒(méi)有太多標(biāo)準(zhǔn)可言,框架需要做各種 switch case 對(duì)這種基礎(chǔ)設(shè)施組件的適配,并且框架經(jīng)常會(huì)為因?yàn)榛A(chǔ)設(shè)施的改變,做一些不兼容的升級(jí)?,F(xiàn)在只需要適配 Kubernetes 即可,大大簡(jiǎn)化微服務(wù)的框架難度和開發(fā)成本。

微服務(wù)的生命周期

剛才我們講到 Kubernetes 的優(yōu)勢(shì)非常明顯,在這里會(huì)描述下我們自己研發(fā)的微服務(wù)框架 Ego 怎么和 Kubernetes 結(jié)合起來(lái)的一些有趣實(shí)踐。

我們將微服務(wù)的生命周期分為以下 6 個(gè)階段:開發(fā)、測(cè)試、部署、啟動(dòng)、調(diào)用、治理。

圖片

2.1 開發(fā)階段

在開發(fā)階段我們最關(guān)注三個(gè)問(wèn)題:如何配置、如何對(duì)接,如何調(diào)試。

2.1.1 配置驅(qū)動(dòng)

大家在使用開源組件的時(shí)候,其實(shí)會(huì)發(fā)現(xiàn)每個(gè)開源組件的配置、調(diào)用方式、debug 方式、記錄日志方式都不一樣,導(dǎo)致我們需要不停去查看組件的示例、文檔、源碼,才能使用好這個(gè)組件。我們只想開發(fā)一個(gè)功能,卻需要關(guān)心這么多底層實(shí)現(xiàn)細(xì)節(jié),這對(duì)我們而言是一個(gè)很大的心智負(fù)擔(dān)。

所以我們將配置、調(diào)用方式做了統(tǒng)一??梢钥吹缴蠄D我們所有組件的地址都叫 addr,然后在下圖中我們調(diào)用 redis、gRPC、MySQL 的時(shí)候,只需要基于組件的配置 Key path 去 Load 對(duì)應(yīng)的組件配置,通過(guò) build 方法就可以構(gòu)造一個(gè)組件實(shí)例??梢钥吹秸{(diào)用方式完全相同,就算你不懂這個(gè)組件,你只要初始化好了,就可以根據(jù)編輯器代碼提示,調(diào)用這個(gè)組件里的 API,大大簡(jiǎn)化我們的開發(fā)流程。

圖片

2.1.2 配置補(bǔ)齊

配置補(bǔ)齊這個(gè)功能,是源于我們?cè)谧铋_始使用一些組件庫(kù)的時(shí)候,很容易遺漏配置,例如使用gRPC的客戶端,未設(shè)置連接錯(cuò)誤、導(dǎo)致我們?cè)谧枞J较逻B接不上的時(shí)候,沒(méi)有報(bào)正確的錯(cuò)誤提示;或者在使用 Redis、MySQL 沒(méi)有超時(shí)配置,導(dǎo)致線上的調(diào)用出現(xiàn)問(wèn)題,產(chǎn)生雪崩效應(yīng)。這些都是因?yàn)槲覀儗?duì)組件的不熟悉,才會(huì)遺漏配置。框架要做的是在用戶不配置的情況下,默認(rèn)補(bǔ)齊這些配置,并給出一個(gè)最佳實(shí)踐配置,讓業(yè)務(wù)方的服務(wù)更加穩(wěn)定、高效。

圖片

2.1.3 配置工具

我們編寫完配置后,需要將配置發(fā)布到測(cè)試環(huán)境,我們將配置中心 IDE 化,能夠非常方便的編寫配置,通過(guò)鼠標(biāo)右鍵,就可以插入資源引用,鼠標(biāo)懸??梢钥吹綄?duì)應(yīng)的配置信息。通過(guò)配置中心,使我們?cè)趯?duì)比配置版本,發(fā)布,回滾,可以更加方便。

圖片

2.1.4 對(duì)接 -Proto 管理

我們內(nèi)部系統(tǒng)全部統(tǒng)一采用gRPC協(xié)議和protobuf編解碼。統(tǒng)一的好處在于不需要在做任何協(xié)議、編解碼轉(zhuǎn)換,這樣就可以使我們所有業(yè)務(wù)采用同一個(gè)protobuf倉(cāng)庫(kù),基于 CI/CD 工具實(shí)現(xiàn)許多自動(dòng)化功能。

我們要求所有服務(wù)提供者提前在獨(dú)立的路徑下定義好接口和錯(cuò)誤碼的 protobuf 文件,然后提交到 GitLab,我們通過(guò) GitLab CI 的 check 階段對(duì)變更的 protobuf 文件做 format、lint、breaking 檢查。然后在 build 階段,會(huì)基于 protobuf 文件中的注釋自動(dòng)產(chǎn)生文檔,并推送至內(nèi)部的微服務(wù)管理系統(tǒng)接口平臺(tái)中,還會(huì)根據(jù) protobuf 文件自動(dòng)構(gòu)建 Go/PHP/Node/Java 等多種語(yǔ)言的樁代碼和錯(cuò)誤碼,并推送到指定對(duì)應(yīng)的中心化倉(cāng)庫(kù)。

圖片

推送到倉(cāng)庫(kù)后,我們就可以通過(guò)各語(yǔ)言的包管理工具拉取客戶端、服務(wù)端的 gRPC 和錯(cuò)誤碼的依賴,不需要口頭約定對(duì)接數(shù)據(jù)的定義,也不需要通過(guò) IM 工具傳遞對(duì)接數(shù)據(jù)的定義文件,極大的簡(jiǎn)化了對(duì)接成本。

2.1.5 對(duì)接 - 錯(cuò)誤碼管理

有了以上比較好的 protobuf 生成流程后,我們可以進(jìn)一步簡(jiǎn)化業(yè)務(wù)錯(cuò)誤狀態(tài)碼的對(duì)接工作。而我們采用了以下方式:

  • Generate:

  • 編寫 protobuf error 的插件,生成我們想要的 error 代碼。

  • 根據(jù) go 官方要求,實(shí)現(xiàn) errors 的 interface,他的好處在于可以區(qū)分是我們自定義的 error 類型,方便斷言。

圖片

  • 根據(jù)注解的 code 信,在錯(cuò)誤碼中生成對(duì)應(yīng)的 grpc status code,業(yè)務(wù)方使用的時(shí)候少寫一行代碼。

圖片

圖片

  • 確保錯(cuò)誤碼唯一,后續(xù)在 API 層響應(yīng)用戶數(shù)據(jù)確保唯一錯(cuò)誤碼,例如: 下單失敗 (xxx)。

  • errors 里設(shè)置 with message,with metadata,攜帶更多的錯(cuò)誤信息。

  • Check:

  • gRPC 的 error 可以理解為遠(yuǎn)程 error,他是在另一個(gè)服務(wù)返回的,所以每次 error 在客戶端是反序列化,new 出來(lái)的。是無(wú)法通過(guò) errors.Is 判斷其根因。

圖片

  • 我們通過(guò)工具將 gRPC 的錯(cuò)誤碼注冊(cè)到一起,然后客戶端通過(guò) FromError 方法,從注冊(cè)的錯(cuò)誤碼中,根據(jù) Reason 的唯一性,取出對(duì)應(yīng)的錯(cuò)誤碼,這個(gè)時(shí)候我們可以使用 errors.Is 來(lái)判斷根因。

圖片

圖片

  • 最后做到 errors.Is 的判斷: errors.Is(eerrors.FromError(err), UserErrNotFound())。

2.1.6 對(duì)接 - 調(diào)試

對(duì)接中調(diào)試的第一步是閱讀文檔,我們之前通過(guò) protobuf 的 ci 工具里的 lint,可以強(qiáng)制讓我們寫好注釋,這可以幫助我們生成非常詳細(xì)的文檔。

基于 gRPC Reflection 方法,服務(wù)端獲得了暴露自身已注冊(cè)的元數(shù)據(jù)能力,第三方可以通過(guò) Reflection 接口獲取服務(wù)端的 Service、Message 定義等數(shù)據(jù)。結(jié)合 Kubernetes API,用戶選擇集群、應(yīng)用、Pod 后,可直接在線進(jìn)行 gRPC 接口測(cè)試。同時(shí)我們可以對(duì)測(cè)試用例進(jìn)行存檔,方便其他人來(lái)調(diào)試該接口。

圖片

2.1.7 Debug- 調(diào)試信息

我們大部分的時(shí)候都是對(duì)接各種組件 API,如果我們能夠展示各種組件例如 gRPC、HTTP、MySQL、Redis、Kafka 的調(diào)試信息,我們就能夠快速的 debug。在這里我們定義了一種規(guī)范,我們將配置名、請(qǐng)求 URL、請(qǐng)求參數(shù)、響應(yīng)數(shù)據(jù)、耗時(shí)時(shí)間、執(zhí)行行號(hào)稱為 Debug 的六元組信息。

將這個(gè) Debug 的六元組信息打印出來(lái),如下圖所示。我們就可以看到我們的響應(yīng)情況,數(shù)據(jù)結(jié)構(gòu)是否正確,是否有錯(cuò)誤。

圖片

2.1.8 Debug- 定位錯(cuò)誤

Debug 里面有個(gè)最重要的一點(diǎn)能夠快速定位錯(cuò)誤問(wèn)題,所以我們?cè)趯?shí)踐的過(guò)程中,會(huì)遵循 Fail Fast 理念。將框架中影響功能的核心錯(cuò)誤全部設(shè)置為 panic,讓程序盡快的報(bào)錯(cuò),并且將錯(cuò)誤做好高亮,在錯(cuò)誤信息里顯示 Panic 的錯(cuò)誤碼,組件、配置名、錯(cuò)誤信息,盡快定位錯(cuò)誤根因。這個(gè)圖里面就是我們的錯(cuò)誤示例,他會(huì)高亮的顯示出來(lái),你的配置可能不存在,這個(gè)時(shí)候業(yè)務(wù)方在配置文件中需要找到server.grpc這個(gè)配置,設(shè)置一下即可。

圖片

2.2 測(cè)試階段
2.2.1 測(cè)試類型

開發(fā)完成后,我們會(huì)進(jìn)入到測(cè)試階段。我們測(cè)試可以分為四種方式:?jiǎn)卧獪y(cè)試、接口測(cè)試、性能測(cè)試、集成測(cè)試。

我們會(huì)通過(guò) docker-compose 跑本地的一些單元測(cè)試,使用 GitLab CI 跑提交代碼的單元測(cè)試。我們接口測(cè)試則使用上文所述接口平臺(tái)里的測(cè)試用例集。性能測(cè)試主要是分兩種,一類是 benchmark 使用 GitLab ci。另一類是全鏈路壓測(cè)就使用平臺(tái)工具。集成測(cè)試目前還做的不夠好,之前是用 GitLab ci 去拉取鏡像,通過(guò) dind(Docker in Docker)跑整個(gè)流程,但之前我們沒(méi)有拓?fù)鋱D,所以需要人肉配置 yaml,非常繁瑣,目前我們正在結(jié)合配置中心的依賴拓?fù)鋱D,準(zhǔn)備用 jekins 完成集成測(cè)試。

在這里我主要介紹下單元測(cè)試。

2.2.2 工具生成測(cè)試用例

單元測(cè)試優(yōu)勢(shì)大家都應(yīng)該很清楚,能夠通過(guò)單測(cè)代碼保證代碼質(zhì)量。但單測(cè)缺點(diǎn)其實(shí)也非常明顯,如果每個(gè)地方都寫單測(cè),會(huì)消耗大家大量的精力。

所以我們首先定義了一個(gè)規(guī)范,業(yè)務(wù)代碼里面不要出現(xiàn)基礎(chǔ)組件代碼,所有組件代碼下層到框架里做單元測(cè)試。業(yè)務(wù)代碼里只允許有 CRUD 的業(yè)務(wù)邏輯,可以大大簡(jiǎn)化我們的測(cè)試用例數(shù)量。同時(shí)我們的業(yè)務(wù)代碼做好 gRPC,HTTP 服務(wù)接口級(jí)別的單元測(cè)試,可以更加簡(jiǎn)單、高效。

然后我們可以通過(guò)開發(fā) protobuf 工具的插件,拿到 gRPC 服務(wù)的描述信息,通過(guò)他結(jié)合我們的框架,使用指令自動(dòng)生成測(cè)試代碼用例。在這里我們框架使用了 gRPC 中的測(cè)試 bufconn 構(gòu)造一個(gè) listener,這樣就可以在測(cè)試中不關(guān)心 gRPC 服務(wù)的 ip port。

圖片

以下是我們通過(guò)工具生成的單元測(cè)試代碼,我們業(yè)務(wù)人員只需要在紅框內(nèi)填寫好對(duì)應(yīng)的斷言內(nèi)容,就可以完成一個(gè)接口的單測(cè)。

圖片

2.2.3 簡(jiǎn)單高效做單元測(cè)試

目前單元測(cè)試大部分的玩法,都是在做解除依賴,例如以下的一些方式:

  • 面向接口編程

  • 依賴注入、控制反轉(zhuǎn)

  • 使用 Mock

不可否認(rèn),以上的方法確實(shí)可以使代碼變得更加優(yōu)雅,更加方便測(cè)試。但是實(shí)現(xiàn)了以上的代碼,會(huì)讓我們的代碼變得更加復(fù)雜、增加更多的開發(fā)工作量,下班更晚。如果我們不方便解除依賴,我們是否可以讓基礎(chǔ)設(shè)施將所有依賴構(gòu)建起來(lái)?;A(chǔ)設(shè)施能做的事情,就不要讓研發(fā)用代碼去實(shí)現(xiàn)。

以下舉我們一個(gè)實(shí)際場(chǎng)景的 MySQL 單元測(cè)試?yán)?。我們可以通過(guò) docker-compose.yml,構(gòu)建一個(gè) mysql。然后通過(guò) Ego 的應(yīng)用執(zhí)行 job。

  • 創(chuàng)建數(shù)據(jù)庫(kù)的表./app --job=install

  • 初始化數(shù)據(jù)庫(kù)表中的數(shù)據(jù) ./app --job=intialize

  • 執(zhí)行 go test ./...

圖片

圖片

可以看到我們可以每次都在干凈的環(huán)境里,構(gòu)建起服務(wù)的依賴項(xiàng)目,跑完全部的測(cè)試用例。詳細(xì) example 請(qǐng)看 https://github.com/gotomicro/go-engineering。

2.3 部署階段
2.3.1 注入信息

編譯是微服務(wù)的重要環(huán)節(jié)。我們可以在編譯階段通過(guò)-ldflags指令注入必要的信息,例如應(yīng)用名稱、應(yīng)用版本號(hào)、框架版本號(hào)、編譯機(jī)器 Host Name、編譯時(shí)間。該編譯腳本可以參考 https://github.com/gotomicro/ego/blob/master/scripts/build/gobuild.sh:

go build -o bin/hello -ldflags -X 'github.com/gotomicro/ego/core/eapp.appName=hello -X github.com/gotomicro/ego/core/eapp.buildVersion=cbf03b73304d7349d3d681d3abd42a90b8ba72b0-dirty -X github.com/gotomicro/ego/core/eapp.buildAppVersion=cbf03b73304d7349d3d681d3abd42a90b8ba72b0-dirty -X github.com/gotomicro/ego/core/eapp.buildStatus=Modified -X github.com/gotomicro/ego/core/eapp.buildTag=v0.6.3-2-gcbf03b7 -X github.com/gotomicro/ego/core/eapp.buildUser=`whoami` -X github.com/gotomicro/ego/core/eapp.buildHost=`hostname -f` -X github.com/gotomicro/ego/core/eapp.buildTime=`date +%Y-%m-%d--%T`'

通過(guò)該方式注入后,編譯完成后,我們可以使用./hello --version ,查看該服務(wù)的基本情況,如下圖所示。

圖片

2.3.2 版本信息

微服務(wù)還有一個(gè)比較重要的就是能夠知道你的應(yīng)用當(dāng)前線上跑的是哪個(gè)框架版本。我們?cè)诔绦蜻\(yùn)行時(shí),使用 go 里面的 debug 包,讀取到依賴版本信息,匹配到我們的框架,得到這個(gè)版本。

圖片

然后我們就可以在 prometheus 中或者二進(jìn)制中看到我們框架的版本,如果框架某個(gè)版本真有什么大 bug,可以查詢線上運(yùn)行版本,然后找到對(duì)應(yīng)的應(yīng)用,讓他們升級(jí)。

圖片

2.3.3 發(fā)布版本

發(fā)布配置版本,我們?cè)跊](méi)有 Kubernetes 的時(shí)候,不得不做個(gè) agent,從遠(yuǎn)端 ETCD 讀取配置,然后將文件放入到物理機(jī)里,非常的繁瑣。而使用 Kubernetes 發(fā)布配置,就會(huì)非常簡(jiǎn)單。我們會(huì)在數(shù)據(jù)庫(kù)記錄配置版本信息,然后調(diào)用 Kubernetes API,將配置寫入到 config map 里,然后再將配置掛載到應(yīng)用里。

發(fā)布微服務(wù)應(yīng)用版本,因?yàn)橛辛?Kubernetes 就更加簡(jiǎn)單,我們只需要發(fā)布系統(tǒng)調(diào)用一下 deployment.yml 就能實(shí)現(xiàn),應(yīng)用的拉取鏡像、啟動(dòng)服務(wù)、探活、滾動(dòng)更新等功能。

2.4 啟動(dòng)階段
2.4.1 啟動(dòng)參數(shù)

EGO內(nèi)置很多環(huán)境變量,這樣可以很方便的通過(guò)基礎(chǔ)設(shè)施將公司內(nèi)部規(guī)范的一些數(shù)據(jù)預(yù)設(shè)在Kubernetes環(huán)境變量?jī)?nèi),業(yè)務(wù)方就可以簡(jiǎn)化很多啟動(dòng)參數(shù),在dockerfile里啟動(dòng)項(xiàng)變?yōu)榉浅:?jiǎn)單的命令行:CMD ['sh', '-c', './${APP}']

圖片

2.4.2 加載配置

我們通過(guò) Kubernetes configmap 掛載到應(yīng)用 pod,通過(guò)框架 watch 該配置。在這里要提醒一點(diǎn),Kubernetes 的配置是軟鏈模式,框架要想要監(jiān)聽該配置,必須使用 filepath.EvalSymlinks(fp.path) 計(jì)算出真正的路徑。然后我們就可以通過(guò)配置中心更改配置,通過(guò) configmap 傳遞到我們的框架內(nèi)部,實(shí)現(xiàn)配置的實(shí)時(shí)更新。

2.4.3 探活

首先我們探活的概念。

  • livenessProbe:如果檢查失敗,將殺死容器,根據(jù) Pod 的 restartPolicy 來(lái)操作

  • readinessProbe:如果檢查失敗,Kubernetes 會(huì)把 Pod 從 service endpoints 中剔除

轉(zhuǎn)換成我們常見的研發(fā)人話就是,liveness 通常是你服務(wù) panic 了,進(jìn)程沒(méi)了,檢測(cè) ip port 不存在了,這個(gè)時(shí)候 Kubernetes 會(huì)殺掉你的容器。而 readinessProbe 則是你服務(wù)可能因?yàn)樨?fù)載問(wèn)題不響應(yīng)了,但是 ip port 還是可以連上的,這個(gè)時(shí)候 Kubernetes 會(huì)將你從 service endpoints 中剔除。

所以我們 liveness Probe 設(shè)置一個(gè) tcp 檢測(cè) ip port 即可,readness 我們需要根據(jù) HTTP,gRPC 設(shè)置不同的探活策略。

圖片

圖片

當(dāng)我們確保服務(wù)接口是 readness,這個(gè)時(shí)候流量就會(huì)導(dǎo)入進(jìn)來(lái)。然后在結(jié)合我們的滾動(dòng)更新,我們服務(wù)可以很優(yōu)雅的啟動(dòng)起來(lái)。(liveness、readness 必須同時(shí)設(shè)置,而且策略必須有差異,否則會(huì)帶來(lái)一些問(wèn)題)

2.5 調(diào)用階段

我們?cè)谑褂?Kubernetes 的時(shí)候,初期也使用最簡(jiǎn)單的 dns 服務(wù)發(fā)現(xiàn),他的好處就是簡(jiǎn)單方便,gRPC 中直接內(nèi)置。但是在實(shí)際的使用過(guò)程中,發(fā)現(xiàn) gRPC DNS Resolver 還是存在一些問(wèn)題。

gRPC DNS Resolver 使用了 rn 的 channel 傳遞事件。當(dāng)客戶端發(fā)現(xiàn)連接有異常,都會(huì)執(zhí)行 ResolveNow,觸發(fā)客戶端更新服務(wù)端副本的列表。但是當(dāng) K8S 增加服務(wù)端副本時(shí),客戶端連接是無(wú)法及時(shí)感知的。

圖片

圖片

因?yàn)?gRPC DNS Resolver 存在的問(wèn)題,我們自己實(shí)現(xiàn)了 Kubernetes API Resolver。我們根據(jù) Kubernetes 的 API,watch 服務(wù)的 endpoints 方式,實(shí)現(xiàn)服務(wù)發(fā)現(xiàn)。

圖片

我們?cè)賮?lái)梳理下微服務(wù)在 Kubernetes 的注冊(cè)與發(fā)現(xiàn)的流程,首先我們服務(wù)啟動(dòng)會(huì),探針會(huì)通過(guò) ip port 檢測(cè)我們的端口查看我們是否是活的,如果是活的就說(shuō)明我們的 pod 已經(jīng)跑起來(lái)了,然后會(huì)通過(guò)探針訪問(wèn)我們 gRPC 服務(wù)的 health 接口,如果是可用的,這個(gè)時(shí)候 Kubernetes 會(huì)將我們這個(gè)服務(wù)的 pod ip 注冊(cè)到 service endpoints,流量就會(huì)隨之導(dǎo)入進(jìn)來(lái)。然后我們的客戶端會(huì)通過(guò) Kubernetes API Watch 到 service endpoints 的節(jié)點(diǎn)變化,然后將該節(jié)點(diǎn)添加到它自己的服務(wù)列表里,然后它就可以通過(guò) Balancer 調(diào)用服務(wù)節(jié)點(diǎn),完成 RPC 調(diào)用。

由于篇幅較多,以上介紹了微服務(wù)生命周期的一部分,下期我們?cè)诮榻B微服務(wù)治理中的監(jiān)控、日志、鏈路、限流熔斷、報(bào)警、微服務(wù)管理等內(nèi)容。以下是 ego 架構(gòu)圖和研發(fā)生命周期的全景圖。

圖片

圖片

資料鏈接
  • Ego 框架:https://github.com/gotomicro/ego

  • PPT:https://github.com/gopherchina/meetup/blob/master/XiAn/20210911/%E7%9F%B3%E5%A2%A8%E6%96%87%E6%A1%A3Go%E5%9C%A8K8S%E4%B8%8A%E5%BE%AE%E6%9C%8D%E5%8A%A1%E7%9A%84%E5%AE%9E%E8%B7%B5-%E5%BD%AD%E5%8F%8B%E9%A1%BA.pdf

  • 文檔:https://ego.

  • 編譯:https://ego./micro/chapter1/build.html

  • 鏈路:https://ego./micro/chapter2/trace.html

  • 限流:https://ego./frame/client/sentinel.html

  • 日志:https://ego./frame/core/logger.html

  • docker-compose 單元測(cè)試,protobuf 統(tǒng)一錯(cuò)誤碼:https://github.com/gotomicro/go-engineering

  • proto 錯(cuò)誤碼插件:https://github.com/gotomicro/ego/tree/master/cmd/protoc-gen-go-errors

  • proto 單元測(cè)試插件:https://github.com/gotomicro/ego/tree/master/cmd/protoc-gen-go-test

    本站是提供個(gè)人知識(shí)管理的網(wǎng)絡(luò)存儲(chǔ)空間,所有內(nèi)容均由用戶發(fā)布,不代表本站觀點(diǎn)。請(qǐng)注意甄別內(nèi)容中的聯(lián)系方式、誘導(dǎo)購(gòu)買等信息,謹(jǐn)防詐騙。如發(fā)現(xiàn)有害或侵權(quán)內(nèi)容,請(qǐng)點(diǎn)擊一鍵舉報(bào)。
    轉(zhuǎn)藏 分享 獻(xiàn)花(0

    0條評(píng)論

    發(fā)表

    請(qǐng)遵守用戶 評(píng)論公約

    類似文章 更多