天天看點

領英遠端開發雲架構建構之路

作者 | Shivani Pai Kasturi,Swati Gambhir

譯者 | Sambodhi

策劃 | 辛曉亮

設想在你的筆記型電腦上進行開發,利用雲計算的算力!在 LinkedIn,我們已經将大部分産品的初始設定和建構時間從 10~30 分鐘減少到 10 秒,并且為使用者帶來了全新的遠端開發體驗。在這篇文章裡,我們将介紹我們實作這一點的曆程。

身為 LinkedI Developer Productivity and Happiness team(開發者效率與幸福團隊)的一員,我們常常會從開發者那兒聽說,開發進度太慢,以及環境設定上的問題會對他們的工作效率造成多大的影響。LinkedIn 擁有一個包含各種技術的、龐大的生态系統,它包括 Java、Python、C/C++、Go、JavaScript、iOS 和 Android,可以滿足不同的需求。擁有一個龐大的生态系統是有其優勢的,但是每個技術的設定都會有差異,并且,新的開發者常常要花費很多時間來設定自己的開發環境。

新冠肺炎大流行期間,在筆記型電腦的 CPU 處理能力、記憶體和磁盤容量受限的情況下,我們都在進行遠端工作,這就更具有挑戰性了。與桌上型電腦或者伺服器級别的計算機相比,筆記型電腦的 CPU 核心、存儲和磁盤容量都要少得多,而且會被熱節流所限制。另外,其他在背景運作的軟體和不完善的網絡也會對系統的性能造成更大的影響,進而導緻建構速度緩慢。考慮到 LinkedIn 的持續內建(Continuous integrationCI)管道每天要處理的建構規模,CI 建構失敗以及本地和 CI 建構之間的不一緻也是支援工程師面臨的一個重要問題。

LinkedIn 的遠端開發活動就是為了解決上述問題,它的目标是為所有的開發者提供可遠端通路、可靠、一緻、可預測、快速建構、易于設定的遠端開發環境,無論他們的本地裝置和網絡連接配接如何,都能滿足他們的項目需求。我們将這種遠端開發環境稱作 RDev(Remote development environments),這是一種為特定産品設定的容器,它包含了開發需要的所有工具和軟體包。RDev 執行個體是在我們的私有雲中強大硬體上建立的,它在網絡上運作時所需的服務時延非常小,比如克隆和下載下傳依賴關系(見圖 1 所示)。

領英遠端開發雲架構建構之路

圖 1:在多次疊代中,以秒為機關,對下載下傳單個依賴關系的時間進行了測量。

我們将 RDev 與開發者最喜歡的 IDE 內建,利用了遠端 SSH 功能,提供無縫的開發體驗,讓開發者有一種在本地開發的感覺。LinkedIn 的一個大型 Play 應用程式的平均建構時間如下圖 2 所示。很明顯,在 RDev 中,建構時間要短得多。

領英遠端開發雲架構建構之路

圖 2:對于不同的作業系統 / 核心,我們的應用程式的建構所花費的平均時間。

在這篇博文中,我們将會介紹我們是怎樣使用現有的基礎設施和産品生命周期來完成這個基于容器的遠端建構和開發環境。我們也将與大家分享一些詳細的内容,包括我們怎樣利用 RDev 來縮短初始設定時間,以及在整個開發和 CI 生命周期中保持一緻。

1

大标題利用預建構的 RDev 對開發者的需求進行預測

我們維護了一個預建構的 RDev 環境池,基于以前 RDev 的使用模式,可以根據需求來為開發者配置設定 RDev。預建構的 RDev 包含了啟動容器、簽出産品、設定環境、建構産品以及使應用程式運作,這樣開發者就無需考慮啟動應用程式的問題,就可以立即開始工作。這可以為開發者節約很多時間,如下圖 3 所示。

領英遠端開發雲架構建構之路

圖 3:應用程式的克隆和建構時間的本地與預建構的 RDev 進行比較。

建構過程會因産品類型的不同而不同,因為一些産品具有特定的持續建構過程,通過 inotify 觀察檔案系統并保持建構的進行(例如,Ember 建構的 JavaScript 産品)。即使是普通的産品,建構過程都會傳回一個退出代碼,也需要記錄建構的輸出。這可以通過在一個 tmux 會話中運作建構來實作,在得到配置設定的 RDev 之後,開發者可以通路這個會話。

2

延伸 RDev 的優勢到持續內建管道

開發(在 RDev 中)、建構和部署(在 CI 中)的能力,都可以通過同一個容器實作一緻性和可重複性的額外好處。

為了獲得這些好處,我們更新了 CI 管道中的建構步驟,并委托它在容器内運作現有的 CI 任務。這個 CI 容器是通過 LinkedIn 的映像基礎設施生成和維護的映像建立的(在下一節中解釋),它可以被用來進行遠端開發,也可以用來建構 CI 工作流。這種方法很像 GitHub 的 “running-on”和“container” 指令的工作方式。

3

它是如何工作的?

讓我們來了解一下,我們是怎樣利用一系列巧妙的技巧,把建構時間降低了兩個數量級。

圖 4 顯示了遠端開發生态系統的主要組成部分。

領英遠端開發雲架構建構之路

遠端開發架構

4

基本映像基礎設施

基本映像基礎設施将建構容器映像與我們的 CI 管道整合在一起,并幫助開發者輕松地為内部的 LinkedIn 容器映像系統資料庫建立和釋出自定義映像。我們有一套針對某些技術的模闆映像,比如 Python、Java 和 JavaScript,這些都是開發者可以直接使用或者進行擴充的。

