雲原生下的開發測試實踐


本文整理自阿里巴巴技術專家金戟和砧木的視頻分享《雲原生下的開發測試》。

測試環境管理之困與阿里巴巴的解決之道


在雲原生時代下,軟件的迭代速度越來越快,對測試的要求也越來越高,很多開發者開始使用Kubernetes來管理測試環境。在這個過程中,開發者會遇到很多困難,其中最主要的兩個問題是:

1、本地環境與 Kubernetes 集羣網絡不通問題;

2、共用測試環境時,相互干擾的問題。

在阿里巴巴內部,我們主要通過扁平的內網 IP 和項目環境兩個機制來解決以上痛點。扁平的內網 IP 主要是基於 CNI (Conteinre Network Interface) 機制改造 Kubernetes 的 IP 邏輯實現的,可以使集羣中的每個 Pod 分配到的 IP 與本地機器分配到的 IP 處於一個大的網絡環境下,這樣就可以解決本地環境和集羣之間互通的問題。項目環境是基於 RPC 、消息中間件的虛擬環境,從表面上看,每個項目環境都是一套獨立完整的測試環境,由一系列服務組成集羣,而實際上,除了個別當前使用者想要測試的服務,其餘服務都是通過路由系統和消息中間件虛擬出來的,指向公共基礎環境的相應服務。這樣操作的好處是,第一,不會佔用大量的開發資源;第二,不會影響公共基礎環境的穩定性。

阿里巴巴的這種測試環境帶來的測試體驗非常爽,本地與集羣雙向互通,每個子項目都可以獨佔一個“項目環境”,彼此不會干擾。但是這種測試環境管理方式實施起來比較複雜,只適合大型的集團公司,我們希望將這種測試體驗以 “更輕”的方式實現,普惠更多開發者。於是雲效團隊推出了雲原生測試環境工具箱,主要包括 kt-connect 和 kt-virtual-environment 這兩個開源工具。

通過 kt-connect 解決本地與集羣雙向互通問題


首先,我們來聊一聊如何使用 Kubernetes 測試環境開源工具箱中的 kt-connect 解決 “本地與集羣雙向互通”的問題。

我們假設有一位主人公叫“程序員小黑”,他所在公司採用了微服務相關的技術實踐。小黑在做本地開發的過程中,會遇到兩種聯調場景,即我需要聯調其它服務和其它服務調用我。

我們先來看第一個場景:聯調其它服務。前面講到本地環境和 K8s 集羣中的網絡是相互隔離的,那麼在本地完成代碼開發後,如何高效的與其它服務進行聯調呢?

最“簡單粗暴”的一種方式,就是在本地完整的部署一套測試環境,這種方式的優點很明顯,效率最高,而且沒有外部依賴。缺點也同樣明顯,一是對開發人員的素質要求非常高,二是要佔用大量本地的開發資源,對本地開發機的性能要求很高。

第二種方式是利用 Kubernetes 等工具在本地部署一套 K8s 集羣,這種方式可以在一定程度上降低開發人員“上手成本”,但是也同樣存在佔用大量本地開發資源的問題。還有一種處理方式是利用 VPN 調用 K8s 集羣中的服務,這種方式存在兩個問題,一個是本地的服務調用是脫離了 Istio 的流量控制的,第二個問題 VPN 這種方式只解決了本地到集羣的通訊,對於回調這種方式是解決不了的。


那麼,有沒有更簡單的方式呢?答案是肯定的,通過 KT-Connect 工具可以讓開發者一鍵建立本地到 Kubernetes 集羣的網絡連接。開發者只需要運行一個“connect”命令,就可以自動在集羣中創建一個代理容器,並且通過這個代理容器建立本地與集羣的 VPN 連接,同時 KT-Connect 也會內置 DNS 服務,本地服務可以直接通過服務的名稱進行服務調用,就好像本地的程序運行在 K8s 集羣中一樣。在 KT-Connect 中,我們給這個代理容器取了一個名字“shadow pod”,即“影子”。它就像是本地服務在集羣中的影子,通過它來完成本地服務與集羣中服務的相互調用。

接下來,我們來看第二個場景:其它服務調用我。在聯調時,小黑不僅需要調用其它人的服務,同時作爲服務的生產者又會被其它服務調用。這時只打通本地到集羣的服務是不能滿足聯調測試需求的,必須同時讓集羣中的服務也可以訪問本地的服務。

