Istio 架构的演进,为什么会有 istiod ?
Service Mesh 化繁為簡:基于 Istiod 回歸單體設計
作為 Service Mesh 領域最具權威的控制面,Istio 從 2017 年發布第一個版本后,就有著一個堪稱“非常優雅”的架構設計。但在推出近 3 年后,其開發團隊卻“意外”推翻之前的架構,重新用上“復古的”單體應用設計。這里面究竟遇到什么不可逾越的鴻溝? 筆者從幾個簡單問題(Why、What、When)出發,為大家揭開這次算是 Istio 誕生以來最大一次“自我革命”的來龍去脈。
背景
“Premature optimizationComplexity is the root of all evil or: How I Learned to Stop Worrying and Love the Monolith”
這是 istiod 長達 21 頁設計文檔的開篇引用語,原文出自 Donald Knuth 1974 年在 ACM Journal 上發表的文章《Structured Programming with go to Statements》,意思是在沒有量化的性能測試檢測出真正存在的性能問題前,各種在代碼層面的“炫技式”優化,可能不僅提升不了性能,反而會導致更多 bug。
而 Istiod 的設計提出者把 “Premature optimization” 換成了 “Complexity”,并且補充一句,“How I Learned to Stop Worrying and Love the Monolith”,簡單翻譯過來就是 —— “復雜性是萬惡之源,停止焦慮,愛上單體”。顯然,今天我們要討論的不是軟件優化相關的事情,而是一個關于 Istio 架構調整的問題。
lstio 作為 Service Mesh(服務網格)領域最具權威的控制面,基本上提到服務網格,所有人都會不自覺地想到它,如網易杭州研究院的輕舟微服務平臺,也是基于 lstio 提供服務網格的支持。
從 2017 年發布第一個版本以來,lstio 就有著一個堪稱非常優雅的架構設計。服務網格整個系統分為數據面和控制面,前者通過同樣是開源的智能代理組件 Envoy 負責進行流量處理。而之所以稱之為智能,是因為 Envoy 相對比其它代理比如 Nginx 有著更豐富的治理能力和靈活的配置方式,并且支持各種插件可用于擴展流量治理能力;而控制面在網格系統里則根據功能職能的不同,被劃分成以下 5 個核心組件:
Pilot
控制面的核心組件,負責對接 Envoy 數據面,也可以解析上層抽象出來的 lstio 配置,轉換成數據面可以識別的 xDS 協議配置并分發到各個 Envoy;
Galley
為更好的解耦職責,它在 lstio 1.1 后由僅負責配置驗證升級成了控制面的配置管理中心,可以對接不同注冊中心,用于為服務網格提供配置輸入能力;
Injector
在 K8s 體系里負責數據面的初始化相關工作,其中 lstio 的核心特性之一 Sidecar 自動注入正是依賴該組件;
Mixer
是 ilstio 里負責提供策略控制和遙測收集的組件,內部包含兩個子組件 —— Telemetry 和 Policy,其中 Telemetry 前者負責監控相關的采集信息的數據聚合以用于對接各種監控后端,而 Policy 負責在服務相互調用過程中對請求進行策略檢查,例如鑒權;
Citadel
負責服務網格里安全相關功能,為服務和用戶提供認證和鑒權、管理憑據和 RBAC 等相關能力;
服務網格控制面各個組件被定義得清楚了然,設計之初就已經考慮到各種組件職責解耦、擴展性、安全性等,架構上看起來也非常清晰優雅。
那么,在這個架構設計中,究竟存在著什么樣的難解之題,迫使 istio 開發團隊在 istio 推出將近 3 年之時,決定推翻這個架構設計,重新用起“復古的”單體應用設計?
下面我從幾個簡單問題(WHY、WHAT、WHEN)出發,試圖為讀者分析這次可以算得上是 istio 從誕生以來最大的一次“自我革命”的來龍去脈,不足之處,歡迎指正。
??
Why — 為什么要回歸單體 ?
如果有人問 lstio 在回歸單體架構設計后,誰最應該開香檳慶祝的話,我可能會不假思索的說是服務網格的運維人員,如果還要再加一類人,那必須算上 lstio 的開發人員。
長期以來,服務網格的運維人員飽受折磨,而這種難言之苦,估計也只有 lstio 的開發同學才能感同深受,試想一下如下場景:
正常非服務網格的環境下,當用戶部署的一個應用出現調用異常時,只需要簡單排查下這個應用自身以及被調用服務端即可,排除網絡等基礎組件異常的話,問題基本上跑不出這兩個應用,原因自然也很容易被定位出來;
現在當用戶的應用接入服務網格后,眾所周知,在服務網格里的調用模型應該是如下圖所示的:
此時,如果業務出現調用異常,由于接入服務網格,問題處理人員要確認 lstio 系統是否正常工作,還記得之前介紹過的控制面組件嗎,首先需要檢查 pilot 是否正常工作,配置是否能下發到 sidecar,然后可能還要檢查 galley 組件是否正常同步到服務實例信息,也有可能是 sidecar 注入問題,還需要檢查 injector 組件是否正常工作…… 這還只是控制面的排查,涉及到數據面還可能需要排查 Envoy 日志等,不過這不是這次關注的點,暫且先不展開介紹。
我猜你可能已經想到我要表達什么,lstio 控制面的各個組件異常都可能會導致數據面在發起請求調用時出現問題,而控制面組件越多,意味著在排查問題的時候要檢查的故障點越多,當然過多的組件設計導致部署難度會增加這點也是毋庸置疑。
說得也許有點危言聳聽。不過,對于將要或者正在使用服務網格的用戶來說,大可不必太擔心,這種由于服務網格本身異常導致數據面無法正常請求的情況一般只出現在服務網格的開發過程中,真正用于生產環境的肯定是經過充分測試的服務網格組件,對于業務用戶而言可以當成是一個穩定的基礎組件來用。
現在,Service Mesh 的優點已經逐漸被大家認可,比如開發運維解耦、集中式管理、開發語言無關等等,但這里有一個問題其實是被大家所忽視的,那就是 lstio 自身的控制面組件的運維難題,分析下來可能有這么三個方面:
第一是管理職責劃分問題
lstio 控制面組件拆分設計的初衷是為了功能職責分離,以便不同的運維 / 開發人員可以單獨管理,但現狀是,大多數的 lstio 應用場景里,運維這件事往往是由一個人或者同一個團隊來管理,這與當初的設計初衷是背道相馳的,存在著過度設計的可能;
第二是導致的部署復雜
拆分后的不同組件,在整個可運維性方面卻是線性增長,比如剛才的排查問題場景,每個組件都有獨立的部署文件,里面封裝著各自特有的啟動參數,雖然這部分可以直接封裝成 K8s 的單一 yaml 文件,但是一旦出問題需要排查原因或者是社區版本的 lstio 功能不滿足需要進行二次開發時,這么多復雜的配置和參數你就必須得關心了。對于開發或者運維來說,這無疑帶來了巨大挑戰。
而且,lstio 在設計之初非常理想化的提出控制面的各個組件都可以獨立部署,在實際應用場景里卻并非如此。
不管是出于簡化運維或是節省資源的目的想要精簡部署的話,你可能不得不做出“一些艱難選擇”,任何一個組件的割舍都意味著你將失去很多核心能力……放棄 galley 意味著無法進行 API 校驗,隨意下發的錯誤配置可能會導致 envoy 拒絕配置而使得相關的配置也同時失效;放棄 mixer 意味著你將無法完成類似于流控、權限檢查、監控采集等;放棄 injector 意味你無法使用自動注入功能……
第三是不必要的獨立伸縮性和安全性考慮
lstio 拆分設計之后,按預先設想各個組件都擁有獨立的伸縮能力,但值得思考的是,lstio 的各個拆分組件,真的需要各自不同的安全設計考慮以及獨立的伸縮能力設計嗎?
引用來自 Istiod 設計文檔里的一段話:“目前看來,對于多數組件來說并非如此。而控制平面的成本由單一功能(xDS)決定。相對而言,其它所有組件的消耗微不足道,因此分離并無必要。”同樣,在關于分離的安全性設計方面,文檔是這么描述的:“在目前,Mutating Webhook、Envoy Bootstrap 以及 Pilot,這幾個組件的安全級別和 Citadel 是基本持平的,對他們的濫用所引發的損失幾乎是相同的。”
非常顯然,分離設計并不會在安全性和擴展性方面帶來實質性的提升,相反這種設計會給用戶帶來額外疑惑 ——“我究竟要給各個組件設置多少個副本或者資源才合理呢?“
看完上面的幾點分析,你可能已經對 lstio 控制面的拆分架構設計有了新的看法,順應了一句老話,“永遠沒有完美的架構,只有最合適的架構”。這個看似如此優雅的架構設計,卻在用戶落地過程中,對運維人員或者開發人員帶來了意料之外的困難……
其實我們可以跳出這個架構設計來重新思考一個有趣的問題:
服務網格本身的設計目標就是號稱下一代微服務架構,用于解決微服務之間的運維管理問題,而在服務網格的設計過程中,竟然又引入了一套新的微服務架構?
這豈不是“用一套微服務架構設計的系統來解決另一套微服務系統的服務治理問題?”那誰來負責解決 istio 系統本身的微服務架構問題呢?
微服務架構帶來的運維成本是不可避免的,所以,這里問題的本質是“一套系統的運維職責由誰來負責?” lstio 作為一個開源項目,運維的職責無疑會落在各個想要使用網格的團隊身上,對于非 istio 開發團隊而言,這個使用門檻是比較高的,無疑存在著巨大的學習和使用成本,很多人因此望而卻步。
What — 什么是 Istiod ?
幸運的是,lstio 社區“非常及時”地發現這個問題,也許是因為 Github 社區里幾乎每天都有各種花樣、無窮無盡的部署相關 issue,也許是他們為了解決運維部署難題在嘗試各種手段(比如 lstio operator、Istioctl 等工具在一定程度上是為解決部分運維部署易用性問題的)卻未取得突破性的改善后,終于有一天,有個勇敢的人站出來說了句:“復雜性是萬惡之源,停止焦慮,愛上單體” 吧!!!
這就是文章開頭的這句合體“宣言”,召喚出了 Istiod …
在這這份公開的設計文檔里,作者一開始便非常明確地提出 istiod 的設計目標:
降低安裝復雜度。單一的二進制文件在安裝部署時將會更加簡單;
降低配置復雜度。之前的很大一部分配置文件是用于編排控制面組件,而單體化設計后這部分配置可以被移除,而且新版本的 Istiod 在配置上可能更精簡,只需保留一個 mesh.yaml 文件,并且能提供最佳實踐配置;
增加控制面可運維性。通過單體設計后的控制面在類似于金絲雀發布的多控制面場景里顯得更加簡單;不同的工作負載可以通過 namespace 或者 pod 上的標簽設置(也可以是組合匹配)來選擇對接不同的控制平面;
提高問題診斷能力。單個控制面組件意味著出了問題后無需在不同的組件間切換來切換去,排查各種問題,顯然這有助于提升問題排查效率;
提高效率和響應速度。再也不用在各個組件間通過遠程調用來傳遞數據,而且原本不同組件間需要共享的數據,現在也可以安全被共享,而且也會一定程度上加快控制面的啟動速度;
消除不必要的耦合。通過把 Envoy 的啟動配置生成移到控制面可以避免 pilot agent 的訪問權限問題。(這個設計目標存在爭議,有人提出 Envoy 的啟動配置跟 pilot 或者 galley 沒有直接關系應該單獨出文檔介紹,也有人認為作者的意圖是指說將 injector 組件也合并入 Istiod 組件內)。
6 個設計目標,基本上都是在針對 Istio 的運維問題,而且也不難發現,這種單體式的設計理念,的確能降低整體的運維復雜度以及排查問題的難度。
那么在一體化的設計后,Istiod 又應該如何找準自己的定位,明確自己的工作職責呢?當然,Istio 的開發團隊并不是說完全推翻之前的設計,其實只是將原有的多進程設計模式優化成單進程的形態,之前各個組件被設計成了 Istiod 的內部子模塊而已,因此 Istiod 就需要承擔所有的職責:
監聽配置,接手了原來 galley 的工作,負責監聽來自多種支持配置源的數據,比如 K8S api server,本地文件或者基于 MCP 協議的配置,包括原來 galley 需要處理的 API 校驗和配置的轉發也需要設計在內;
監聽 Endpoint,監聽來自本地或者遠程集群的 endpoint 信息,在將來還計劃允許 endpoint 復制在各個集群內,包括非 K8s 的注冊中心例如 consul;
CA 根的生成,生成私鑰和證書,目前 Citadel 的職責之一;
控制面身份標識,目前在內部控制面之間是通過 CA 根來生成一個 SPIFFE ID 用于識別身份,也同時用于 injector 組件的證書生成,可以參考另外一篇 proposal(simplified control-plane identity proposal)
證書生成,主要是為各個控制面之間的通訊生成私鑰和證書來保證安全通訊;
自動注入,在 K8S 里需要為 Mutating Admission Controller 提供接口支持,從而可以在 pod 創建階段修改資源文件來實現 sidecar 的自動注入;
CNI/CRI 注入,通過 CNI/CRI 作為 hook 來實現自動注入的另一種方式,目前還沒使用;
Envoy 啟動配置生成,上文目標中提到的,Envoy 的啟動配置將由 istiod 來提供;
本地的 SDS Server,提供密鑰發現服務的本地服務端;
中央 SDS Server,同上,是一個中央化的密鑰發現服務端,一般用以對接第三方的密鑰系統;
xDS 服務提供,之前 pilot 的核心能力,為所有的 Envoy 提供 xDS 下發的服務端;
如果將改造前的 Istio 控制前按功能簡化整理成表格就是:
而新版本后的組件則非常精簡,對應如下:
經過對比,可以很直觀地看到,Istiod 是將原有的的其它組件統統塞入了 pilot,而架構調整后的新 pilot,即 Istiod 肩負了相比 pilot 更多的職責,單個二進制文件在部署方式上變得更加簡單。
如果按照官方的部署一套 demo 的話,除了 ingress 和 egress 網關以及另外幾個監控相關的組件,剩下的就只有一個 istiod 組件。
通過這種多進程到單進程的架構調整,Istio 的開發團隊可以算是以最小的成本實現了整體運維方面的巨大收益:
新的基于 Istiod 的架構變成下圖:
相比之前的架構圖,是不是感覺格外清爽,有種豁然開朗的感覺?
When — 什么時候發布 ?
介紹完了 Istiod 的誕生初衷和設計理念,作為服務網格的開發人員或者正在觀望的團隊,想必都會對這個 Istiod 的新特性滿懷期待,單體設計后的 Istio 管控平面簡化部署流程,減少因為部署或者配置問題引發的不必要時間浪費,的的確確是在“save your life”。
網易輕舟微服務團隊一直在關注 Istio 社區的最新動態,早在社區代碼倉庫的 release 1.5 開發分支中就發現了 Istiod 的身影,而近日正式發布的 1.5 版本,眾望所歸的 Istiod 自然包含在內,這意味著從這個版本開始,Istio 控制面部署形態將正式進入一個全新的時代,堪稱是一次突破性的設計革新。
One More Thing,Istio 的官方博客在正式發布 1.5 的前幾天,發布了一篇博文 ——《Istio in 2020 - Following the Trade Winds》,介紹了 Istio 社區 2020 年的一些“風向標”,其中就有提到一些非常令人興奮的特性:
1.將會更整潔、更平滑、更快速
Istio 從誕生以來的第一天就提供了可擴展性方面的能力,這里面 mixer 組件扮演了非常重要的角色,它允許用戶通過自定義適配器(adapter)的方式來開發擴展;在之前版本里,mixer 一直是一個進程外組件設計,新設計中針對一些常用場景比如鑒權,將會被 Istio 的認證模塊取代,這樣子設計好處是允許用戶直接在 proxy 內部進行鑒權認證,其它的比如通用的指標監控也同時被移入了 proxy 內部。
這意味著之前一直遭人詬病的 Mixer 性能問題將會有非常大的改善,根據官方的 benchmark,通過新的 telemetry 模型設計可以取得業界領先的性能數據,相比之前減少約 50% 的延遲以及不少 CPU 消耗;
2.全新的擴展支持方式
這種全新的擴展支持架構相比之前提供了更好兼容性,也正是 Istio 社區的開發者主導開發了 Envoy 里的 WASM 特性支持,允許用戶以超過 20 種開發語言來實現各種擴展插件。
令人感到興奮的是,這些插件是可以在 envoy 處理流量過程中被動態的加載、重載的,這種動態的靈活性自然不言而喻,istio 社區也在和 envoy 社區共建來發現、分發更多的擴展,目的是為了讓這些插件更加容易被用戶安裝或是在容器環境里運行;包括部分之前編寫 mixer adapter 的開發者也正在“搬運”這些插件到 WASM 上,社區也在努力提供相關的文檔以幫助更多的開發者上手 WASM;
Istio 1.5 確實可以稱得上是一次突破性的版本發布,各種架構上或者是設計上的優化,都可以看的出來是在做減法,包括更精簡的架構,更簡單的擴展支持方式。
社區里提出的各種缺陷,都正在逐一被優化,比如可運維性、易用性、擴展性等方面,還有一直被人詬病的性能,也正在通過架構性的調整得以優化和改良,甚至這篇文章里還提到,之前把一大批非容器用戶擋在門外的平臺限制問題,在不久的將來也將成為一個歷史,按照博客介紹的,社區正在努力 “Making it easier to run Istio without needing Kubernetes”!
結語
盡管之前一直被人抱怨存在各種問題,但 Istio 社區的開發腳步沒有停歇,我們看到了一次又一次的版本發布從未間斷,伴隨著各種大大小小的功能更新和優化。就網易杭研而言,輕舟微服務將 Istio 引入生產環境也是極為審慎,事實上也曾遇到了運維和開發的困惑,而 istiod 架構設計的回歸讓我們徹底松了一口氣,擁抱 Istio 實現服務網格的思路更加堅定。
就像當年的 kubernates 也曾受過質疑,現在卻沒人質疑它在容器編排領域的地位,相信在不久的未來,Istio 這艘小船在微服務的海洋里將會行駛得更加敏捷、輕快、平穩,而 Service Mesh,也終將不再是一個新鮮詞。
作者介紹
翁揚慧,網易杭州研究院云計算技術部資深研發工程師,有多年微服務開發經驗,目前主要負責網易輕舟服務框架和服務網格的核心設計以及業務落地工作,熱愛編程,熱衷于開源社區的技術交流和分享。
總結
以上是生活随笔為你收集整理的Istio 架构的演进,为什么会有 istiod ?的全部內容,希望文章能夠幫你解決所遇到的問題。
- 上一篇: [再寄小读者之数学篇](2014-07-
- 下一篇: (干货分享)PCB板和集成电路解析