對于“映像”産品的每一次 CI 建構,都會建立一個依賴關系圖,其中包含了該映像的所有 RPM 資訊和父級基本映像資訊。這個依賴關系圖支援一個圖像依賴關系更新服務,可以将所有 RDev 映像保持最新。它可以從内部 RPM 中接受所有可用的更改,并利用它們來重建映像。任何包含這些 RPM 的映像以及任何相關的映像都會被直接更新。這些映像在 RDev 配置和 CI 中都用來建立開發容器和 CI 建構容器,進而支援一緻的開發和建構環境。

5

RDev 配置

我們遵循 VS Code 的容器配置格式。基本的容器配置,如映像名稱、環境變量和要從容器内轉發的端口,都在産品庫的 root 目錄中的 devcontainer/devcontainer.json 檔案中以聲明方式進行了描述。

6

RDev CLI

RDev CLI 是一個 Python CLI,它被分發到所有開發者的機器上,具有建立、連接配接(通過 CLI 或 IDE)和管理這些遠端開發環境所需的指令。

7

RDev 伺服器

RDev 伺服器是一個 Rest.li Python 服務,充當 CLI 和 Kubernetes Operator 之間的代理。它負責将請求轉發給 Kubernetes Operator,查詢其結果,并與我們存儲開發者偏好和中繼資料(如 dotfiles)的資料庫進行互動。

8

RDev Operator

我們通過利用 Kubernetes Operator 模式和定義 LinkedIn 特定的自定義資源定義(Custom Resource Definitions,CRD),對 Kubernetes API 進行了擴充。

我們定義了兩個 CRD:Rdev 和 RdevPool。Rdev CRD 表示一個單執行個體有狀态應用程式,它的規範有足夠的資訊可以從頭開始重新建立自身。RdevPool CRD 包裝了 Cloneset CRD,用于維護預建構的 RDev 池。RDev Operator 利用 Operator SDK Kubebuilder 架構,作為這些 CRD 的控制器,将其目前狀态與所需狀态進行協調。

領英遠端開發雲架構建構之路

Pod 架構

如圖 5 所示,RDev 與一個服務相關聯,該服務是向 Kubernetes 叢集外部公開端口所必需的。節點端口用于公開伺服器。

持久卷聲明(Persistent Volume Claim,PVC)是保留持久卷(Persistent Volume,PV)的必要條件,以便存儲非易失性資料;在這種情況下,這些資料是 RDev 的主目錄。當下面描述的 Pod 需要移動到另一個節點或被意外删除時,這一點就至關重要。

每個 RDev 都由一個 Kubernetes Pod 備份,該 Pod 由三個不可變的容器組成:RDev-init-workspace、RDev-sshd 和 RDev-sidecar。它還有兩個主要的卷挂載,Home 和 Rdev Info,以及其他與證書和安全有關的必要卷。

容器:

rdev-init-workspace:這是一個 init 容器,用于準備開發者的工作區和偏好。

rdev-sshd:為 RDev 提供登入服務的容器。這個容器是由産品的 devcontainer.json 檔案指定的映像建立的,包含了容器中開發所需的所有工具,并運作 sshd。

rdev-sidecar:負責檢查和安裝 dotfiles 的容器,同時也運作 Startup Probe(啟動探針,在下一段描述)。這個探針用于确定 RDev Pod 是否完全建構并準備配置設定給開發者。

卷挂載:

Home volume:顧名思義,Home volume 是開發人的主卷,它将簽出産品,安裝開發者的 dotfiles,設定環境變量,以及為開發者配置的使用者配置檔案。

Rdev info volume:包含使用 Pod 的标簽和注釋填充的主機和端口詳細資訊,利用向下的 API。

正如前面提到的,RdevPool 是一個 Cloneset,它根據配置的副本數量維護一個 RDev 池。一旦 RDev Pod 被建立,PostStart 容器鈎子會觸發 rdev-sshd 容器中的建構指令。在 rdev-sidecar 容器中運作的啟動探針不斷探測,以确認建構是否已成功完成。它通過尋找記錄建構輸出的檔案,或通過使用 curl 擷取配置檔案中提供的 URL 來确定産品是否已建構。啟動探針成功後,RDev Pod 被标記為“準備就緒”,以便配置設定給開發者。

當開發者請求一個 RDev 時,RDev 控制器将尋找一個完全建構的未配置設定的 Pod,取得 Pod 的所有權,并将其從 RdevPool 控制器中移除。RdevPool 控制器将注意到它的一個 Pod 丢失,然後建立一個新的 Pod 以維持 RdevPool 規範中提供的副本數量。

9

展望未來

由于遠端工作已經滲透到了我們的日常生活中,我們認為,不管在哪裡,遠端開發對于 LinkedIn 開發者的一流開發體驗來說都是一個巨大的動力。

我們對于未來的遠端開發所提供的支援非常激動,比如:

通過為每個失敗的執行提供相應的 RDev,重新生成失敗的 CI 建構并簡化調試體驗。

通過将 RDev 和每一個 GitHub 的 RDev 相關聯,這樣可以讓審閱者對更改有一個直覺的了解,這樣可以提高審閱的體驗。

作者介紹:

Shivani Pai Kasturi,LinkedIn 進階軟體工程師。

Swati Gambhir,LinkedIn 主管軟體工程師。

https://engineering.linkedin.com/blog/2021/building-in-the-cloud-with-remote-development

繼續閱讀