微服务架构下 CI/CD 如何落地
本文系云原生應(yīng)用最佳實(shí)踐杭州站活動(dòng)演講稿整理。杭州站活動(dòng)邀請(qǐng)了 Apache APISIX 項(xiàng)目 VP 溫銘、又拍云平臺(tái)開發(fā)部高級(jí)工程師莫紅波、螞蟻金服技術(shù)專家王發(fā)康、有贊中間件開發(fā)工程師張超,分享云原生落地應(yīng)用的經(jīng)驗(yàn)心得,以下是莫紅波《微服務(wù)架構(gòu)下 CI/CD 如何落地》分享內(nèi)容。
莫紅波,又拍云平臺(tái)開發(fā)部高級(jí)工程師,目前專注于容器及虛擬化技術(shù)在又拍云的私有云實(shí)踐,主要負(fù)責(zé)又拍云容器云的設(shè)計(jì)和開發(fā)工作。
大家好,今天分享的主題是《微服務(wù)架構(gòu)下 CI/CD 如何落地》,圍繞以下兩部分展開:
-
理論篇,討論從單體到微服務(wù)的過程中會(huì)面臨怎樣的挑戰(zhàn),以及微服務(wù)的測(cè)試模型
-
實(shí)踐篇,圍繞集成測(cè)試環(huán)境的服務(wù)發(fā)現(xiàn)需要怎么做,如何落地持續(xù)交付和持續(xù)部署
背景
或許大家對(duì)于互聯(lián)網(wǎng)公司的共同印象是 996,對(duì)于我個(gè)人而言,互聯(lián)網(wǎng)公司還有另一個(gè)特點(diǎn),那就是經(jīng)常需要擁抱變化。在互聯(lián)網(wǎng)公司,新產(chǎn)品上線、下線、調(diào)整,這都是很家常便飯的事情。在這種情況下,一個(gè)好的松耦合的架構(gòu)就顯得尤為重要。
剛好我最近就有遇到這個(gè)問題,我在做的項(xiàng)目,賬號(hào)這塊是對(duì)標(biāo) GitHub 的注冊(cè)制賬號(hào)機(jī)制的。原本的需求是用戶注冊(cè)我們的平臺(tái),注冊(cè)完成后可以創(chuàng)建一個(gè)屬于自己的團(tuán)隊(duì),并將其他人拉入自己的團(tuán)隊(duì)。但是當(dāng)我們做完這部分內(nèi)容后發(fā)現(xiàn),客戶還是更偏好「賬號(hào)+子賬號(hào)」的模式,公司一個(gè)總的賬號(hào),所有員工單獨(dú)開子賬號(hào)進(jìn)行關(guān)聯(lián)。這讓我們已經(jīng)做好的項(xiàng)目變得非常尷尬,需要立即擁抱變化,需要根據(jù)最新的需求進(jìn)行調(diào)整。這時(shí),我就發(fā)現(xiàn)擁有一套松耦合的架構(gòu)的重要性,比如賬號(hào)這一部分,如果把它單獨(dú)拎出來,做好足夠的抽象,提供必要的對(duì)外接口,可能會(huì)更加靈活,擴(kuò)展性更加好。
**那怎樣擁有一套松耦合的架構(gòu)?有什么好的方案呢?在我看來有兩個(gè),一個(gè)是幾年前出現(xiàn)的 SOA,即將服務(wù)進(jìn)行單獨(dú)化,將每一塊都進(jìn)行拆分;另一個(gè)就是最近幾年火熱的微服務(wù)了。**我認(rèn)為,微服務(wù)跟 SOA 其實(shí)是一回事,只不過微服務(wù)比 SOA 拆分粒度更細(xì),功能也更小。
在調(diào)研微服務(wù)過程中,很多人會(huì)有疑問:“我們是一個(gè)很小的團(tuán)隊(duì),小團(tuán)隊(duì)適不適合上微服務(wù)呢?”。因?yàn)樯衔⒎?wù)就意味著一個(gè)服務(wù)可能就會(huì)被拆分成 10 個(gè)、20 個(gè)甚至更多個(gè)的服務(wù),這就讓小團(tuán)隊(duì)不得不去考慮自己的測(cè)試、部署、更新成本是不是會(huì)翻很多倍。
那么我對(duì)于“小團(tuán)隊(duì)適不適合上微服務(wù)”這個(gè)問題的答案是什么呢?我認(rèn)為是完全可以上的,不過你需要注意一點(diǎn):做好自動(dòng)化,能交給自動(dòng)化來實(shí)現(xiàn)的,就不要人工介入了。
在聊如何做自動(dòng)化集成測(cè)試(CI)之前,我先和大家談一談從單體如何到微服務(wù),服務(wù)是如何拆分的,以及微服務(wù)的測(cè)試一般是怎么做的。
從單體到微服務(wù)
如上圖所示,我們可以看到圖左邊是一個(gè)單體服務(wù),右邊則是經(jīng)過微服務(wù)拆解后的。我們可以看到它有 4 個(gè)特點(diǎn):
-
根據(jù)不同領(lǐng)域拆分
-
服務(wù)之間通過網(wǎng)絡(luò)協(xié)議通信
-
擁有獨(dú)立的數(shù)據(jù)庫(kù)
-
擁有特定對(duì)外開放的接口
我們都知道,如果需要一個(gè)服務(wù)能夠穩(wěn)定運(yùn)行,那測(cè)試肯定是少不了的。而就像我們微服務(wù)化有一套理論一樣,微服務(wù)測(cè)試也擁有屬于自己的金字塔理論:最底層是單元測(cè)試,成本相對(duì)較低,像我們?cè)?API 認(rèn)證部分做的簽名校驗(yàn)?zāi)K,它一般不需要依賴其他東西,因此測(cè)試效率也比較高;第二層是集成測(cè)試,這一層你就必須要依賴一些第三方的服務(wù)模塊或者組件,比如我們一般會(huì)用到數(shù)據(jù)庫(kù)的測(cè)試,就屬于集成測(cè)試的范疇;第三層是 e2e 測(cè)試,它會(huì)模擬客戶端的行為來進(jìn)行測(cè)試,大家也許都接觸過這類測(cè)試,像K8S 就有一個(gè) e2e 測(cè)試,當(dāng)你去申請(qǐng) CNCF 的一致性認(rèn)證時(shí),就需要通過官方提供的 e2e 測(cè)試;最上層是 UI 測(cè)試,比如對(duì)于頁(yè)面的點(diǎn)擊調(diào)整是否符合預(yù)期,這部分我們現(xiàn)在做的比較弱,還處在人工模式下,但我們也在努力將它更新成自動(dòng)化。
從這個(gè)微服務(wù)測(cè)試金字塔我們可以看到,越靠近底層成本越低,你只需要幾行代碼就能完成,效率也非常高。同時(shí)越底層它對(duì)于三方或組件的依賴也越低,自動(dòng)化也就越簡(jiǎn)單。到這里可能就有人想問:“既然越底層的成本越低,那我們能不能只跑單元測(cè)試?”在解答這個(gè)問題前,大家先看下面這張圖。
這兩扇窗戶,每一扇單獨(dú)存在的時(shí)候都是完好的窗戶,可以正常開合。但是兩個(gè)都安裝到墻上后就沒有辦法正常開合。這就是我們不能只跑單元測(cè)試的原因了,不跑集成測(cè)試就無法發(fā)現(xiàn)一些問題。同理不跑單元測(cè)試也會(huì)有一些無法發(fā)現(xiàn)的問題,所以我們?cè)谂軠y(cè)試的時(shí)候,集成測(cè)試和單元測(cè)試,一項(xiàng)都不能少。
那具體實(shí)踐的時(shí)候要如何做呢,我推薦大家分成兩步來進(jìn)行:
-
第一步是將底子打好:你需要對(duì)你的的微服務(wù)進(jìn)行單元化測(cè)試,編寫單元化的測(cè)試用例,然后再?gòu)?qiáng)化集成測(cè)試。沒有好底子的微服務(wù)是不可靠的,任何時(shí)候都可能會(huì)出問題,而且出問題后的排查會(huì)非常費(fèi)時(shí)。
-
第二步是自動(dòng)化的持續(xù)集成環(huán)境:將能夠自動(dòng)化的部分全部進(jìn)行自動(dòng)化,減少人工的介入。
GitLab/CI
自動(dòng)化集成環(huán)境這塊目前已經(jīng)有很多的開源方案了,比如常見的 Jenkins,還有 GitLab。我們選擇的是 GitLab,或者說是選擇了 GitLab/CI,選擇它的原因有以下幾點(diǎn):
-
統(tǒng)一的 web 頁(yè)面
-
可以再 MR 中跳轉(zhuǎn)查看
-
Pipeline 編排直觀展示
-
所有操作都在項(xiàng)目中搞定
-
GitLab 官方支持
GitLab WorkFlow
既然我們選擇使用了 GitLab,那我們內(nèi)部就會(huì)嚴(yán)格遵守 GitLab 的 WorkFlow。WorkFlow 主要分為兩個(gè)部分。
第一部分是面向代碼倉(cāng)庫(kù)。代碼倉(cāng)庫(kù)中,我們一般會(huì)有三類分支,第一類分支是 master 分支,一般只會(huì)有一個(gè),我們會(huì)定義 master 分支,并基于這個(gè)分支進(jìn)行線上版本的發(fā)布。第二類分支是 develop 分支,一般也只會(huì)有一個(gè),develop 分支是從 master 分支中 checkout 出來的,功能比 master 領(lǐng)先,包含一些已經(jīng)完成功能開發(fā),但是還沒有發(fā)布的功能。第三類分支是 feature 分支,特性分支,一般會(huì)有很多個(gè),新功能都會(huì)在這個(gè)分支上進(jìn)行開發(fā),往往一個(gè)功能對(duì)應(yīng)一個(gè) feature 分支。最后一類是 hotfix 分支,這個(gè)就比較常見了,線上發(fā)布后,如果發(fā)現(xiàn)了一個(gè)需要緊急修復(fù)的bug,這時(shí)你就可以在 master 分支上 checkout 出來一個(gè) hotfix 分支,把代碼改掉。不過進(jìn)行這個(gè)操作時(shí)你需要注意,master 分支和 develop 分支都需要進(jìn)行該 commit 合并,否則就不能算完成了 bug 修復(fù)。
第二部分與 CI/CD 有關(guān)。以我們的流程舉例,研發(fā)的同學(xué)提交代碼到 GitLab 倉(cāng)庫(kù),之后 GitLab 會(huì)觸發(fā)事先約定好的 CI 的 pipeline 進(jìn)行測(cè)試和構(gòu)建。等待測(cè)試和構(gòu)建成功后再進(jìn)行 code review 的確認(rèn),確認(rèn)無誤后會(huì)合并到 develop 分支并最終合并到 master 分支進(jìn)行發(fā)布。這就是 GitLabCI 的一個(gè)配置,總結(jié)來看可以劃分為下圖的四個(gè)階段。
下圖是配置文件對(duì)應(yīng)的 pipeline 的展示,大家可以看一下。
微服務(wù)下的場(chǎng)景變形
其實(shí)到目前為止的方案,已經(jīng)是微服務(wù)沒有大熱前的完備方案了。如果你想要將方案運(yùn)用到微服務(wù)的集成測(cè)試?yán)?#xff0c;你還需要做一些變形,不妨參考下圖中所示的又拍云現(xiàn)在使用的整套流程。
從圖中可以看到,我們目前使用的整套流程相比標(biāo)準(zhǔn)的其實(shí)有做一些小的變形,變形主要集中在中間的集成測(cè)試環(huán)境這一塊,我們將每個(gè)服務(wù)器都部署在了集成環(huán)境內(nèi),使集成環(huán)境變成一個(gè)準(zhǔn)發(fā)布環(huán)境。具體流程是,當(dāng)我們的創(chuàng)建 projectA 后,由它來 push 代碼,完成后觸發(fā) CI,也就是在 GitLab runner 上進(jìn)行測(cè)試。
在跑測(cè)試的過程中,因?yàn)?A 服務(wù)需要調(diào)用 B 和 C 服務(wù),所以通過 API 去請(qǐng)求集成環(huán)境中的對(duì)應(yīng)服務(wù)。如果測(cè)試完成后沒有問題,則合并到主線。再通過在 master 分支打 tag 的方式來觸發(fā)容器構(gòu)建并推送到 Harbor 鏡像倉(cāng)庫(kù)。最后我們會(huì)做一個(gè)線上 release。這個(gè)就是我們的大致流程了。
那么接下來我們來具體看一下變形中會(huì)遇到的問題。
服務(wù)發(fā)現(xiàn)
在微服務(wù)場(chǎng)景下的變形中遇到了很多問題,我覺得其中值得注意的是“服務(wù)發(fā)現(xiàn)”。比如我們現(xiàn)在有這樣一個(gè)場(chǎng)景,A 服務(wù)在跑測(cè)試時(shí)需要依賴 B 服務(wù)和 C 服務(wù),面對(duì)這個(gè)需求,在沒有引入 Kubernetes 之前,我們可以通過使用一臺(tái)共用機(jī)器,將服務(wù)都布置到這臺(tái)機(jī)器上,并在測(cè)試代碼里寫死 IP 地址,讓每一次測(cè)試都在這個(gè)環(huán)境內(nèi)跑。但這個(gè)方法會(huì)有下面四個(gè)無法忽視的問題:
-
服務(wù)更新延遲
-
環(huán)境權(quán)限混亂
-
人工操作容易出錯(cuò)
-
維護(hù)成本過高
因此我們引用了 Kubernetes Service 的方案進(jìn)行優(yōu)化。
Kubernetes Service 的流程大家可以大概看一下。我們先定義一個(gè) Service, 我們這邊創(chuàng)建的 ClusterIP 類型的,定義了暴露端口 8000,目標(biāo)端口 8000,協(xié)議是 TCP,標(biāo)簽選擇器是 app=holdon。通過這種方式,我們可以把一組相同功能的服務(wù),綁定在同一個(gè) Service 下。在 Kubernetes 集群內(nèi),定義好 Service 后,會(huì)提供內(nèi)部的 DNS 解析,你可以通過一個(gè)固定的域名訪問指定的 Service。這樣當(dāng)在跑測(cè)試的時(shí)候就可以通過這個(gè)域名加對(duì)應(yīng)端口,調(diào)用到對(duì)應(yīng)服務(wù)了。
持續(xù)交付
持續(xù)交付(英語(yǔ):Continuous Delivery,縮寫為 CD)。每個(gè)項(xiàng)?都要有?個(gè) Dockerfile,提供了服務(wù)運(yùn)?所需的環(huán)境,以及服務(wù)對(duì)應(yīng)的軟件包。當(dāng)需要發(fā)版本的時(shí)候,我們會(huì)在主線上打上?個(gè) tag,觸發(fā)鏡像構(gòu)建,然后推送到 Harbor 鏡像倉(cāng)庫(kù)。其中,這個(gè) tag 也會(huì)對(duì)應(yīng)到鏡像的版本號(hào)。
上圖是我們的 CD 流程大家可以參考看一下。需要提一下的是,我們引用 Harbor 的原因是因?yàn)樗鄬?duì)官方的 Registry 更安全。大家應(yīng)該都知道,官方的 Registry 本身不帶權(quán)限校驗(yàn),當(dāng)你公司內(nèi)部使用的時(shí)候,這個(gè)問題會(huì)導(dǎo)致你的鏡像有被其他部門的人覆蓋掉的可能性,所以我們引入了 Harbor。但這里也有一個(gè)問題,使用同一個(gè) tag 去推依然會(huì)被覆蓋的情況。不過好歹做到了小組和小組之間、部門和部門之間的隔離。
持續(xù)部署
持續(xù)部署(英語(yǔ):Continuous deployment,縮寫為 CD),目前這塊,在實(shí)踐過程中,我們是只針對(duì)集成測(cè)試環(huán)境,線上更新還是走常規(guī)的流程。給項(xiàng)?增加?個(gè) k8s-deploy.yaml 的?件,??包含了服務(wù)相關(guān)的配置、部署?式、訪問?式等等,等待鏡像構(gòu)建完成后,apply 該?件就可以了 。
回顧
現(xiàn)在我們?cè)倩氐椒?wù)變形的流程圖來看一下,當(dāng)我們有 A、B、C 三個(gè)服務(wù),且 A 服務(wù)在測(cè)試時(shí)需要調(diào)用集成環(huán)境內(nèi)的 B 服務(wù)與 C 服務(wù)時(shí),可以通過 K8S 提供的內(nèi)部域名進(jìn)行訪問。等待整塊測(cè)試跑完后,我們?cè)谥骶€上打 tag,讓 CI 去幫執(zhí)行 image build 構(gòu)建鏡像并推送到 Harbor 倉(cāng)庫(kù)。
其中涉及到的準(zhǔn)發(fā)布環(huán)境,可以通過 kubectl apply 的方式進(jìn)行部署。由于線上環(huán)境更復(fù)雜,推薦大家通過自研的容器云平臺(tái)來進(jìn)行操作,我們就是這么處理的,通過云平臺(tái)發(fā)布,功能更加全面安全,更加符合線上部署的流程。
成果展示
最后,跟大家分享下最近正在做的項(xiàng)目的情況。從 2019 年 12月 開始到現(xiàn)在,我們每天基本保持在一個(gè)較高的 commit 數(shù)上,而這其中一共進(jìn)行了大約 4500 次的測(cè)試。想象下,如果沒有這套自動(dòng)化持續(xù)集成環(huán)境,測(cè)試需要怎么來進(jìn)行,需要投入人力資源。
點(diǎn)擊閱讀可直接跳轉(zhuǎn),獲取現(xiàn)場(chǎng)分享視頻、下載 PPT。
總結(jié)
以上是生活随笔為你收集整理的微服务架构下 CI/CD 如何落地的全部?jī)?nèi)容,希望文章能夠幫你解決所遇到的問題。
- 上一篇: 网骗欺诈?网络裸奔?都是因为 HTTP?
- 下一篇: 白话科普系列——网站靠什么提升加载速度?