雲原生時代, 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 多集羣架構初探

那麼一個以應用爲中心、圍繞應用交付的多集羣多集羣管理該具備何種能力呢?這裏面有三個技術點值得深入思考:

  1. 用戶 Kubernetes 集羣可能是沒有公網IP、甚至在私有網絡當中的:而無論用戶的 Kubernetes 集羣部署在任何位置,多集羣服務都應該能夠將它們接入進來,並且暴露完整的、沒有經過任何修改的 Kubernetes API。這是用戶進行應用交付的重要基礎。
  2. 以GitOps 驅動的多集羣配置管理中心:用戶接入集羣的配置管理,需要通過一箇中心化的配置管理中心來推送和同步。但更重要的是,這些配置信息應該通過 GitOps、 以對用戶完全公開、透明、可審計的方式進行託管,通過 Git 協議作爲多集羣控制中心與用戶協作的標準界面。
  3. “託管式”而非“接管式”的統一鑑權機制:無論用戶是在使用的是公有云上的 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容器服務相關開發工作。InfoQ專欄作者。

殷達,清華大學與卡內基梅隆大學計算機專業在讀研究生,於阿里雲容器平臺部實習,主要參與ACK容器服務多雲技術及雲原生應用開發。

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章