1. 程式人生 > 其它 >Nocalhost:雲原生開發新體驗

Nocalhost:雲原生開發新體驗

本文為 CSDN 博主「祈晴小義」(黃鑫鑫:騰訊雲 CODING DevOps 研發工程師、Nocalhost 專案的核心開發者)的原創文章,並根據作者在 CSDN 雲原生 Meetup 深圳站的演講內容進行了整理,主要分享 Nocalhost 在解決雲原生開發問題上的思路和探索,並展示 Nocalhost 為雲原生開發帶來的全新體驗。

雲原生場景下的開發痛點

當我們的應用架構從傳統應用過渡到雲原生應用的時候,會發現應用架構的複雜性大大提升了,原來的傳統應用元件少,部署簡單,我們往往可以在本地開發完一個傳統應用後,把它丟到伺服器上就能跑起來。而對於雲原生應用來說,應用被拆分成一個一個粒度更小的微服務,各個服務之間有著錯綜複雜的關係,從而讓開發環境的搭建和服務的除錯變得異常困難。

本地部署 VS 叢集部署

當我們要開發雲原生微服務應用時,如何將我們的開發環境搭建起來呢?常見的有兩種方式:本地部署和叢集部署。

本地部署是將一整套微服務應用部署到本地的開發機器上,如下圖所示:

這種方式會帶來以下幾個問題:

1. 影響開發機器的效能。微服務應用往往規模比較大,動輒幾十上百個服務,都泡在自己的開發機上可能會讓電腦變得很卡,影響工作效率。

2. 環境無法共享,資源浪費嚴重。當我們需要在本地部署起整套規模比較大的微服務應用的時候,就需要使用配置較高的開發機器,並且每臺開發機器的開發環境只有一個開發人員能使用,即便該開發人員只需要開發其中一個或某幾個服務,也無法將其它使用不到的服務共享給其它開發人員使用。

3. 對於一些規模很大的微服務應用,本地機器可能還沒有辦法跑起來。

另外一種方式將微服務應用部署到雲上的 K8s 叢集裡,如下圖所示:

這種部署方式可以較好地提高資源利用率,但是它會讓開發和除錯應用時的反饋鏈路被大大拉長。

我們開發傳統應用時的工作流是:在本地編寫好程式碼 -> 把程式碼進行編譯 -> 執行程式檢視結果,如下圖所示:

這個過程往往很快,所以我們可以在做完一次程式碼的小改動以後,就把它執行起來檢視結果。

但是在開發 K8s 叢集上的應用時,工作流變成了:修改程式碼 -> 編譯程式 -> 將程式打包到 Docker 映象 -> 將 Docker 映象推送到映象倉庫 -> 修改叢集中容器的映象版本,等待 K8s 將新版本的映象部署上去 -> 檢視結果,如下圖所示:

這個流程可能需要耗時幾分鐘,當這個迴圈反饋被大大拉長了以後,無疑會讓開發的效率大大降低。

目前主流的雲原生開發方式

手動打包推送映象

這種方式是最原始的方式,工作流大體如下:

編寫完程式碼以後,在本地編譯生成二進位制檔案或者 jar 包之類,然後通過 Dockerfile 構建出 Docker 映象,再將映象推送到 Docker 倉庫,再通過修改工作負載的 yaml 定義中映象版本,部署新版本容器的任務則交給 K8s 去做,只不過部署排程的過程可能有點漫長,需要等待 K8s 將新版本的 Pod 排程執行起來之後,我們才能看到程式碼修改的效果。如果程式碼改動得頻繁,這個流程顯然是非常繁瑣的。

CI/CD 流水線

這種方式和第一種方式的流程大體上是一樣的,只不過是通過 CI/CD 的能力,把手動的操作改成了自動化的流程:

這種方式的工作流是:在本地修改完程式碼,把程式碼推送到程式碼倉庫,從而觸發程式碼倉庫配置好的 CI 流程,把程式碼編譯構建成應用程式(如二進位制或 Jar 包),並打包成映象,之後會觸發所謂的持續交付(Continuous Delivery)機制,將映象推送到製品倉庫裡,最後再觸發持續部署(Continuous Delivery)流程,將新版本的容器排程部署到叢集中。雖然使用 CI/CD 以後,可以減少大部分手工操作環節,但整個流程花費的時間仍然很多,事實上,CI/CD 更適合在釋出應用環節使用,而不是在開發應用環節。開發環節更注重的是能夠快速得到反饋從而驗證自己的想法,當我們的修改需要提交到程式碼倉,在 CI/CD 流水線跑完了以後才能看到效果,會限制我們使用簡單的嘗試,來從幾種方案中找出最優的一種,或者定位 bug 的原因。

流量轉發

流量轉發的思路是:將叢集裡訪問開發中服務的流量轉發到本地。如下圖所示:

當需要開發 D 服務時,將叢集中訪問 D 服務的流量轉發到本地開發機器上的某個埠上,在本地寫完程式碼以後,直接將應用程式在本地跑起來即可。實現這種方式的相關產品有:kt-connecttelepresence

