云原生时代, Kubernetes 多集群架构初探
為什么我們需要多集群?
近年來,多集群架構已經成為“老生常談”。我們喜歡高可用,喜歡異地多可用區,而多集群架構天生就具備了這樣的能力。另一方面我們也希望通過多集群混合云來降低成本,利用到不同集群各自的優勢和特性,以便使用不同集群的最新技術(如 AI、GPU 集群等)。
就是因為這種種原因,多集群幾乎成為了云計算的新潮流,而被談及最多并且落地的多集群場景主要有這三類:
一類用于應對“云突發”。如下圖 1 所示,正常情況下用戶使用自己的 IDC 集群提供服務,當應對突發大流量時,迅速將應用擴容到云上集群共同提供服務,將多集群作為備用資源池。該模式一般針對無狀態的服務,可以快速彈性擴展,主要針對使用 CPU、內存較為密集的服務,如搜索、查詢、計算等類型的服務。
圖 1:多集群“云突發”場景
第二類用于“云容災”。如下圖 2 所示,通常主要服務的集群為一個,另一個集群周期性備份。或者一個集群主要負責讀寫,其他備份集群只讀。在主集群所在的云出現問題時可以快速切換到備份集群。該模式可用于數據量較大的存儲服務。
圖 2:多集群“云容災”場景
第三類則用于“異地多活”。如圖 3 所示,與“云容災”的主要區別是數據是實時同步的,多集群都可以同時讀寫。這種模式通常針對極其重要的數據,如全局統一的用戶賬號信息等。
圖 3:多集群,異地多活場景
但是多集群同時也帶來了巨大的復雜性,一方面如何讓應用可以面向多集群部署分發,另一方面是希望應用真正能做到多集群之間靈活切換,想到傳統應用遷移的難度可能就已經讓我們望而卻步了。面向多集群,我們依然缺乏足夠成熟的應用交付和管理的能力。
多集群的最后一公里
早在 2013 年,不少老牌云計算廠商就已經在聊“為什么要多集群”,并開始倡導多集群是“Next Big Thing”。
然而殘酷的現實卻是,每一個不同的云、每一個數據中心都是一套自己的 API 與設計方式,所謂“多集群”多數情況下只是廠商 A 主動集成不同類型集群的一套接入層。
這種背景下的多集群一直以來都以架構復雜著稱,具體表現就是各個廠商發布會上令人眼花繚亂的多集群 / 混合云解決方案架構圖,如下 圖 4 就是一個傳統的多集群企業級解決方案架構圖,不得不說,我們很難完全理解圖中的所有細節。
圖 4:傳統的多集群企業級解決方案架構圖
這種背景下的多集群技術,其實更像是廠商對一個封閉產品的代名詞。不同廠商的云有不同的 API、不同的能力特性,廠商們在這之上架構的多集群、混合云解決方案,大量的精力都是在適配和整合不同集群平臺上的各類能力。
而對于用戶,最終的結果又會是另一種形式的綁定。這樣的多集群無法形成生態,也許這就是我們遲遲無法面向這種多集群構建統一的應用交付、構建真正多集群能力的原因。
Kubernetes:全世界數據中心的統一 API
不過,伴隨著云原生理念的迅速普及,“步履蹣跚”的多集群理念卻迎來了一個非常關鍵的契機。
從 2015 年 CNCF 成立到現在,短短四年多的時間,其組織下就孵化了數十個項目,吸引了近四百位企業級會員的加入,項目貢獻人數達到六萬三千多人,而每年參與 CNCF 官方活動的人數也早已超過了十萬人, CNCF Lanscape 下符合云原生標準的項目已經達到了上千個。
這種 Kubernetes 以及云原生技術體系迅速崛起的直接結果,就是在所有公有云之上, Kubernetes 服務都已經成為了毋庸置疑的一等公民;而全世界幾乎所有的科技公司和大量的企業終端用戶,也都已經在自己的數據中心里使用 K8s 來進行容器化應用的編排與管理。
不難看到,Kubernetes 正在迅速成為全世界數據中心的統一 API。
圖 5:云原生的曙光
這層統一而標準的 API 之下,多集群和混合云的能力才開始真正體現價值。
Kubernetes 和它所推崇的聲明式容器編排與管理體系,讓軟件交付本身變得越來越標準化和統一化,并且實現了與底層基礎設施的完全解耦;而另一方面,云原生技術體系在所有公有云和大量數據中心里的落地,使得軟件面向一個統一的 API 實現“一次定義,到處部署”成為了可能。
Kubernetes API 在全世界數據中心里的普及,終于讓多集群和混合云理念有了一個堅實的事實基礎。而伴隨著軟件產業對提升效率、降低成本的巨大渴望,云原生加持下的云計算飛輪終于啟動,并將越飛越快。
多集群時代的 “ The Platform for Platform”
大家可能聽說過,Kubernetes 項目的本質其實是 Platform for Platform,也就是一個用來構建“平臺”的“平臺”。
相比于 Mesos 和 Swarm 等容器管理平臺,Kubernetes 項目最大的優勢和關注點,在于它始終專注于如何幫助用戶基于 Kubernetes 的聲明式 API ,快速、便捷的構建健壯的分布式應用,并且按照統一的模型(容器設計模式和控制器機制)來驅動應用的實際狀態向期望狀態逼近和收斂。
而當 The Platform for Platform 的特質和多集群連接在一起, Kubernetes 的用戶實際上直接擁有了面向多集群統一構建平臺級服務的寶貴能力。
比如, kubeCDN 項目就是這樣的一個典型案例,它的核心思想,就是直接基于全世界公有云上的 K8s 集群來自建 CDN。借助云原生技術,巧妙的解決了使用傳統 CDN 廠商服務的很多痛點(包括安全性沒有保障、服務質量依賴外部廠商、CDN 廠商看重利潤忽視部分用戶需求、商業機密可能被泄露洞察等等)。在實現上,kubeCDN 在不同的區域構建 K8s 集群,并通過 Route53 來根據延遲智能路由用戶的請求到最優的集群。而作為搭建 CDN 的基礎,Kubernetes 則幫助用戶整合了基礎設施,其本身統一的 API 又使得用戶可以快速分發內容部署應用。
圖 6:CDN 場景的 K8s 多集群
不難看到,基于 Kubernetes 的多集群給了 kubeCDN 災備和統一多集群資源的能力;而統一標準的 Kubernetes API 層,則把構建一個全球級別 CDN 的代價減少到了幾百行代碼的工作量。基于 K8s 的多集群混合云,正在為不同的產業帶來了新的活力和更多的想象空間。
云的未來,是面向多集群的應用交付
如果說多集群是云計算的未來,那么多集群的未來又是什么呢?
云原生技術的發展路徑是持續輸出“事實標準的軟件”,而這些事實標準中,應用的彈性(resiliency)、易用性(usability)和可移植性(portability)是其所解決的三大本質問題。
-
應用的彈性對于云產品的客戶來說等價于業務可靠性和業務探索與創新的敏捷性,體現的是云計算所創造的客戶價值,應用彈性的另一個關注點在于快速部署、交付、以及在云上的擴縮容能力。這就需要完善的應用交付鏈路以及應用的云原生開發框架支撐;
-
其次,良好易用性才能更好地發揮應用的彈性。在微服務軟件架構成為主流的情形下,易用性需要考慮通過技術手段實現對應用整體做全局性的治理,實現全局最優。這凸顯了 Service Mesh 的服務能力;
-
最后,當應用具備良好的可移植性,實現多集群和混合云的戰略將成為必然趨勢。
就像 K8s 是云時代的操作系統,而在這操作系統之上構建的應用還需要一系列的開發、交付、管理工具。云計算的價值,最終會回歸到應用本身的價值。而如何服務好這些應用,將成為云廠商們新一輪能力的體現。
在這條路徑上,統一的云原生應用標準定義和規范,通用的應用托管和分發中心,基于 Service Mesh 的、跨云的應用治理能力,以及 K8s 原生的、面向多集群的應用交付和管理體系,將會持續不斷的產生巨大的價值。
Kubernetes 項目在“多集群”上的探索
當前 K8s 圍繞多集群也已經開始了許多項目,如 Federation V2,Cluster Registry,Kubemci 等。在這之前更早開始的項目是 Federation v1,但是如今已經逐漸被社區所廢棄。這其中的主要原因,在于 v1 的設計試圖在 K8s 之上又構建一層 Federation API,直接屏蔽掉了已經取得廣泛共識的 K8s API ,這與云原生社區的發展理念是相悖的。
而 RedHat 后來牽頭發起的 Federation V2 項目, 則以插件的形式融入到 K8s API 中(即我們熟悉的 CRD)。它提供了一個可以將任何 K8s API type 轉換成有多集群概念的 federated type 的方法,以及一個對應的控制器以便推送這些 federated 對象 (Object)。而它并不像 V1 一樣關心復雜的推送策略(V1 的 Federation Scheduler),只負責把這些 Object 分發到用戶事先定義的集群去。
需要注意的是,這里被推送到這些集群上的對象,都來自于一個相同的模板,只有一些元數據會有差別。另外,被推送的 type 都需要制作 Fedrated type,這在 type 類型比較有限的時候才比較方便。
這也就意味著 Federation v2 的主要設計目標,其實是向多集群推送 RBAC,policy 等集群配置信息:這些可推送資源類型是固定的,而每個集群的配置策略格式也是基本類似的。
所以說,Federation v2 的定位暫時只是一個多集群配置推送項目。
然而,面向多集群交付應用背后往往是有著復雜的決策邏輯的。比如:集群 A 當前負載低,就應該多推一些應用上去。再比如,用戶可能有成百上千個來自二方、三方的軟件( 都是 CRD + Operator)要面向多集群交付,在目前 Fed v2 的體系下,用戶要去維護這些 CRD 的 Fedreted type,代價是非常大的。
面向應用的 Kubernetes 多集群架構初探
那么一個以應用為中心、圍繞應用交付的多集群多集群管理該具備何種能力呢?這里面有三個技術點值得深入思考:
用戶 Kubernetes 集群可能是沒有公網 IP、甚至在私有網絡當中的:而無論用戶的 Kubernetes 集群部署在任何位置,多集群服務都應該能夠將它們接入進來,并且暴露完整的、沒有經過任何修改的 Kubernetes API。這是用戶進行應用交付的重要基礎。
以 GitOps 驅動的多集群配置管理中心:用戶接入集群的配置管理,需要通過一個中心化的配置管理中心來推送和同步。但更重要的是,這些配置信息應該通過 GitOps、 以對用戶完全公開、透明、可審計的方式進行托管,通過 Git 協議作為多集群控制中心與用戶協作的標準界面。
“托管式”而非“接管式”的統一鑒權機制:無論用戶是在使用的是公有云上的 Kubernetes 服務,還是自建 IDC 集群,這些集群接入使用的鑒權證書是由統一機構頒發的。云提供商,不應該存儲用戶集群的任何秘鑰 (Credentials) 信息,并且應該提供統一的授權權限管理能力,允許用戶對接入的任何集群做子用戶授權。
多集群架構的基石:Kubernetes API 隧道
要將 Kubernetes 集群以原生 API 的托管方式接入到多集群管理體系當中,這背后主要的技術難點是“集群隧道”。
集群隧道會在用戶的 Kubernetes 集群里安裝一個 agent,使得用戶的集群無需公網 IP,就可以被用戶像使用公有云上的 Kubernetes 服務一樣在公網訪問,隨時隨地愉快的使用、管理、監控自己的集群,擁有統一的鑒權、權限、日志、審計、控制臺等等一系列的功能。
集群隧道的架構也應該是簡潔的。如下圖 7 所示,其核心分為兩層,下層是被托管的集群,在其中會有一個 Agent,Agent 一方面在被托管的集群中運行,可以輕易的在內網訪問被托管的集群,另一方面它通過公網與公有云接入層中的節點 (Stub) 構建一個隧道 (tunnel)。在上層,用戶通過公有云統一的方式接入審計、鑒權、權限相關功能,通過訪問 Stub,再通過隧道由 Agent 向用戶自己的 Kubernetes 集群轉發命令。
圖 7:多集群 K8s 隧道架構
通過這樣的層層轉發,用戶可以使用公有云統一的鑒權方式透明的使用被托管的集群,并且公有云本身不應該觸碰和存儲用戶的鑒權信息。要實現這樣的集群隧道,多集群架構必須要能克服兩大難題:
- 在用戶訪問時,API 接入公有云統一的證書管理,包括鑒權、權限、子用戶授權等等。
- 在 API 轉發到用戶 Agent 時,再將請求變為 K8s 集群原有的授權訪問,被托管集群的鑒權永遠只存在集群本身。
這兩大難題,是現有的開源 Tunnel 庫、以及原生的四層轉發與七層轉發都不能完全解決的,這里一一列舉如下:
- ngrok:一個曾經很有名,但是目前已經被廢棄的項目,github 的 Readme 中明確的寫著,“不要在生產環境使用”;
- go-http-tunnel:很簡潔的項目,但是一方面源碼的協議是 AGPL-3.0,意味著代碼無法商用,另一方面,在 kubectl 執行 exec 等命令時需要 hijack 連接,基于 http2 的 tunnel 在協議原理上就天然不滿足這個功能;
- chisel: 同樣很簡潔的項目,底層基于 TCP 構建連接,然后巧妙的利用了 ssh 實現 tcp 連接的 session 管理和多路復用。但是依然無法解決在 tunnel 的一端 (Stub) 對接解析公有云的證書,驗證后又在另一端 (Agent) 使用 K8s 的 token 發起新的請求;
- rancher/remotedialer:rancher 的這個項目功能與 chisel 相似,基于 websocket,agent 直接把集群的 token 傳遞到了 Server 端,需要存儲用戶自己的集群鑒權信息,與我們的目標不符;
- frp: 一個大而全的項目,有很多如 UI、Dashboard 等功能,但是依然沒有直接滿足我們在 stub 端證書解析、agent 端 token 訪問需求;
- apiserver-network-proxy:與 chisel 的功能很像,基于 grpc,剛開始沒多久的項目,同樣不能直接滿足需求。
阿里云 Kubernetes 服務多集群架構
目前,在阿里云 Kubernetes 服務中( ACK )提供的多集群能力,遵循的正是上述“以應用為中心”的多集群架構。這個功能,以“接入已有集群”作為入口,如下圖所示:
圖 8:在阿里云容器服務 Kubernetes 版上使用“接入已有集群”能力
集群隧道
圖 9:阿里云的集群隧道架構
這個多集群架構如圖 9 所示,跟上一節所述是基本一致的。具體來說,阿里云的 ACK 服務(容器服務 Kubernetes 版)會在用戶集群上安裝一個 Agent,安裝完畢后 Agent 只需要能夠公網訪問,用戶就可以在 ACK 上使用自己的集群,通過 ACK 統一的鑒權方式體驗原生的 K8s API。
長連接與長響應
在 Kubernetes 控制操作中,存在諸如 kubectl exec , kubectl port-forward 基于非 HTTP 協議的長連接以及 kubectl logs -f 這種反饋持續時間較長的長響應。它們對于通信鏈路的獨占使得 HTTP/2 的多路復用無法運作,Go 語言官方庫中的 HTTP/1.1 本身也不支持協議升級,故而無法采用原生七層 HTTP 轉發。
為了解決這兩大難題,ACK 的隧道技術上采用了一系列策略進行應對:
- 使用原生七層轉發,對轉發數據進行證書識別,將 Kubernetes 權限注入,解決鑒權問題;
- 對于協議升級請求,劫持七層鏈路,使用四層鏈路,進而使用原生四層無感知轉發,解決長連接問題;
- 只在發送請求方向上復用鏈路,每次反饋建立新鏈路,防止阻塞,解決長響應問題。
隧道高可用
除此之外,在 ACK 的隧道設計中,由于中間的鏈路(Agent 與 Stub)對于用戶而言是透明的,在客戶端以及目標集群的 API Server 正常運轉的情況下,不能因為中間鏈路的故障導致無法連接,因此 ACK 隧道還提供了 Agent 與 Stub 的高可用能力,提高容錯力,降低故障恢復時間。
Agent 高可用
允許多個 Agent 同時連接 Stub,多個 Agent 的存在不僅可以高可用,還可以作為負載均衡來使用。
- 多 Agent 負載均衡 :一方面,每個 Agent 會定時向 Stub 發送當前的可用狀態,另一方面,Stub 進行數據包轉發時,采用隨機輪詢的方式,選擇一個可用的 Agent 轉發;
- 多集群防干擾、集群切換:在多 Agent 的存在下,可能會涉及到 Agent 來自不同的 Kubernetes 集群造成干擾,所以同樣需要加入 Agent 的集群唯一 ID。當原先集群的所有連接都斷開時,會進行集群切換。
Stub 高可用
在 Stub 端,由于客戶端只會向同一個 IP 發送,多個 Stub 的存在需要使用 Kubernetes 的 Service 進行協調,例如可以使用 LoadBalancer。但是,如果使用 LoadBalancer 對請求進行分流,一個重要問題是,由于長連接的存在,從客戶端發出的信息可能是上下文相關的而非互相獨立的。TCP 四層分流會破壞上下文,所以 Stub 在同一時刻應當只能有一個在起作用。
在只有一個 Stub 運行的情況下,依然要保證其高可用,這里 ACK 隧道采用了 Kubernetes 的 Lease API 等高可用能力。因此 Stub 端的高可用雖然不能像 Agent 端一樣起到分流分壓作用,但是它提供滾動升級等能力。
結語
云的邊界正在被技術和開源迅速的抹平。越來越多的軟件和框架從設計上就不再會跟某云產生直接綁定。畢竟,你沒辦法撫平用戶對商業競爭擔憂和焦慮,也不可能阻止越來越多的用戶把 Kubernetes 部署在全世界的所有云上和數據中心里。
在未來云的世界里,K8s 會成為連通“云”與“應用”的高速公路,以標準、高效的方式將“應用”快速交付到世界上任何一個位置。而這里的交付目的地,既可以是最終用戶,也可以是 PaaS/Serverless ,甚至會催生出更加多樣化的應用托管生態。“云”的價值,一定會回歸到應用本身。
多集群與混合云的時代已經來臨,以應用為中心的多集群多集群架構,才是云計算生態發展的必然趨勢,你的云可以運行在任何地方,而我們幫你管理。讓我們一起迎接面向應用的云原生多集群時代,一起擁抱云原生,一起關注應用本身的價值!
作者介紹:
孫健波,阿里云容器平臺技術專家,Kubernetes 項目社區成員,負責 ACK 容器服務相關開發工作。
殷達,清華大學與卡內基梅隆大學計算機專業在讀研究生,于阿里云容器平臺部實習,主要參與 ACK 容器服務多云技術及云原生應用開發。
總結
以上是生活随笔為你收集整理的云原生时代, Kubernetes 多集群架构初探的全部內容,希望文章能夠幫你解決所遇到的問題。
- 上一篇: 云原生生态周报 Vol. 13 | Fo
- 下一篇: Kubernetes 弹性伸缩全场景解析