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

{"type":"doc","content":[{"type":"blockquote","content":[{"type":"paragraph","attrs":{"indent":0,"number":0,"align":null,"origin":null},"content":[{"type":"text","text":"設想在你的筆記本計算機上進行開發,利用雲計算的算力!在 LinkedIn,我們已經將大部分產品的初始設置和構建時間從 10~30 分鐘減少到 10 秒,並且爲用戶帶來了全新的遠程開發體驗。在這篇文章裏,我們將介紹我們實現這一點的歷程。"}]}]},{"type":"paragraph","attrs":{"indent":0,"number":0,"align":null,"origin":null}},{"type":"paragraph","attrs":{"indent":0,"number":0,"align":null,"origin":null},"content":[{"type":"text","text":"身爲 LinkedI Developer Productivity and Happiness team(開發者效率與幸福團隊)的一員,我們常常會從開發者那兒聽說,開發進度太慢,以及環境設置上的問題會對他們的工作效率造成多大的影響。LinkedIn 擁有一個包含各種技術的、龐大的生態系統,它包括 Java、Python、C\/C++、Go、JavaScript、iOS 和 Android,可以滿足不同的需求。擁有一個龐大的生態系統是有其優勢的,但是每個技術的設置都會有差異,並且,新的開發者常常要花費很多時間來設置自己的開發環境。"}]},{"type":"paragraph","attrs":{"indent":0,"number":0,"align":null,"origin":null}},{"type":"paragraph","attrs":{"indent":0,"number":0,"align":null,"origin":null},"content":[{"type":"text","text":"新冠肺炎大流行期間,在筆記本計算機的 CPU 處理能力、內存和磁盤容量受限的情況下,我們都在進行遠程工作,這就更具有挑戰性了。與臺式機或者服務器級別的計算機相比,筆記本計算機的 CPU 內核、存儲和磁盤容量都要少得多,而且會被熱節流所限制。另外,其他在後臺運行的軟件和不完善的網絡也會對系統的性能造成更大的影響,從而導致構建速度緩慢。考慮到 LinkedIn 的持續集成(Continuous integrationCI)管道每天要處理的構建規模,CI 構建失敗以及本地和 CI 構建之間的不一致也是支持工程師面臨的一個重要問題。"}]},{"type":"paragraph","attrs":{"indent":0,"number":0,"align":null,"origin":null}},{"type":"paragraph","attrs":{"indent":0,"number":0,"align":null,"origin":null},"content":[{"type":"text","text":"LinkedIn 的遠程開發活動就是爲了解決上述問題,它的目標是爲所有的開發者提供可遠程訪問、可靠、一致、可預測、快速構建、易於設置的遠程開發環境,無論他們的本地設備和網絡連接如何,都能滿足他們的項目需求。我們將這種遠程開發環境稱作 RDev(Remote development environments),這是一種爲特定產品設置的容器,它包含了開發需要的所有工具和軟件包。RDev 實例是在我們的私有云中強大硬件上創建的,它在網絡上運行時所需的服務時延非常小,比如克隆和下載依賴關係(見圖 1 所示)。"}]},{"type":"paragraph","attrs":{"indent":0,"number":0,"align":null,"origin":null}},{"type":"image","attrs":{"src":"https:\/\/static001.geekbang.org\/infoq\/5b\/5b2c0b818eb3bddff396a1604ccfa0f1.jpeg","alt":null,"title":null,"style":[{"key":"width","value":"75%"},{"key":"bordertype","value":"none"}],"href":null,"fromPaste":true,"pastePass":true}},{"type":"paragraph","attrs":{"indent":0,"number":0,"align":"center","origin":null},"content":[{"type":"text","text":"圖 1:在多次迭代中,以秒爲單位,對下載單個依賴關係的時間進行了測量。"}]},{"type":"paragraph","attrs":{"indent":0,"number":0,"align":null,"origin":null}},{"type":"paragraph","attrs":{"indent":0,"number":0,"align":null,"origin":null},"content":[{"type":"text","marks":[{"type":"color","attrs":{"color":"#494949","name":"user"}}],"text":"我們將 RDev 與開發者最喜歡的 IDE 集成,利用了"},{"type":"link","attrs":{"href":"https:\/\/code.visualstudio.com\/docs\/remote\/ssh","title":null,"type":null},"content":[{"type":"text","text":"遠程 SSH 功能"}],"marks":[{"type":"color","attrs":{"color":"#494949","name":"user"}}]},{"type":"text","marks":[{"type":"color","attrs":{"color":"#494949","name":"user"}}],"text":",提供無縫的開發體驗,讓開發者有一種在本地開發的感覺。LinkedIn 的一個大型 "},{"type":"link","attrs":{"href":"https:\/\/www.playframework.com\/","title":null,"type":null},"content":[{"type":"text","text":"Play"}],"marks":[{"type":"color","attrs":{"color":"#494949","name":"user"}}]},{"type":"text","marks":[{"type":"color","attrs":{"color":"#494949","name":"user"}}],"text":" 應用程序的平均構建時間如下圖 2 所示。很明顯,在 RDev 中,構建時間要短得多。"}]},{"type":"paragraph","attrs":{"indent":0,"number":0,"align":null,"origin":null}},{"type":"image","attrs":{"src":"https:\/\/static001.geekbang.org\/infoq\/47\/47d60f1e438b136d3250cbf9df68827c.jpeg","alt":null,"title":null,"style":[{"key":"width","value":"75%"},{"key":"bordertype","value":"none"}],"href":null,"fromPaste":true,"pastePass":true}},{"type":"paragraph","attrs":{"indent":0,"number":0,"align":"center","origin":null},"content":[{"type":"text","marks":[{"type":"color","attrs":{"color":"#494949","name":"user"}}],"text":"圖 2:對於不同的操作系統\/內核,我們的應用程序的構建所花費的平均時間。"}]},{"type":"paragraph","attrs":{"indent":0,"number":0,"align":null,"origin":null}},{"type":"paragraph","attrs":{"indent":0,"number":0,"align":null,"origin":null},"content":[{"type":"text","text":"在這篇博文中,我們將會介紹我們是怎樣使用現有的基礎設施和產品生命週期來完成這個基於容器的遠程構建和開發環境。我們也將與大家分享一些詳細的內容,包括我們怎樣利用 RDev 來縮短初始設置時間,以及在整個開發和 CI 生命週期中保持一致。"}]},{"type":"heading","attrs":{"align":null,"level":4},"content":[{"type":"text","text":"利用預構建的 RDev 對開發者的需求進行預測"}]},{"type":"paragraph","attrs":{"indent":0,"number":0,"align":null,"origin":null},"content":[{"type":"text","marks":[{"type":"color","attrs":{"color":"#494949","name":"user"}}],"text":" "}]},{"type":"paragraph","attrs":{"indent":0,"number":0,"align":null,"origin":null},"content":[{"type":"text","marks":[{"type":"color","attrs":{"color":"#494949","name":"user"}}],"text":"我們維護了一個預構建的 RDev 環境池,基於以前 RDev 的使用模式,可以根據需求來爲開發者分配 RDev。預構建的 RDev 包含了啓動容器、簽出產品、設置環境、構建產品以及使應用程序運行,這樣開發者就無需考慮啓動應用程序的問題,就可以立即開始工作。這可以爲開發者節約很多時間,如下圖 3 所示。"}]},{"type":"paragraph","attrs":{"indent":0,"number":0,"align":null,"origin":null}},{"type":"image","attrs":{"src":"https:\/\/static001.geekbang.org\/infoq\/05\/053ad60943ed8a064a6331b807f175c7.jpeg","alt":null,"title":null,"style":[{"key":"width","value":"75%"},{"key":"bordertype","value":"none"}],"href":null,"fromPaste":true,"pastePass":true}},{"type":"paragraph","attrs":{"indent":0,"number":0,"align":"center","origin":null},"content":[{"type":"text","text":"圖 3:應用程序的克隆和構建時間的本地與預構建的 RDev 進行比較。"}]},{"type":"paragraph","attrs":{"indent":0,"number":0,"align":null,"origin":null}},{"type":"paragraph","attrs":{"indent":0,"number":0,"align":null,"origin":null},"content":[{"type":"text","text":"構建過程會因產品類型的不同而不同,因爲一些產品具有特定的持續構建過程,通過 inotify 觀察文件系統並保持構建的進行(例如,Ember 構建的 JavaScript 產品)。即使是普通的產品,構建過程都會返回一個退出代碼,也需要記錄構建的輸出。這可以通過在一個 tmux 會話中運行構建來實現,在得到分配的 RDev 之後,開發者可以訪問這個會話。"}]},{"type":"heading","attrs":{"align":null,"level":4},"content":[{"type":"text","text":"延伸 RDev 的優勢到持續集成管道"}]},{"type":"paragraph","attrs":{"indent":0,"number":0,"align":null,"origin":null}},{"type":"paragraph","attrs":{"indent":0,"number":0,"align":null,"origin":null},"content":[{"type":"text","marks":[{"type":"color","attrs":{"color":"#494949","name":"user"}}],"text":"開發(在 RDev 中)、構建和部署(在 CI 中)的能力,都可以通過同一個容器實現一致性和可重複性的額外好處。"}]},{"type":"paragraph","attrs":{"indent":0,"number":0,"align":null,"origin":null},"content":[{"type":"text","marks":[{"type":"color","attrs":{"color":"#494949","name":"user"}}],"text":" "}]},{"type":"paragraph","attrs":{"indent":0,"number":0,"align":null,"origin":null},"content":[{"type":"text","marks":[{"type":"color","attrs":{"color":"#494949","name":"user"}}],"text":"爲了獲得這些好處,我們更新了 CI 管道中的構建步驟,並委託它在容器內運行現有的 CI 任務。這個 CI 容器是通過 LinkedIn 的映像基礎設施生成和維護的映像創建的(在下一節中解釋),它可以被用來進行遠程開發,也可以用來構建 CI 工作流。這種方法很像 "},{"type":"link","attrs":{"href":"https:\/\/docs.github.com\/en\/actions\/creating-actions\/creating-a-docker-container-action","title":null,"type":null},"content":[{"type":"text","text":"GitHub 的 “running-on”和“container”"}],"marks":[{"type":"color","attrs":{"color":"#494949","name":"user"}}]},{"type":"text","marks":[{"type":"color","attrs":{"color":"#494949","name":"user"}}],"text":" 指令的工作方式。"}]},{"type":"heading","attrs":{"align":null,"level":4},"content":[{"type":"text","text":"它是如何工作的?"}]},{"type":"paragraph","attrs":{"indent":0,"number":0,"align":null,"origin":null}},{"type":"paragraph","attrs":{"indent":0,"number":0,"align":null,"origin":null},"content":[{"type":"text","text":"讓我們來了解一下,我們是怎樣利用一系列巧妙的技巧,把構建時間降低了兩個數量級。"}]},{"type":"paragraph","attrs":{"indent":0,"number":0,"align":null,"origin":null}},{"type":"paragraph","attrs":{"indent":0,"number":0,"align":null,"origin":null},"content":[{"type":"text","text":"圖 4 顯示了遠程開發生態系統的主要組成部分。"}]},{"type":"paragraph","attrs":{"indent":0,"number":0,"align":null,"origin":null}},{"type":"image","attrs":{"src":"https:\/\/static001.geekbang.org\/infoq\/75\/75bc48bf46031d9457f458451ee5dc3b.jpeg","alt":null,"title":null,"style":[{"key":"width","value":"75%"},{"key":"bordertype","value":"none"}],"href":null,"fromPaste":true,"pastePass":true}},{"type":"paragraph","attrs":{"indent":0,"number":0,"align":"center","origin":null},"content":[{"type":"text","text":"遠程開發架構"}]},{"type":"heading","attrs":{"align":null,"level":4},"content":[{"type":"text","text":"基本映像基礎設施"}]},{"type":"paragraph","attrs":{"indent":0,"number":0,"align":null,"origin":null}},{"type":"paragraph","attrs":{"indent":0,"number":0,"align":null,"origin":null},"content":[{"type":"text","text":"基本映像基礎設施將構建容器映像與我們的 CI 管道整合在一起,並幫助開發者輕鬆地爲內部的 LinkedIn 容器映像註冊表創建和發佈自定義映像。我們有一套針對某些技術的模板映像,比如 Python、Java 和 JavaScript,這些都是開發者可以直接使用或者進行擴展的。"}]},{"type":"paragraph","attrs":{"indent":0,"number":0,"align":null,"origin":null}},{"type":"paragraph","attrs":{"indent":0,"number":0,"align":null,"origin":null},"content":[{"type":"text","text":"對於“映像”產品的每一次 CI 構建,都會創建一個依賴關係圖,其中包含了該映像的所有 RPM 信息和父級基本映像信息。這個依賴關係圖支持一個圖像依賴關係更新服務,可以將所有 RDev 映像保持最新。它可以從內部 RPM 中接受所有可用的更改,並利用它們來重建映像。任何包含這些 RPM 的映像以及任何相關的映像都會被直接更新。這些映像在 RDev 配置和 CI 中都用來創建開發容器和 CI 構建容器,從而支持一致的開發和構建環境。"}]},{"type":"heading","attrs":{"align":null,"level":4},"content":[{"type":"text","text":"RDev 配置"}]},{"type":"paragraph","attrs":{"indent":0,"number":0,"align":null,"origin":null},"content":[{"type":"text","marks":[{"type":"color","attrs":{"color":"#494949","name":"user"}}],"text":" "}]},{"type":"paragraph","attrs":{"indent":0,"number":0,"align":null,"origin":null},"content":[{"type":"text","marks":[{"type":"color","attrs":{"color":"#494949","name":"user"}}],"text":"我們遵循 "},{"type":"link","attrs":{"href":"https:\/\/code.visualstudio.com\/docs\/remote\/devcontainerjson-reference","title":null,"type":null},"content":[{"type":"text","text":"VS Code 的容器配置格式"}],"marks":[{"type":"color","attrs":{"color":"#494949","name":"user"}}]},{"type":"text","marks":[{"type":"color","attrs":{"color":"#494949","name":"user"}}],"text":"。基本的容器配置,如映像名稱、環境變量和要從容器內轉發的端口,都在產品庫的 root 目錄中的 devcontainer\/devcontainer.json 文件中以聲明方式進行了描述。"}]},{"type":"heading","attrs":{"align":null,"level":4},"content":[{"type":"text","text":"RDev CLI"}]},{"type":"paragraph","attrs":{"indent":0,"number":0,"align":null,"origin":null}},{"type":"paragraph","attrs":{"indent":0,"number":0,"align":null,"origin":null},"content":[{"type":"text","text":"RDev CLI 是一個 Python CLI,它被分發到所有開發者的機器上,具有創建、連接(通過 CLI 或 IDE)和管理這些遠程開發環境所需的命令。"}]},{"type":"heading","attrs":{"align":null,"level":4},"content":[{"type":"text","text":"RDev 服務器"}]},{"type":"paragraph","attrs":{"indent":0,"number":0,"align":null,"origin":null}},{"type":"paragraph","attrs":{"indent":0,"number":0,"align":null,"origin":null},"content":[{"type":"text","marks":[{"type":"color","attrs":{"color":"#494949","name":"user"}}],"text":"RDev 服務器是一個 "},{"type":"link","attrs":{"href":"https:\/\/linkedin.github.io\/rest.li\/","title":null,"type":null},"content":[{"type":"text","text":"Rest.li"}],"marks":[{"type":"color","attrs":{"color":"#494949","name":"user"}}]},{"type":"text","marks":[{"type":"color","attrs":{"color":"#494949","name":"user"}}],"text":" Python 服務,充當 CLI 和 Kubernetes Operator 之間的代理。它負責將請求轉發給 Kubernetes Operator,查詢其結果,並與我們存儲開發者偏好和元數據(如 dotfiles)的數據庫進行交互。"}]},{"type":"heading","attrs":{"align":null,"level":4},"content":[{"type":"text","text":"RDev Operator"}]},{"type":"paragraph","attrs":{"indent":0,"number":0,"align":null,"origin":null}},{"type":"paragraph","attrs":{"indent":0,"number":0,"align":null,"origin":null},"content":[{"type":"text","marks":[{"type":"color","attrs":{"color":"#494949","name":"user"}}],"text":"我們通過利用 "},{"type":"link","attrs":{"href":"https:\/\/kubernetes.io\/docs\/concepts\/extend-kubernetes\/operator\/","title":null,"type":null},"content":[{"type":"text","text":"Kubernetes Operator 模式"}],"marks":[{"type":"color","attrs":{"color":"#494949","name":"user"}}]},{"type":"text","marks":[{"type":"color","attrs":{"color":"#494949","name":"user"}}],"text":"和定義 LinkedIn 特定的"},{"type":"link","attrs":{"href":"https:\/\/kubernetes.io\/docs\/concepts\/extend-kubernetes\/api-extension\/custom-resources\/","title":null,"type":null},"content":[{"type":"text","text":"自定義資源定義"}],"marks":[{"type":"color","attrs":{"color":"#494949","name":"user"}}]},{"type":"text","marks":[{"type":"color","attrs":{"color":"#494949","name":"user"}}],"text":"(Custom Resource Definitions,CRD),對 Kubernetes API 進行了擴充。"}]},{"type":"paragraph","attrs":{"indent":0,"number":0,"align":null,"origin":null},"content":[{"type":"text","marks":[{"type":"color","attrs":{"color":"#494949","name":"user"}}],"text":" "}]},{"type":"paragraph","attrs":{"indent":0,"number":0,"align":null,"origin":null},"content":[{"type":"text","marks":[{"type":"color","attrs":{"color":"#494949","name":"user"}}],"text":"我們定義了兩個 CRD:Rdev 和 RdevPool。Rdev CRD 表示一個單實例"},{"type":"link","attrs":{"href":"https:\/\/kubernetes.io\/docs\/tasks\/run-application\/run-single-instance-stateful-application\/","title":null,"type":null},"content":[{"type":"text","text":"有狀態應用程序"}],"marks":[{"type":"color","attrs":{"color":"#494949","name":"user"}}]},{"type":"text","marks":[{"type":"color","attrs":{"color":"#494949","name":"user"}}],"text":",它的規範有足夠的信息可以從頭開始重新創建自身。RdevPool CRD 包裝了 "},{"type":"link","attrs":{"href":"https:\/\/openkruise.io\/docs\/next\/user-manuals\/cloneset\/","title":null,"type":null},"content":[{"type":"text","text":"Cloneset"}],"marks":[{"type":"color","attrs":{"color":"#494949","name":"user"}}]},{"type":"text","marks":[{"type":"color","attrs":{"color":"#494949","name":"user"}}],"text":" CRD,用於維護預構建的 RDev 池。RDev Operator 利用 Operator SDK "},{"type":"link","attrs":{"href":"https:\/\/kubernetes.io\/blog\/2018\/08\/10\/introducing-kubebuilder-an-sdk-for-building-kubernetes-apis-using-crds\/","title":null,"type":null},"content":[{"type":"text","text":"Kubebuilder 框架"}],"marks":[{"type":"color","attrs":{"color":"#494949","name":"user"}}]},{"type":"text","marks":[{"type":"color","attrs":{"color":"#494949","name":"user"}}],"text":",作爲這些 CRD 的控制器,將其當前狀態與所需狀態進行協調。"}]},{"type":"paragraph","attrs":{"indent":0,"number":0,"align":null,"origin":null}},{"type":"image","attrs":{"src":"https:\/\/static001.geekbang.org\/infoq\/5e\/5ed500d6fc9865825b40243e7d3ad7d7.jpeg","alt":null,"title":null,"style":[{"key":"width","value":"75%"},{"key":"bordertype","value":"none"}],"href":null,"fromPaste":true,"pastePass":true}},{"type":"paragraph","attrs":{"indent":0,"number":0,"align":"center","origin":null},"content":[{"type":"text","text":"Pod 架構"}]},{"type":"paragraph","attrs":{"indent":0,"number":0,"align":null,"origin":null}},{"type":"paragraph","attrs":{"indent":0,"number":0,"align":null,"origin":null},"content":[{"type":"text","marks":[{"type":"color","attrs":{"color":"#494949","name":"user"}}],"text":"如圖 5 所示,RDev 與一個"},{"type":"link","attrs":{"href":"https:\/\/kubernetes.io\/docs\/concepts\/services-networking\/service\/","title":null,"type":null},"content":[{"type":"text","text":"服務"}],"marks":[{"type":"color","attrs":{"color":"#494949","name":"user"}}]},{"type":"text","marks":[{"type":"color","attrs":{"color":"#494949","name":"user"}}],"text":"相關聯,該服務是向 Kubernetes 集羣外部公開端口所必需的。節點端口用於公開服務器。"}]},{"type":"paragraph","attrs":{"indent":0,"number":0,"align":null,"origin":null},"content":[{"type":"text","marks":[{"type":"color","attrs":{"color":"#494949","name":"user"}}],"text":" "}]},{"type":"paragraph","attrs":{"indent":0,"number":0,"align":null,"origin":null},"content":[{"type":"link","attrs":{"href":"https:\/\/kubernetes.io\/docs\/concepts\/storage\/persistent-volumes\/#claims-as-volumes","title":null,"type":null},"content":[{"type":"text","text":"持久卷聲明"}],"marks":[{"type":"color","attrs":{"color":"#494949","name":"user"}}]},{"type":"text","marks":[{"type":"color","attrs":{"color":"#494949","name":"user"}}],"text":"(Persistent Volume Claim,PVC)是保留"},{"type":"link","attrs":{"href":"https:\/\/kubernetes.io\/docs\/concepts\/storage\/persistent-volumes\/","title":null,"type":null},"content":[{"type":"text","text":"持久卷"}],"marks":[{"type":"color","attrs":{"color":"#494949","name":"user"}}]},{"type":"text","marks":[{"type":"color","attrs":{"color":"#494949","name":"user"}}],"text":"(Persistent Volume,PV)的必要條件,以便存儲非易失性數據;在這種情況下,這些數據是 RDev 的主目錄。當下面描述的 Pod 需要移動到另一個節點或被意外刪除時,這一點就至關重要。"}]},{"type":"paragraph","attrs":{"indent":0,"number":0,"align":null,"origin":null},"content":[{"type":"text","marks":[{"type":"color","attrs":{"color":"#494949","name":"user"}}],"text":" "}]},{"type":"paragraph","attrs":{"indent":0,"number":0,"align":null,"origin":null},"content":[{"type":"text","marks":[{"type":"color","attrs":{"color":"#494949","name":"user"}}],"text":"每個 RDev 都由一個 "},{"type":"link","attrs":{"href":"https:\/\/kubernetes.io\/docs\/concepts\/workloads\/pods\/","title":null,"type":null},"content":[{"type":"text","text":"Kubernetes Pod"}],"marks":[{"type":"color","attrs":{"color":"#494949","name":"user"}}]},{"type":"text","marks":[{"type":"color","attrs":{"color":"#494949","name":"user"}}],"text":" 備份,該 Pod 由三個不可變的容器組成:RDev-init-workspace、RDev-sshd 和 RDev-sidecar。它還有兩個主要的卷掛載,Home 和 Rdev Info,以及其他與證書和安全有關的必要卷。"}]},{"type":"heading","attrs":{"align":null,"level":5},"content":[{"type":"text","text":"容器:"}]},{"type":"paragraph","attrs":{"indent":0,"number":0,"align":null,"origin":null}},{"type":"bulletedlist","content":[{"type":"listitem","attrs":{"listStyle":null},"content":[{"type":"paragraph","attrs":{"indent":0,"number":0,"align":null,"origin":null},"content":[{"type":"text","marks":[{"type":"color","attrs":{"color":"#494949","name":"user"}},{"type":"strong"}],"text":"rdev-init-workspace"},{"type":"text","marks":[{"type":"color","attrs":{"color":"#494949","name":"user"}}],"text":":這是一個 init 容器,用於準備開發者的工作區和偏好。"}]}]},{"type":"listitem","attrs":{"listStyle":null},"content":[{"type":"paragraph","attrs":{"indent":0,"number":0,"align":null,"origin":null},"content":[{"type":"text","marks":[{"type":"color","attrs":{"color":"#494949","name":"user"}},{"type":"strong"}],"text":"rdev-sshd"},{"type":"text","marks":[{"type":"color","attrs":{"color":"#494949","name":"user"}}],"text":":爲 RDev 提供登錄服務的容器。這個容器是由產品的 devcontainer.json 文件指定的映像創建的,包含了容器中開發所需的所有工具,並運行 sshd。"}]}]},{"type":"listitem","attrs":{"listStyle":null},"content":[{"type":"paragraph","attrs":{"indent":0,"number":0,"align":null,"origin":null},"content":[{"type":"text","marks":[{"type":"color","attrs":{"color":"#494949","name":"user"}},{"type":"strong"}],"text":"rdev-sidecar"},{"type":"text","marks":[{"type":"color","attrs":{"color":"#494949","name":"user"}}],"text":":負責檢查和安裝 dotfiles 的容器,同時也運行 Startup Probe(啓動探針,在下一段描述)。這個探針用於確定 RDev Pod 是否完全構建並準備分配給開發者。"}]}]}]},{"type":"heading","attrs":{"align":null,"level":5},"content":[{"type":"text","text":"卷掛載:"}]},{"type":"paragraph","attrs":{"indent":0,"number":0,"align":null,"origin":null}},{"type":"bulletedlist","content":[{"type":"listitem","attrs":{"listStyle":null},"content":[{"type":"paragraph","attrs":{"indent":0,"number":0,"align":null,"origin":null},"content":[{"type":"text","marks":[{"type":"color","attrs":{"color":"#494949","name":"user"}},{"type":"strong"}],"text":"Home volume"},{"type":"text","marks":[{"type":"color","attrs":{"color":"#494949","name":"user"}}],"text":":顧名思義,Home volume 是開發人的主卷,它將簽出產品,安裝開發者的 dotfiles,設置環境變量,以及爲開發者配置的用戶配置文件。"}]}]},{"type":"listitem","attrs":{"listStyle":null},"content":[{"type":"paragraph","attrs":{"indent":0,"number":0,"align":null,"origin":null},"content":[{"type":"text","marks":[{"type":"color","attrs":{"color":"#494949","name":"user"}},{"type":"strong"}],"text":"Rdev info volume"},{"type":"text","marks":[{"type":"color","attrs":{"color":"#494949","name":"user"}}],"text":":包含使用 Pod 的標籤和註釋填充的主機和端口詳細信息,利用"},{"type":"link","attrs":{"href":"https:\/\/kubernetes.io\/docs\/tasks\/inject-data-application\/downward-api-volume-expose-pod-information\/#the-downward-api","title":null,"type":null},"content":[{"type":"text","text":"向下的 API"}],"marks":[{"type":"color","attrs":{"color":"#494949","name":"user"}}]},{"type":"text","marks":[{"type":"color","attrs":{"color":"#494949","name":"user"}}],"text":"。"}]}]}]},{"type":"paragraph","attrs":{"indent":0,"number":0,"align":null,"origin":null}},{"type":"paragraph","attrs":{"indent":0,"number":0,"align":null,"origin":null},"content":[{"type":"text","marks":[{"type":"color","attrs":{"color":"#494949","name":"user"}}],"text":"正如前面提到的,RdevPool 是一個 Cloneset,它根據配置的副本數量維護一個 RDev 池。一旦 RDev Pod 被創建,"},{"type":"link","attrs":{"href":"https:\/\/kubernetes.io\/docs\/concepts\/containers\/container-lifecycle-hooks\/#container-hooks","title":null,"type":null},"content":[{"type":"text","text":"PostStart 容器鉤子"}],"marks":[{"type":"color","attrs":{"color":"#494949","name":"user"}}]},{"type":"text","marks":[{"type":"color","attrs":{"color":"#494949","name":"user"}}],"text":"會觸發 rdev-sshd 容器中的構建命令。在 rdev-sidecar 容器中運行的"},{"type":"link","attrs":{"href":"https:\/\/kubernetes.io\/docs\/tasks\/configure-pod-container\/configure-liveness-readiness-startup-probes\/#define-startup-probes","title":null,"type":null},"content":[{"type":"text","text":"啓動探針"}],"marks":[{"type":"color","attrs":{"color":"#494949","name":"user"}}]},{"type":"text","marks":[{"type":"color","attrs":{"color":"#494949","name":"user"}}],"text":"不斷探測,以確認構建是否已成功完成。它通過尋找記錄構建輸出的文件,或通過使用 curl 獲取配置文件中提供的 URL 來確定產品是否已構建。啓動探針成功後,RDev Pod 被標記爲“準備就緒”,以便分配給開發者。"}]},{"type":"paragraph","attrs":{"indent":0,"number":0,"align":null,"origin":null},"content":[{"type":"text","marks":[{"type":"color","attrs":{"color":"#494949","name":"user"}}],"text":" "}]},{"type":"paragraph","attrs":{"indent":0,"number":0,"align":null,"origin":null},"content":[{"type":"text","marks":[{"type":"color","attrs":{"color":"#494949","name":"user"}}],"text":"當開發者請求一個 RDev 時,RDev 控制器將尋找一個完全構建的未分配的 Pod,取得 Pod 的所有權,並將其從 RdevPool 控制器中移除。RdevPool 控制器將注意到它的一個 Pod 丟失,然後創建一個新的 Pod 以維持 RdevPool 規範中提供的副本數量。"}]},{"type":"heading","attrs":{"align":null,"level":4},"content":[{"type":"text","text":"展望未來"}]},{"type":"paragraph","attrs":{"indent":0,"number":0,"align":null,"origin":null}},{"type":"paragraph","attrs":{"indent":0,"number":0,"align":null,"origin":null},"content":[{"type":"text","marks":[{"type":"color","attrs":{"color":"#494949","name":"user"}}],"text":"由於遠程工作已經滲透到了我們的日常生活中,我們認爲,不管在哪裏,遠程開發對於 LinkedIn 開發者的一流開發體驗來說都是一個巨大的動力。"}]},{"type":"paragraph","attrs":{"indent":0,"number":0,"align":null,"origin":null},"content":[{"type":"text","marks":[{"type":"color","attrs":{"color":"#494949","name":"user"}}],"text":" "}]},{"type":"paragraph","attrs":{"indent":0,"number":0,"align":null,"origin":null},"content":[{"type":"text","marks":[{"type":"color","attrs":{"color":"#494949","name":"user"}}],"text":"我們對於未來的遠程開發所提供的支持非常激動,比如:"}]},{"type":"paragraph","attrs":{"indent":0,"number":0,"align":null,"origin":null},"content":[{"type":"text","marks":[{"type":"color","attrs":{"color":"#494949","name":"user"}}],"text":" "}]},{"type":"bulletedlist","content":[{"type":"listitem","attrs":{"listStyle":null},"content":[{"type":"paragraph","attrs":{"indent":0,"number":0,"align":null,"origin":null},"content":[{"type":"text","marks":[{"type":"color","attrs":{"color":"#494949","name":"user"}}],"text":"通過爲每個失敗的執行提供相應的 RDev,重新生成失敗的 CI 構建並簡化調試體驗。"}]}]},{"type":"listitem","attrs":{"listStyle":null},"content":[{"type":"paragraph","attrs":{"indent":0,"number":0,"align":null,"origin":null},"content":[{"type":"text","marks":[{"type":"color","attrs":{"color":"#494949","name":"user"}}],"text":"通過將 RDev 和每一個 GitHub 的 RDev 相關聯,這樣可以讓審閱者對更改有一個直觀的理解,這樣可以提高審閱的體驗。"}]}]}]},{"type":"paragraph","attrs":{"indent":0,"number":0,"align":null,"origin":null}},{"type":"paragraph","attrs":{"indent":0,"number":0,"align":null,"origin":null},"content":[{"type":"text","marks":[{"type":"color","attrs":{"color":"#494949","name":"user"}},{"type":"strong"}],"text":"作者介紹:"}]},{"type":"paragraph","attrs":{"indent":0,"number":0,"align":null,"origin":null},"content":[{"type":"text","marks":[{"type":"color","attrs":{"color":"#494949","name":"user"}}],"text":" "}]},{"type":"paragraph","attrs":{"indent":0,"number":0,"align":null,"origin":null},"content":[{"type":"text","marks":[{"type":"color","attrs":{"color":"#494949","name":"user"}}],"text":"Shivani Pai Kasturi,LinkedIn 高級軟件工程師。"}]},{"type":"paragraph","attrs":{"indent":0,"number":0,"align":null,"origin":null},"content":[{"type":"text","marks":[{"type":"color","attrs":{"color":"#494949","name":"user"}}],"text":"Swati Gambhir,LinkedIn 主管軟件工程師。"}]},{"type":"paragraph","attrs":{"indent":0,"number":0,"align":null,"origin":null},"content":[{"type":"text","marks":[{"type":"color","attrs":{"color":"#494949","name":"user"}}],"text":" "}]},{"type":"paragraph","attrs":{"indent":0,"number":0,"align":null,"origin":null},"content":[{"type":"text","marks":[{"type":"color","attrs":{"color":"#494949","name":"user"}},{"type":"strong"}],"text":"原文鏈接:"}]},{"type":"paragraph","attrs":{"indent":0,"number":0,"align":null,"origin":null},"content":[{"type":"text","marks":[{"type":"color","attrs":{"color":"#494949","name":"user"}}],"text":" "}]},{"type":"paragraph","attrs":{"indent":0,"number":0,"align":null,"origin":null},"content":[{"type":"text","marks":[{"type":"color","attrs":{"color":"#494949","name":"user"}}],"text":"https:\/\/engineering.linkedin.com\/blog\/2021\/building-in-the-cloud-with-remote-development"}]}]}
發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章