在本地直接執行應用程式固然可以縮短迴圈反饋,提高開發效率,但這種方式也有一個很大的問題:許多執行在 K8s 叢集上的服務會依賴其它 K8s 資源,例如依賴 ServiceAccount、ConfigMap、Secret、PVC 等等,這樣的服務要在本地跑起來並不太容易。

在容器裡進行開發

這種方式的思路是:當我們要對某個服務進入開發時,先讓要開發的服務進入開發模式,然後將程式碼同步到容器中,直接在容器中把開發中的程式碼執行起來:

這種方式同時解決了開發迴圈反饋過慢和服務依賴叢集問題,是目前雲原生開發中較好的實踐,也是 Nocalhost 支援的主要開發方式之一。

Nocalhost 初體驗

第三部分主要是以 Demo 演示的方式來帶大家體驗 Nocalhost 的特性,感興趣的同學可以前往深圳站 Meetup 視訊回放,從 01:26:15 處開始觀看。
https://live.csdn.net/room/csdnnews/yCHrYqnM

Nocalhost 核心機制

Nocalhost 是如何實現在容器中進行應用程式的開發的呢?在一個服務進入開發模式時,Nocalhost 所做的核心工作有以下 4 個步驟。

縮減副本數

開發應用程式時,我們只需要在一個容器裡執行正在開發中的應用程式,如果存在多個副本,我們通過 Service 訪問該服務時,就無法控制流量只訪問到我們正在開發中的應用程式所執行的那個副本,所以 Nocalhost 需要先將工作負載的副本數縮減為 1。

替換開發容器映象

生產環境執行的容器往往會使用很輕量級的映象,映象裡僅包含執行業務程式所必須的元件,而缺少編譯構建業務程式所需的相關工具(如 JDK)。在對某個工作負載進行開發的時候,Nocalhost 會將容器映象替換成包含完整開發工具的開發映象。

增加 SideCar 容器

為了將本地的原始碼改動同步到容器中,我們需要在容器裡執行一個檔案同步伺服器。為了使檔案同步伺服器程序和業務程序解耦,Nocalhost 將檔案同步伺服器執行在一個獨立的 sidecar 容器中,該容器與業務容器掛載相同的同步目錄,因此,同步到 sidecar 容器中的原始碼在業務容器中也可以訪問。

啟動檔案同步客戶端

由於檔案同步伺服器監聽在容器裡的某個埠上,我們在本地無法直接訪問,所以 Nocalhost 會把一個本地隨機埠轉發到容器裡檔案同步伺服器監聽的埠,打通檔案同步伺服器和客戶端的網路,然後再啟動本地的檔案同步客戶端。檔案同步客戶端啟動後會通過剛剛轉發的本地隨機埠和檔案同步伺服器建立通訊,之後便會開始進行檔案的同步。

在以上步驟完成後,Nocalhost 會自動開啟一個進入到遠端容器的終端,通過該終端,我們就可以把實時同步到容器裡到原始碼直接執行起來。

Nocalhost 高階特性

Duplicate 開發模式

Nocalhost 預設的開發模式是將叢集中原本正常執行著的服務給替換成開發容器,如下圖:

這種方式存在以下問題:

1. 開發時會影響環境的使用。當對某個服務進行開發時,該服務在開發過程中可能會由於程式碼修改有問題導致異常甚至奔潰,叢集裡又有其他服務依賴該服務,從而影響到整個環境的使用。

2. 無法支援多人開發同一個服務。

為此,我們可以使用 Duplicate 開發模式,這種模式下,Nocalhost 不會對原有的服務做任何修改,而是複製出和一個原有服務一樣的副本來進行開發,如下圖所示:

這種模式下,多人可以對同一個服務進行開發,每個人都擁有自己的開發副本,叢集原有的環境也不會受到任何影響。

Nocalhost Server

Nocalhost 除了通過 IDE 提供方便開發 K8s 應用的外掛外,還提供了一個適合企業級開發環境管理的 Nocalhost Server,以下是 Nocalhost Server 的管理介面:

Nocalhost Server 可以提供叢集、應用、人員許可權上的管理,關於 Nocalhost Server 的詳細介紹,可以參考官方文件上的介紹。

Mesh 模式

前面我們提到,如果要實現多人開發同一個服務,可以使用 Duplicate 開發模式,但這種方式也有一個侷限性,就是隻能在本地通過 API 介面請求去訪問開發中的副本,沒辦法通過應用的入口地址來訪問。對於需要通過統一的應用入口來訪問開發中服務的場景,我們可以使用 Nocalhost 的 Mesh 模式。

Mesh 模式會為每個人分配一個 MeshSpace,不同的 MeshSpace 通過在流量中帶入不同的 Header 來控制從應用入口進來的流量的訪問鏈路。

使用 Mesh 模式要求開發環境通過 Nocalhost Server 管理,並且應用需要有 Header 透傳和使用 Istio 進行流量轉發的能力,關於 Mesh 模式的使用可以參考官網文件 (文件目前還不是很完善,更詳細的資訊可以直接通過 GitHub 聯絡 Nocalhost 的開發團隊)。

點選閱讀原文,一鍵開啟雲原生開發環境