這就需要使用 KT-Connect 的第二個命令——“Exchange”。Exchange(交換)命令會在集羣內部署一個代理容器,並替換集羣中指定服務的目標容器,從而將發往該服務的所有流量攔截並轉發到本地端口。這是一種“完全替換”,這就意味着在同一時間點,只有一位開發者可以將他本地的服務加入到集羣中。爲了解決這個問題,KT-Connect 提供了第三個命令——Mesh(混合)。當我們在本地運營“Mesh”命令後,我們同樣會把本地服務加入到集羣裏面,但是會保持原有的目標服務狀態不變,並且本地服務會繼承目標服務中所有的標籤。依照 K8s 本身服務發現的原理,請求流量會被隨機地轉發到原有服務或本地的服務。同時配合 Istio 的流量規則,就可以讓所有正常流量依然保持對原應用的訪問,而只對一些有特殊標記的的請求轉發到本地。從而可以實現在一套公用測試環境的基礎上各自獨立的完成本地的集成聯調。

KT-Connect背後的原理


我們通過 KT-Connect 的“connect”“Exchange” “Mesh”命令實現了本地到集羣的雙向網絡互通,看起來似乎很神奇,其實背後並沒有什麼黑科技。我們只是綜合利用了 Kubernetes 原有的特性及 SSH 這個我們經常會用到的網絡協議,通過 Kubectl 的端口轉發可以實現將集羣中服務的端口映射到本地,通過 SSH 協議建立本地與集羣之間的隧道。

以“Connect”命令爲例,瞭解一下 KT-Connect 背後的原理。如上圖所示,當開發者在本地運行“Connect”命令後,首先會創建一個代理容器(shadow pod),這個代理容器會運行“SSH Server”和“DNS Server”。當代理容器啓動成功之後,就可以通過“port-forward”將代理容器的 22 端口轉映射到本地,如 2222 端口。此時,本地服務就可以通過本地的 2222 端口建立與集羣內部的連接。

“Exchange”和與“Connect”命令背後的原理類似,我們也會先創建一個代理容器,並通過“port-forward”將代理容器的端口映射到本地。然後根據 Exchange 的目標服務,判斷將代理容器的哪一個端口的請求全部轉發到本地的特定端口。

“Mesh”與“Exchange”的最大的差異在於“Exchange”會將原應用的副本數直接降到 0 ,會將集羣內所有對原應用的流量全部轉發到本地。而 “Mesh”則是在保持原有應用 Pod 不變的前提下,創建一個新的代理容器並且繼承原應用的所有標籤,還會增加一個隨機的 version 標籤。這時我們就可以通過 Istio 規則, 精確控制流量。

如前文所述,通過 KT-Connect 我們可以實現從本地到集羣的雙向互通。我們可以看到這樣一個有趣的場景:小黑A可以通過“ Mesh ”命令把本地服務加入到測試環境裏,並且可以讓集羣中一部分特定的流量轉發到本地,這樣他可以與集羣中的其它服務進行聯調。小黑B通過“Connect”命令連接到集羣,直接在本地進行測試。在某些情況下,小黑B需要依賴的服務剛好是小黑A正在開發的版本,小黑 B 只要按照 Istio 的流量規則設置可以調用小黑 A 服務的值,就可以跟小黑A的服務進行聯調。對於小黑 C ,他既需要調用集羣中的服務,又需要集羣中的服務回調到本地,所以他在本地既運營了 “Connect”又運行了“Mesh”。

上文描述的其實是一種理想情況,需要建立在我們的測試環境是一種穩定狀態的基礎之上。但在現實情況下,由於頻繁的代碼變更測試環境往往處於一種不太穩定的狀態。接下來我們會介紹如何使用雲原生測試環境工具箱中的 kt-virtual-environment 打造穩定的測試環境,讓開發者可以更好地進行協同研發工作。

共用測試環境相互干擾問題及常見解決方案


在一箇中大規模研發團隊負責的項目中,往往一個系統裏包含許多(微)服務,而且服務之間存在鏈式依賴,難以獨立啓動運行。這時就很容易出現“共用測試環境相互干擾”的問題,比如一個開發者重新部署、重啓測試環境時,可能會打斷所有正在測試的開發者;一個開發者提交了有BUG的代碼,所有開發者都可能受影響;一個開發者爲了排查問題,單步調試測試環境服務時,所有開發者測試請求會被攔截。

