資安

阿里云云效技術專家分享:雲原生開發、調測及可靠發佈解決方案

在雲原生環境中,基於Kubernetes的工具鏈一方面簡化了開發者的許多日常瑣碎,另一方面也帶來了許多新的概念和工作方式的改變。本篇文章將聚焦於雲原生基礎設施,談談如何在面向雲原生的開發流程中,高效地進行開發調測以及發佈。

首先,從通用意義上講,作為一個開發者,你期望怎樣的研發流程?

DM_20210806161527_001.png我理解的理想研發過程


基於這個理想的研發流程,當研發基礎設施遷移到雲原生和微服務架構之後,在開發、調試和發佈方面會遇到什麼問題,又要如何解決?

一個典型的研發過程包含三個環節:開發、測試和部署

開發主要指的是代碼的編寫和自測。當你寫好代碼和單元測試之後,需要在一個運行環境中進行功能性驗證。本地IDE提供了大量用於調測的功能,並且本地服務的重新啟動速度也比較快。相比將代碼部署到遠端的測試環境,能夠完全在本地進行編寫、啟動、debug,是最理想的工作方式。

實際的工作中,為了驗證一個特定功能場景,往往需要配合其它的外部依賴,比如當前我編寫的這個服務依賴什麼別的服務;還有什麼其他服務需要調用我的服務,我才能做一個完整的驗證?

這些問題都需要很好的解決,才能真正享受到本地開發的便利。

測試一般指的是在CI環境中的各種自動化測試和驗收環境中的測試驗證,本文的重點不在這裡,因此假設我們已經完成了這些操作。來到了部署的環節。

雖然已經經過了很多的驗證,我們對要發佈的版本的質量已經有了相當程度的信心。但發佈發上線之後,也不可避免的時不時會引入一些缺陷,因此如何讓出現的這些問題的影響面最小,就是所謂的穩健發佈。

首先來關注在雲原生下的開發和調試

DM_20210806161527_002.png

隨著微服務技術和各類開源服務組件普及,如今的軟件系統或多或少的都會包含數個相互獨立的服務實體,之間通過接口調用相互連接。因此在本地進行服務測試的時候,難免涉及到與上下游的其他服務的互動,特別是在進行完整功能驗證時,常常需要在本地將上下游鏈路的所有服務全部啟動起來。然而隨著系統的演進和服務的增多,本地資源很快就無法支撐整體系統啟動了。那麼,是否能夠將測試環境中的公共服務節點和本地服務串聯在一起,行成完整的測試鏈路呢?

DM_20210806161527_003.png

在雲原生的環境下,測試環境被Kubernetes的集群網絡邊界所隔離。從集群外部訪問測試集群中的服務需要經過統一的Ingress網關,且只能訪問配置了網關路由的一小部分部分服務。同時由於開發者的本地主機通常沒有公網IP地址,從測試環境中完全無法連接到本地的服務實例。

為此雲效創造了kt-connect工具來解決本地測試時的網絡聯通問題,它能夠在開發者的本地環境和Kubernetes測試集群之間,建立起一條虛擬的雙向網絡通路。

kt-connect是一款簡單易用的命令行工具。對於從本地連接測試環境的情況,它提供了一個connect命令,利用在集群中部署一個作為網絡代理的Pod節點,使得從本地網絡能夠直接訪問集群中的任意Service域名、IP地址和任意Pod的IP地址。而對於其從集群訪問本地的情況,kt-connect提供了exchange命令,通過另一個反向的代理節點實現將集群中流入指定服務的所有請求導向到本地的指定端口。

DM_20210806161527_004.png

對於個人開發者的使用場景來說,以上兩個命令就能夠完全滿足日常工作了。然而對於團隊開發的場景下,則會帶來新的問題。當一個開發者使用了exchange命令,將特定服務實例的流量全部導向本地,在同一個集群中工作的所有其他開發者都會隨之受到影響。為了避免這樣的相互干擾,kt-connect又創造了第三種命令mesh,它的功能與exchange命令相似,但並不會將網絡中的所有流量全部導入到開發者本地,而是基於特定的網格規則,只將符合要求的測試流量導向開發者的本地環境,從而實現測試環境資源的最大化利用率和多項目的和平共處。

