位元組跳動kube-apiserver高可用方案KubeGateway

陶然陶然發表於2022-11-01

  本文整理自 2022 年稀土開發者大會,位元組跳動雲原生工程師章駿分享了 Kubernetes 叢集 kube-apiserver 請求的負載均衡和治理方案 KubeGateway。

  KubeGateway 是位元組跳動針對 kube-apiserver 流量特徵專門定製的七層閘道器,它徹底解決了 kube-apiserver 負載不均衡的問題,同時在社群範圍內首次實現了對 kube-apiserver 請求的完整治理,包括請求路由、分流、限流、降級等,顯著提高了 Kubernetes 叢集的可用性。

  專案地址:

   1. 背景

  在 Kubernetes 叢集中,kube-apiserver 是整個叢集的入口,任何使用者或者程式對叢集資源的增刪改查操作都需要經過 kube-apiserver,因此它的高可用性決定了整個叢集的高可用能力。kube-apiserver 本質上是一個無狀態的伺服器,為了實現其高可用,通常會部署多個 kube-apiserver 例項,同時引入外部負載均衡器(以下簡稱 LB)進行流量代理。  

  為了保證叢集的安全,kube-apiserver 對請求進行認證和授權的准入控制,其中認證是為了識別出使用者的身份。Kubernetes 支援多種認證策略,比如 Bootstrap Token、Service Account Token、OpenID Connect Token、TLS 雙向認證等。

  目前 kube-apiserver 的客戶端使用得較多的策略是 TLS 雙向認證。TLS 雙向認證需要 LB 將請求中的 Client X509 Cert 正確傳遞給 kube-apiserver,但是傳統的七層 LB 無法做到這一點,在轉發過程中會丟失 Client X509 Cert,導致 kube-apiserver 無法認證使用者。

  因此目前 LB 的選型一般為 LVS、雲廠商的 SLB 或 nginx、HAProxy 的四層負載均衡方案。

  四層負載均衡工作在 OSI 的第四層即傳輸層,使用 NAT 技術進行代理轉發

  七層負載均衡工作在 OSI 的第七層即應用層,一般是基於請求 URL 地址的方式進行代理轉發。

  但是使用四層 LB 會引起另外的問題,具體如下:

  請求負載不均衡:由於 kube-apiserver 和 client 是使用 HTTP2 協議連線,HTTP2 的多個請求都會複用底層的同一個 TCP 連線並且長時間不斷開。在 kube-apiserver 滾動升級或者某個例項重啟時,很容易引起遲些啟動的 kube-apiserver 在長時間內只有很少的請求數。極端情況下,負載較高的例項會出現 OOM,甚至引起雪崩。  

  缺乏請求治理的靈活性:4 層負載均衡在傳輸層工作,它只負責訊息的傳遞,但是無法處理應用層的 HTTP 協議的資訊,因此相較於 7 層負載缺乏對請求治理的“靈活性”和 “智慧性”。比如無法根據請求的內容(比如 verb、url 等欄位)制定靈活的負載均衡和路由策略,也無法在閘道器層對請求級別進行限流降級等處理。

  社群中有一些相關工作試圖解決上述問題,但均沒有根治問題:  

  隨著雲原生技術的發展,目前位元組跳動 95% 以上的業務跑在 Kubernetes 上,對叢集高可用提出了更高的要求。事實上,在生產環境中,我們也曾遇到過多次由於 kube-apiserver 負載不均衡或者缺乏請求治理能力帶來的事故,面對以上問題,我們針對 kube-apiserver 的流量特徵自研了七層閘道器 KubeGateway。

   2. 架構設計

  KubeGateway 作為七層閘道器接入和轉發 kube-apiserver 的請求,它具有以下特點:

  對於客戶端完全透明,客戶端無需任何改造即可以接入 KubeGateway;

  支援同時代理多個 K8s 叢集的請求,不同 K8s 叢集透過不同的域名或者虛擬地址(vip)進行區分。

  負載均衡從 TCP 連線級別變為 HTTP 請求級別,進而實現快速、有效的進行負載均衡,徹底解決 kube-apiserver 負載不均衡的問題。

  高擴充套件性的負載均衡策略,目前支援 Round Robin、Random 策略,負載均衡策略外掛化,易於擴充套件。

  支援靈活的路由策略,KubeGateway 根據請求資訊,包括但不限於 resource/ verb/ user/ namespace/ apigroup 等進行路由。為 kube-apiserver 分組提供基礎能力,以低運維成本實現 kube-apiserver 組之間的隔離性,提高叢集穩定性。

  配置管理雲原生化,以 K8s 的標準 API 形式管理閘道器配置,支援配置熱更新。

  支援限流、降級、動態服務發現、優雅退出、upstream 異常檢測等閘道器的通用能力。

  KubeGateway 對外以 K8s 標準 API 的形式提供代理配置管理的服務,主要提供路由轉發規則、上游叢集 kube-apiserver 地址、叢集證書資訊、限流等請求治理策略等配置資訊的維護變更。它代理 kube-apiserver 的請求的流程如下圖所示,主要分為五個步驟:請求解析、路由匹配、使用者認證、流量治理和反向代理。下面依次對這些步驟進行詳細介紹:  

  2.1 請求解析

  KubeGateway 可以深入理解 kube-apiserver 請求模型,從中解析出更多的資訊,它將 kube-apiserver 的請求分為兩種型別:

  資源請求,如對 Pod 的 CRUD(增刪改查)。

  非資源請求,如訪問 /healthz 檢視 kube-apiserver 的健康情況,訪問 /metrics 檢視暴露的指標等。

  對於資源請求,可以從請求的 URL 和 Header 中解析出以下的內容:  

  最終一個請求可以解析出多維度的路由欄位,如下圖所示,這些欄位將作為路由選擇的依據。  

  2.2 路由匹配

  從請求中解析出多維度的路由欄位後,可以很方便地組合出非常強大的路由規則來區分不同的 API 請求,比如

  透過 Verb 和 Resource 的結合,我們可以直接匹配到所有的 list pod 的請求。

  透過 User,UserGroup,ServiceAccount 等,我們可以匹配出 kube-controller-manager,kube-scheduler 等核心控制元件的請求。

  將不同的請求經過路由規則匹配後,我們能對它們做更精細化的分流,限流,熔斷等流量控制。

  匹配規則可以直接透過修改 KubeGateway 的配置管理服務對外暴露的 API -- UpstreamCluster 實時生效。

  2.3 使用者認證

  為了能夠正確地代理 kube-apiserver 的七層流量,讓請求經過代理後的在 upstream kube-apiserver 能被正確地進行認證授權,KubeGateway 需要將請求中的使用者資訊透傳給 kube-apiserver,這要求 KubeGateway 也能認證出請求中的使用者資訊。

  KubeGateway 將 kube-apiserver 支援的認證方式可以分為以下幾類

  基於 x509 客戶端證書的認證方式:KubeGateway 透過規則 upstream kube-apiserver 中的 CA 證書,解析出客戶端證書中使用者和使用者組資訊

  基於 Bearer Token 的認證方式:KubeGateway 透過給 upstream kube-apiserver 傳送 TokenReview 請求,要求 upstream kube-apiserver 對 Bearer Token 進行認證,從而得到對應的使用者資訊。

  識別出使用者後,KubeGateway 透過 kube-apiserver 提供的 Impersonate(使用者扮演)機制進行轉發,詳細內容會在 2.5.1 部分進行介紹。此外,KubeGateway 只會對請求進行認證,並不會對請求進行授權判斷,授權操作由 upstream kube-apiserver 進行。

  2.4 請求治理

  KubeGateway 作為七層閘道器,有著豐富的流量治理能力,具體包括:

  2.4.1 負載均衡

  UpstreamCluster 確定後,Upstream Servers 也隨之確定。KubeGateway 按照負載均衡策略從 Upstream Servers 中選擇出一個進行請求轉發。良好的負載均衡策略可以最佳化資源效率,最大化吞吐量,減少延遲和容錯。

  目前 KubeGateway 支援 Round Robin 和 Random 負載均衡策略,這兩種策略簡單有效,能夠滿足大部分場景的需求。此外,KubeGateway 支援靈活的負載均衡策略擴充套件,可以快速實現 Least Request 等演算法,以滿足更多場景的需求。

  2.4.2 健康監測

  KubeGateway 會定期主動地訪問 kube-apiserver 的 /healthz 介面進行健康監測。代理流量只會轉發給健康的 kube-apiserver;而不健康的 kube-apiserver 會被臨時遮蔽,當它被恢復健康後才會重新有新的流量

  2.4.3 限流

  KubeGateway 預設提供限流的能力,可以有效地防止 upstream kube-apiserver 在某些情況下過載。它的限流方案相比於 Kubernetes 本身的 APF(API Priority and Fairness)更容易理解和配置。請求經過請求解析和路由匹配之後,KubeGateway 會確定這個請求的限流規則。

  比如我們想要限制普通使用者 list pod 的 QPS 但是又要對管控元件(如 controller-manager,scheduler)進行豁免,可以在路由匹配中區分出兩種型別的使用者然後為他們單獨配置 FlowControl 限流規則。  

  KubeGateway 提供了兩種限流策略:

  token bucket:令牌桶是常用的限流方式,它能有效地限制請求的 QPS 並在一定程度上允許突發的請求。

  max requests inflight:最大請求數是比令牌桶更嚴格的限制方式,它限制在某個時刻能夠執行的最大請求數量,通常用來限制一些更加耗時的請求,比如在大叢集 list 全量 pods,這種請求會可能會持續好幾分鐘,而且會佔用 kube-apiserver 大量的資源,只透過令牌桶的限流會放入過多的請求而造成 kube-apiserver OOM 等問題。

  2.4.4 降級

  KubeGateway 支援降級以應對叢集管控面異常的情況。

  在 kube-apiserver 或者 ETCD 發生故障的時候,可能引起叢集的雪崩。在雪崩情況下,部分請求會返回成功,部分請求返回失敗,加上客戶端不斷重試,容易導致叢集出現非預期行為,比如 Node NotReady、 Pod 大量驅逐和刪除等。

  在這種情況下,開發人員可以透過 KubeGateway 進行降級操作拒掉所有流量。在降級狀態下叢集相當於被凍結了,所有寫入都無法成功,可以保證存量的 Pod 程式保持存活狀態,避免對業務造成影響。在叢集恢復正常後,首先放開限制允許 Node 上報心跳,然後再恢復叢集的其他流量。

  2.5 反向代理

  KubeGateway 在反向代理部分,有以下關鍵的技術點:

  2.5.1 Impersonate(使用者扮演)

  在透過流量治理後,KubeGateway 會根據選擇出的 kube-apiserver 進行轉發。在轉發的時候 KubeGateway 透過 impersonate 的機制將使用者資訊透過 Request Header 傳遞給 upstream kube-apiserver。在 Request Header 中新增以下資訊:

  Impersonate-User: Client 使用者名稱Impersonate-Group: Client 使用者組

  Impersonate 是 kube-apiserver 對外提供的一種機制,它允許一個使用者扮演成另外一個使用者執行 API 請求。在使用這個機制之前,我們需要在 upstream kube-apiserver 為 KubeGateway 的客戶端配置好 Impersonate 的許可權,Impersonate 的請求具體的流程如下:  

  kube-apiserver 認證 KubeGateway 使用者,識別出使用者扮演的行為。

  kube-apiserver 確保 KubeGateway 具有 Impersonate 許可權。

  kube-apiserver 根據 HTTP Header 識別出 KubeGateway 扮演的使用者名稱和使用者組,然後將請求執行者替換成被扮演的使用者。

  對被扮演的使用者進行授權驗證,檢查他是否有許可權訪問對應的資源。

  kube-apiserver 對於 Impersonate 機制支援的很完善,審計日誌中也相容了 Impersonate。

  最終 KubeGateway 依靠使用者認證和 Impersonate 機制,完成原始使用者資訊的透傳,解決了傳統七層 LB 無法代理 kube-apiserver 請求的問題。而且在代理過程中,對於客戶端是完全透明的,客戶端無需進行任何修改即可接入 KubeGateway。

  2.5.2 HTTP2 多路複用

  KubeGateway 預設使用 HTTP2 協議,基於 HTTP2 協議的多路複用能力,單條連線上預設支援 250 個 Stream,即單個連線上支援 250 個併發的請求,使得 upstream 單個 kube-apiserver 的 TCP 連線數可以降低兩個數量級。  

  2.5.3 Forward & Exec 類請求處理

  KubeGateway 支援所有原生 kube-apiserver 請求的透明代理。由於 Forward 、Exec 等部分請求需要透過 HTTP 1.1 建立的連結之上使用其他的協議(比如 SPDY、WebSocket 等)來進行通訊,KubeGateway 在轉發這類請求時會禁止 http2,且支援 Hijacker 處理。

   3. 落地效果

  經過壓測,KubeGateway 效能優異,經過代理後,請求延遲增加在 1ms 左右。目前 KubeGateway 已經平滑的接管了位元組所有的 Kubernetes 叢集,總 QPS 20w+。在 KubeGateway 的幫助下,研發團隊徹底解決了 kube-apiserver 流量不均衡的問題,而且極大增強了 kube-apiserver 請求的治理能力,包括請求分組、路由、限流、降級等,有效提高了叢集的穩定性和可用性。

  同時,我們在 KubeGateway 優雅升級、多叢集動態證書管理、可觀測性上也做了很多最佳化,具體技術細節以後會進行更多的介紹,敬請期待。

   4. 未來演進

  目前,KubeGateway 已在 GitHub 開源,未來它會在以下幾個方面持續演進:

  提供更完整的 7 層閘道器能力,比如黑白名單,快取等。

  持續提高可觀測性,可以在異常情況下能夠快速定位到問題,輔助排障。

  探索基於 KubeGateway 閘道器實現新型的聯邦方案,透過 KubeGateway 可以將多個 K8s 叢集透明地聚合成一個叢集。

  期待有更多朋友關注和加入 KubeGateway 社群,也歡迎大家在 GitHub 給我們提出各種建議!

來自 “ 位元組跳動技術團隊 ”, 原文作者:章駿;原文連結:http://server.it168.com/a2022/1031/6771/000006771415.shtml,如有侵權,請聯絡管理員刪除。

相關文章