如何來解決這個問題呢?以往的思路是準備多套測試環境。雖然這種方式可以暫時緩解開發過程中的相互影響,但是這會帶來額外的資源分配和管理問題,特別是當沒有那麼多並行開發時會產生非常嚴重的資源浪費。

於是出現了一種“改進”方法,企業通過用 helm 或自制工具自動化地快速創建一套環境,用完即刪。該方法在一定程度上解決閒置資源回收的問題,但是也沒有那麼“完美”。在實際操作過程中,環境的創建其實並沒有那麼“快速”,往往需要等待幾分鐘甚至幾十分鐘的時間。而且如果爲每個子項目的成員分別拉一套環境,資源浪費依然嚴重。

在多人協同場景下,如何做到測試環境不相互干擾又不產生極大的資源浪費呢?在阿里巴巴內部主要通過“項目環境”的方案解決。

“項目環境”的本質是基於路由隔離實現的一個“虛擬環境”。我們通過一個實例來簡單瞭解一下。

如上圖中藍色部分所示,由服務A、服務B、服務C、服務D組成一個完整的測試環境,我們稱爲“公共基礎環境”(也稱默認環境)。當某位開發者需要進行項目開發的時候,他不需要把應用或服務部署到公共基礎環境中,而是單拉出來一部分資源(服務C和服務D)並複用部分公共基礎環境資源(服務A和服務B)形成 “項目環境”。這樣操作的好處是,第一不會佔用大量的開發資源;第二,不會影響公共基礎環境的穩定性。

我們主要通過打“環境標”的形式形成獨立的“隔離域”,比如[dev]代表公共基礎服務實例的標籤值,[dev.proj]代表項目環境的服務實例。同一個環境標形成一個獨立的“隔離域”,這是基於路由規則實現的。如果服務請求是來自一個有環境標的服務實例,它的服務請求會優先尋找跟它具有相同環境標的實例,如果沒有,會尋找它上一級的環境標,這叫做“路由兜底”。比如上圖中服務請求來自帶有[dev.proj]環境標的實例 C ,需要調用服務 B ,但是發現沒有帶環境標[dev.proj]的服務 B ,於是尋找帶有上一級環境標[dev]的服務 B 。

我們還可以將本地開發機加入項目環境。比如開發者“小黑”在本地啓動了一個服務實例C,他給這個服務實例打的環境標是[dev.proj.local],通過前面介紹路由規則我們瞭解到帶環境標的服務發出的請求會優先尋找帶相同環境標的服務,如果找不到則會尋找帶有上一級環境標的服務,於是服務C[dev.proj.local]、服務D[dev.proj]和公共基礎環境中服務A[dev]、服務B[dev]就組成了一個新的的“項目環境”(圖中紅色部分)。

這時“小黑”的同事也加入了項目,他在本地啓動了一個服務 A ,如果他沒有對這個服務打“環境標”的話,他會默認使用“公共基礎環境”進行測試。這時小黑在他自己的“項目環境”中的任何調試都不會影響到小黑的同事,反之亦然。

後來小黑的同事和小黑加入了同一個子項目,他們之間需要“聯調”。這時,小黑的同事只要給他本地的服務打上一個和小黑的“項目環境”相同的環境標即可,如上圖紅色部分。

總結一下前面介紹的概念:“隔離域”是由路由規則形成的虛擬邊界;每個“環境標”都會形成一個獨立的“隔離域”;“隔離域”之間可以存在部分或完全重合;“隔離域”的成員會隨集羣中服務實例所帶“環境標”動態變化。

如何使用 kt-virtual-environment 打造項目環境


kt-virtual-environment 是一種基於 Service Mesh 的微服務環境複用工具,源於阿里巴巴內部的項目環境實踐。通過Pod上的虛擬環境標籤,kt-virtual-environment 能夠自動將測試環境網絡動態隔離成多個虛擬隔離域,同時以簡單規則在隔離域間局部複用 Pod 實例,從而達到只需很少資源成本即可創建大量不同微服務版本組合的獨立測試環境的目的。