DM_20210806161527_005.png

從本質上來說,kt-connect主要利用了Kubernetes原生命令行的端口轉發和開源SSH工具的四層網絡代理能力實現,對應用本身不產生任何侵入,目前我們已經將它的所有源代碼在Github開源。

接下來來到發佈的環節

DM_20210806161528_006.png

雲原生基礎設施內置了滾動發佈的能力,可以很好的滿足發佈本身的可靠性的需求,保證整個發佈過程是優雅的。但這個模式有一些問題,比如發佈和回滾的時間都比較長,且無法暫定下來進行業務運行狀態的觀察。一個進階的模式是藍綠髮布,新啟動一個副本,然後把所有流量全切到新的版本,這樣發佈和回滾都很快了,但所有流量還是一次性切換的,沒法進行增量驗證。金絲雀發佈可以解決這個問題,可以通過路由控制,逐步將流量導入到新版本上。但一般是採用流量百分比的方式,所有沒法指定特定人群使用新版本。

DM_20210806161528_007.png

一個更加可控的金絲雀方式,需要給每個用戶設置一個流量標誌,比如使用cookie。也就是說通過一個類似interpcetor的機制,判斷當前用戶是否應該是一個灰度用戶,如果是的話,就給他設置一個cookie,後續來自該用戶的所有流量都會帶上這個cookie。有了這個流量標誌,就可以在流量入口處根據cookie的值判斷該請求應該到新版本還是老版本。

DM_20210806161528_008.png

有了這個路由機制,還是不夠。因為我們實際的應用程序並不是只有一個服務,而是像圖中的由多個服務互相調用而組成。比如當我要發佈服務B的時候,因為服務B並不是直接面向瀏覽器的,所有無法接收到用戶的cookie。這時就需要有一個流量表自動傳遞機制。一般的做法是在請求的入口處把灰度標記存在一個ThreadLocal中,然後在應用的出口處,比如一個OkHttpClient的調用處再把這個ThreadLocal中的值放到cookie中繼續往下傳遞。

DM_20210806161528_009.png

我們已經理解了“全鏈路可控金絲雀發佈”的做法,接下來要探討在技術上如何實現。在阿里巴巴,我們使用了一個叫做統一接入的技術,所有的請求(包括入口流量和內部服務之間互相調用的流量)都會經過通過接入,然後有統一接入決定該將這個請求分發到哪裡。

DM_20210806161528_010.png

到了雲原生時代,Service Mesh的概念興起,其實本質上就是一個“分佈式統一接入”。這個統一接入不再是一箇中心化的服務,而是隨著每個服務的每個實例一起部署在一起的進程,這個進程負責接收改實例的入口流量,並轉發給實際的服務;同時也攔截實例的出口流量,並決定下一跳應該是誰。

Istio是Service Mesh的一個被廣泛採用的實現。

DM_20210806161528_011.png

瞭解了這個原理之後,從上圖中,可以看到一次發佈過程是什麼樣子。

DM_20210806161528_012.png

這個發佈過程中涉及到多次Kubernetes資源的更新操作,如果完全採用原生命令+手工配置來操作,不僅複雜還容易出錯。為此雲效對雲原生的各種常見發佈模式都進行了產品化封裝,開發者只需要配置一些簡單的發佈和路由規則,就可以輕鬆地實現安全可控發佈過程。

DM_20210806161528_013.png

點擊此處可以瞭解更多雲效雲原生開發內容,也歡迎大家直接加入kt connect釘釘交流群(釘釘群號:23314962),將你的想法隨時告訴我們。

DM_20210806161528_014.png

Leave a Reply

Your email address will not be published. Required fields are marked *