下面我們來了解一下如何使用 kt-virtual-environment 打造項目環境。通過前面的介紹,我們知道相同的“環境標”會形成一個獨立的“隔離域”。所以首先我們需要爲服務實例打上環境標,在 kt-virtual-environment 中是通過爲爲 pod (或容器)添加約定的 Label 的方式實現的。在服務調用過程中,需要爲應用程序添加一些邏輯,才能讓“環境標”順利在上下文之間傳遞,這個過程類似 SkyWalking、Zipkin 等鏈路追蹤工具的 SDK 端所做的事情,讓“環境標”通過 HTTP 頭在請求鏈路上一直保持傳遞。第三步,我們需要在集羣中配置 Virtual Environment 類型的資源實例,詳細配置的結構如上圖所示。

kt-virtual-environment 實現的基本原理是:觀察並持續監聽環境中的所有服務和開發資源,動態生成 Service Mesh 控制面規則,實現核心隔離邏輯 。當前 kt-virtual-environment 僅支持基於 Istio 的規則,未來會增加基於其它 控制面的 Service Mesh 規則的實現。

阿里巴巴使用項目環境的最佳實踐


“項目環境”在阿里巴巴內部已近發展多年,下面我將一些優秀的實踐分享給大家。理論上,“環境標”的層級可以無限多,但是我們的經驗是最好不要超過三級。因爲三層的“環境標”基本上可以滿足 95% 以上的研發場景。

以三層環境標實現的項目環境舉例。第一層一般只有一個環境標,比如[dev],這是對應默認隔離域(公共環境)使用的環境標,這樣做會讓整個路由規則比較簡單,大家不用猜測“路由兜底”最後會“兜”到哪裏去。這個頂級的[dev]環境標對應的測試環境是不需要開發者自己去部署的,一般是通過“流水線”等自動化工具部署的穩定版本。對於某個子項目,我們可以基於頂級環境標建立一個二級環境標,如[dev.proj1],這樣會形成這個子項目的隔離域(項目環境)。在這個隔離域中,只需要開發者自己部署需要改動的服務實例即可,其它不需要改動的服務實例可以複用公共環境中實例。有的時候,某位開發者可能要對某服務進行比較大的改動或者他不希望這個服務被其它同事訪問到,他可以基於“項目環境”再創建一個“個人環境”。在這個個人環境中,他既可以調用子項目中的服務,也可以調試本地開發的新的服務版本,並且不會影響到其他開發者。以上,是我們比較推薦的項目環境的用法。

總結


雲原生測試環境工具箱共包含兩款獨立的工具:kt-connect和kt-virtual-environment。kt-connect 是一款本地工具,主要是幫助開發者打通本地和集羣網絡,實現本地加入隔離域。kt-virtual-environment 是一種基於 Service Mesh 的微服務環境複用工具,通過觀察並持續監聽環境中的所有服務和開發資源,動態生成 Service Mesh 控制面規則,實現核心隔離邏輯 。只需要一次性部署,開發者不會頻繁使用到。目前兩款工具已經開源,大家可以進入 Github 社區進行下載使用。

如果你對本次分享感興趣,敬請關注“2020阿里巴巴研發效能峯會”,屆時衆多技術大咖將爲大家帶來更多精彩內容。6月12-13日,阿里巴巴研發效能峯會將在阿里雲開發者社區線上直播。點擊文末“閱讀原文”可進行直播預約

福利來襲


2020 阿里巴巴研發效能峯會即將開始,設有云原生專場、數字化領導力專場、產品創新專場、架構設計與代碼智能專場、持續交付域質量專場、運維穩定性專場,總有一個專場是你的期待~

歡迎在評論區留言 (二選一即可):

1、關於 2020 阿里巴巴研發效能峯會,你最關注的是哪個專場,爲什麼?

2、你對研發效能的哪些內容更感興趣?

3、雲原生下的開發測試幫你解決了什麼問題?

點贊數 Top 3 的評論者,每人將獲得一件 2020 阿里巴巴研發效能峯會 Just lean T恤(截止時間爲6月12日10:00)。

本文縮略圖:icon by 採濁工

Tips:

# 點下“看”❤️

# 然後,公衆號對話框內發送“Nacos”,試試手氣?????

# 本期獎品是超級受歡迎的《碼出高效》一本 

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章