OpenYurt 深度解讀:如何構建 Kubernetes 原生雲邊高效協同網絡?


頭圖.png

作者 | 鄭超

導讀:OpenYurt 是阿里巴巴開源的雲邊協同一體化架構,與同類開源方案相比,OpenYurt 擁有可實現邊緣計算全場景覆蓋的能力。在之前的一篇文章中,我們介紹了 OpenYurt 是如何在弱網和斷網場景下實現邊緣自治的。本文作為 OpenYurt 系列文章的第四篇,我們將着重介紹 OpenYurt 的另一個核心能力——雲邊通信,以及相關組件 Yurttunnel。

使用場景

在應用的部署和運維過程中,用戶常常需要獲取應用的日志,或直接登錄到應用的運行環境中進行調試。在 Kubernetes 環境中,我們通常使用 kubectl log,kubectl exec 等指令來實現這些需求。如下圖所示,在 kubectl 請求鏈路上, kubelet 將扮演服務器端,負責處理由 kube-apiserver(KAS) 轉發來的請求,這就要求 KAS 和 kubelet 之間需要存在一條網絡通路,允許 KAS 主動訪問 kubelet

1.png
圖一:kubectl 執行流程

然而,在邊緣計算場景中,邊緣節點常位於本地專有網絡中,這雖然保證了邊緣節點的安全,但也造成位於雲端管控節點的 KAS 無法直接訪問位於邊緣節點的 kubelet。因此,為了支持通過雲端節點對邊緣端應用進行運維操作,我們必須在雲、邊之間建立反向運維通道。

反向通道

Yurttunnel 是 OpenYurt 近期開源的一個重要組件,用來解決雲邊通信問題。反向通道是解決跨網絡通信的一種常見方式,而 Yurttunnel 的本質就是一個反向通道。一個邊緣集群下屬的節點常位於不同的 network region 中,而位於同一個 region 內的節點之間是可以相互通信的,因此在設置反向通道時,我們只需保證在每個 region 內設置一個與 proxy server 相連的 agent 即可(如下圖所示)。具體包括以下幾個步驟:

  • 在管控組件所在網絡內,部署 proxy server。
  • proxy server 對外開放一個公網可以訪問的 IP。
  • 在每個 region 部署個 agent,並通過 server 的公網 IP 與 server 建立長連接。
  • 管控組件對邊緣節點的訪問請求都將轉發致 proxy server。
  • proxy server 再將請求通過對應的長連接發往目標節點。

2.png
圖二

在 Yurttunnel 中,我們選擇使用上游項目 apiserver-network-proxy(ANP) 來實現 server 和 agent 間的通信。ANP 是基於 kubernetes 1.16 Alpha 新功能 EgressSelector 開發,意在實現 Kubernetes 集群組件的跨 intranet 通信(例如,master 位於管控 VPC,而 kubelet 等其他組件位於用戶 VPC)。

讀者可能會好奇,既然 OpenYurt 是基於 ACK@Edge 開源的,而在生產環境中, ACK@Edge 的雲邊運維通道使用的是自研組件 tunnellib,那為什么在開源版本里我們要選用一個新的組件呢? 這里不得不再次提到 OpenYurt 的核心設計理念 “Extend upstream Kubernetes to Edge”

誠然,tunnellib 經過了復雜線上環境的考驗,組件性能穩定,但我們更希望能與上游保持最大的技術公約數,讓 OpenYurt 的用戶體驗更接近原生 Kubernetes ;同時,在 ACK@Edge 的開發和運維過程中,我們發現,邊緣集群的許多需求也同樣存在於其他場景中(例如,大多數雲廠商也需要實現節點跨網絡通信),並且運維通道的傳輸效率也能進一步優化(4.5章將詳述優化過程)。因此,秉承開放分享、平等普惠的開源精神,我們希望能將開發和運維過程中積累的的寶貴經驗在上游社區與更多的開發者分享。

ANP 並非開箱即用

然而 ANP 項目仍處於起步階段,功能尚未完善,許多問題仍有待解決。我們從實踐中發現的主要問題包括:

  • 如何轉發雲端節點的請求 -- 反向通道正常工作的一個前提是,管控節點發往邊緣節點的請求必須先經過 proxy server。對於 Kubernetes 1.16 + 版本,KAS 能借由 EgressSelector 將發往節點的請求先發往指定的 proxy server。但對於 1.16 以前的版本,KAS 及其他管控組件(Prometheus 和 metrics server)只能直接訪問節點,而不能繞道 proxy server。可以預見的是,部分用戶在短期內,仍將使用 1.16 以前的版本,並且 Prometheus 和 metrics server 等管控組件在短期內也沒有支持 EgressSelector 的計划。因此,我們要解決的第一個問題是,如何將管控組件發往節點的請求轉發致 proxy server

  • 如何確保 server 副本覆蓋所有的 region -- 在生產環境中,一個邊緣集群常常包含上萬個節點,並同時服務上百名用戶,如果一個集群只有一個 proxy server, 那么,一旦 proxy server 出現故障,所有用戶都將無法對位於邊緣節點上的 pod 進行操作。因此,我們必須同時部署多個 proxy server 副本以保證集群高可用。同時,proxy server 的工作負荷將隨着訪問流量的增大而增大,用戶的訪問延時也勢必增加。因此在部署 proxy server 時,我們還需考慮如何對 proxy server 進行水平拓展,以應對高並發場景。一個應對單點故障和高並發場景的經典解決方案是,部署多個 proxy server 副本,並使用負載均衡進行流量分發。然而在 OpenYurt 場景下,對於 KAS 發來的任意請求,LoadBalancer (LB) 會轉發給哪個 server 副本是不可控的,因此,需要解決的第二個問題是,如何保證每個 server 副本都能與所有的 agent 建立連接

  • 如何將請求轉發給正確的 agent -- 在運行過程中,proxy server 在收到請求后,需根據請求的 destination IP,將請求轉發至位於對應 network region 內的 agent。然而,ANP目前的實現,假設所有的節點都位於一個網絡空間內, server 會隨機挑選一個 agent 轉發請求。因此,我們需要解決的第三個問題是,如何將請求正確地轉發給指定的 agent

  • 如何解除組件對節點證書的依賴 -- 在運行時,我們需要為 server 提供一套 TLS 證書,以實現 server 與 KAS,server 與 agent 間的安全通信。同時,我們也需要為 agent 准備一套 TLS client 證書,用以建立 agent 和 server 間的 gRPC 信道。ANP 目前的實現,要求 server 必須和 KAS 部署在同一個節點上,並且在啟動時掛載節點 volume 共享 KAS tls 證書。同樣,agent 也需要在啟動時掛載 volume 共享 kubelet tls 證書。這無形中降低了部署的靈活性,造成了組建對節點證書的強依賴,在有些情況下,用戶可能希望將 server 部署在非 KAS 所在節點上。因此,另一個需要關注的問題是,如何解除組件對節點證書的依賴

  • 如何縮小 Tunnel 帶寬 -- ANP 的一個核心設計思想,是使用 gRPC 封裝 KAS 所有對外 HTTP 請求。這里選擇 gRPC,主要是看重其對流(stream)的支持和清晰的接口規范,此外,強類型的客戶端和服務器端可以有效減少運行時錯誤,提高系統穩定性。然而,我們也發現,相較於直接使用 TCP 協議,采用 ANP 也會帶來額外的開銷增加帶寬。從產品層面考慮,Tunnel 流量走的是公網,帶寬的增加也意味着用戶成本的增加。因此,一個非常重要的問題是,在提高系統穩定性的同時,我們是否也能縮小帶寬

Yurttunnel 設計解析

1. 制定 DNAT 規則轉發雲端節點的請求

如前文所述,ANP 是基於上游新功能 EgressSelector 開發的,該功能允許用戶在啟動 KAS 時通過傳入 egress configuration 來要求 KAS 將 egress 請求轉發到指定的 proxy server。但由於我們需要兼顧新老版本的 Kubernetes 集群,並且考慮到,其他管控組件(Prometheus 和 metric server)並不支持 EgressSelector 特性,我們需要保證在無法使用 EgressSelector 的情況下也能將 KAS egress 請求轉發致 proxy server。為此,我們在每一個雲端管控節點上都部署一個 Yurttunnel Server 副本,並在 Server 中內嵌一個新組件 Iptabel Manager。Iptable Manager 會通過在宿主機的 Iptable 中的 OUTPUT 鏈中添加 DNAT 規則,將管控組件對節點的請求轉發致 Yurttunnel Server。

同時,當啟用 EgressSelector 后,KAS 對外請求都遵循一個統一的格式,因此我們新增一個組件, ANP interceptor。ANP interceptor 會負責截取從 master 發來的 http 請求,並將其封裝成 EgressSelector 格式。Yurttunnel 請求轉發的具體流程見圖三。

3.png
圖三:Yurttunnel 請求轉發流程

2. 動態獲取 Server 副本數

在上一節中,我們提到,我們將采用負載均衡的方式來管理 yurttunnel server,所有的 ingress 請求都會通過 LB 分發給一個 server 副本。由於我們無法預測 LB 會挑選哪個 server 副本,我們必須保證每個 server 副本都要與所有的 agent 建立連接。這里,我們將使用 ANP 自帶的功能實現這一需求,具體流程如下:

  • 在啟動 yurttunnel server 時,我們會將副本數(serverCount)傳入每個 server 副本中,並且為每個副本指定一個 server ID;

  • agent 連接 LB 后,LB會隨機選擇一個 server 副本並讓其與 agent 建立長連接;

  • 與此同時,server 會通過該通道向 agent 返回一個 ACK package,這個 package 中將包含 serverCount 和 serverID;

  • agent 通過解析 ACK package,可以獲悉 server 副本的個數,並在本地記錄已連接的 serverID;

  • 如果 agent 發現,本地連接的 server 副本數小於 serverCount,則會再次向 LB 發送連接請求,直至本地記錄的 serverID 數與 server Count 數一致為止。

該機制雖然幫助我們實現了 server 副本的全網段覆蓋。但同時,也存在不可忽視的缺點,由於 agent 無法選擇與哪個 server 副本建立連接,因此,為了連接所有的 server 副本,agent 必須反復訪問 LB。在這個過程中,server 由於還沒有與所有的 agent 建立連接,KAS 發來的請求可能無法轉發至對應的節點。一個潛在的解決方案是,為每個 server 副本創建一個獨立的 LB,負責與 agent 之間的連接,同時在 agent 端記錄所有 server 副本對應 LB 的信息,這一方案能幫助 agent 快速地與所有的 server 副本建立連接。該方案的具體實現細節,目前仍在與上游社區的開發者討論中。

3. 為 ANP 添加代理策略

在 OpenYurt 的網絡模型下,邊緣節點分布在不同的 network region 中,隨機選擇的 agent 可能無法將請求轉發至位於其他 region 內的節點上。因此我們不得不修改 ANP server 底層代理轉發的邏輯。然而,根據長期的經驗,我們相信,proxy server 支持不同的代理策略,例如,將請求轉發至指定數據中心,region,或者指定主機,是一個較為通用的需求。經過和 ANP 社區開發者討論,我們決定重構 ANP 管理 agent 連接的接口,允許用戶根據需求實現新的代理策略,並計划將該 feature 最終合入上游代碼庫。目前重構工作仍在進行中,在 Yurttunnel 第一個開源版本中,我們暫時采用以下配置:

  • 在每個邊緣節點上部署一個 agent。

  • agent 在 server 處登記時,使用 agent 所在節點的 IP 作為 agentID。

  • server 在轉發請求時,通過匹配請求目標 IP 和 agentID,將請求轉發至對應的 agent。

我們計划在 OpenYurt 后續發布 Yurt Unit(邊緣節點分區管控)之后,配合新增的 ANP 代理轉發策略,實現 agent 的分區部署,和請求的分區轉發。

4. 動態申請安全證書

為了解除 yurttunnel 組件對節點證書的依賴,我們在 yurttunnel 中新增 cert manager 組建,cert manager 會在 server 和 agent 運行后,向 KAS 提交 certificate signning request(CSR)。server 將使用申請到的證書來確保其與 KAS 和 agent 間的安全通信,agent 會使用申請到的證書確保其與 server 間 gRPC 信道的安全。由於 agent 和 kubelet 間是通過 tcp 協議連接,因此,我們無需為 agent 和 kubelet 間的連接准備證書。

5. 壓縮 Tunnel 帶寬,節約成本

在 3.5 中,我們提到,使用 gRPC 封裝 Tunnel 雖然可以提高傳輸穩定性,但同時也會增加公網流量。這是否意味着穩定性和性能,我們只能二選一?通過對不同用戶場景的分析,我們發現,在大多數情況下,用戶使用運維通道是為了獲取容器日志(即 kubectl log),而傳統日志文件,存在許多相同的文本信息,因此我們推斷使用 gzip 等壓縮算法能有效縮小帶寬。為了驗證這一假設,我們在 ANP 底層的 gRPC 庫中添加了 gzip compressor,並且對比了與使用原生 TCP 連接場景下的數據傳輸量。

我們考慮的第一個實驗場景是,分別通過 TCP 連接和 ANP 獲取同一 kubeproxy 容器的日志,我們截取了這一過程中 Tunnel 上雙向 package 和 bytes 總量。

4.png
表 1: 原生 TCP V.S. ANP (kubectl logs kube-proxy)

如表 1 所示,通過使用 ANP, 總傳輸數據量下降了 29.93%

經過長時間運行,容器的日志文本常常可以達到十幾兆,為了模擬獲取大文本日志的場景。我們創建了一包含 10.5M systemd log(即 journalctl)的 ubuntu 容器,同樣我們分別使用原生 TCP 連接和 ANP 傳輸該日志文件,並測量了 Tunnel 上的數據總量。

5.png
表 2: 原生 TCP V.S. ANP (large log file)

如表 2 所示,在日志文本較大的情況下,通過使用 ANP, 總傳輸數據量下降了 40.85%

由此可見,相較於原生 TCP 連接,ANP 不僅能提供更高的傳輸穩定性,還可以大幅降低公網流量。考慮到邊緣集群動輒上萬的節點規模,新的解決方案將幫助用戶在公網流量方面節約大量開銷。

Yurttunnel 系統架構

6.png
圖四:Yurttunnel 系統架構

綜上,Yurttunnel 主要包含以下組件:

  • Yurttunnel Server - 負責將 apiserver,prometheus,metrics server 等管控組件發往節點的請求,轉發至對應的 agent。具體包括以下子組件:

    • ANP Proxy Server - 對 ANP gRPC server 的封裝,負責管理與 Yurttunnel Agent 之間的長連接,並轉發請求。
    • Iptable Manager - 修改管控節點的 DNAT 規則,以確保管控組件的請求能被轉發至 Yurttunnel Server。
    • Cert Manager - 為 Yurttunnel Server 生成 TLS 證書。
    • Request Interceptor - 將 KAS 對節點的 HTTP 請求封裝到符合 ANP 規則的 gRPC 包里。
  • **Yurttunnel Agent **- 與 Yurttunnel Server 主動建立連接,並將 Yurttunnel Server 發來的請求轉發給 Kubelet。具體包括兩個子組件:

    • ANP Proxy Agent - 對 ANP gRPC agent 的封裝,相較於上游,我們額外加入了 gzip compressor 以壓縮數據。
    • Cert Manager - 為 Yurttunnel Agent 生成 TLS 證書。
  • Yurttunnel Server Service - 通常是一個 SLB,負責將管控組件發來的請求分發給合適的 Yurttunnel Server 副本,保證 Yurttunnel 的高可用和負載均衡。

總結與展望

Yurttunnel 作為 OpenYurt 近期開源的重要組件,打通了 OpenYurt 集群的雲邊通道,為邊緣集群上的容器運維提供了一個統一的入口。通過對上游解決方案進行改造,Yurttunnel 不僅提供了更高的傳輸穩定性,也大幅降低了數據傳輸量。

OpenYurt 於 2020 年 5 月 29 日正式對外開源,借助社區和廣大開發者的力量快速成長,開源僅 3 個月后就正式成為 CNCF 沙箱級別邊緣計算雲原生項目。未來,OpenYurt 將延續 “Extending your upstream Kubernetes to edge” 的核心設計理念,在選擇與上游保持最大技術公約數的同時,發揚開源分享的精神,與廣大開發者一起推進 Kubernetes 社區的進步。

OpenYurt 已入圍 “2020 年度 10 大新銳開源項目”,歡迎大家點擊鏈接:https://www.infoq.cn/talk/sQ7eKfv1KW1A0kUafBgv,選擇“25 號”,為 OpenYurt 加油助力!

阿里巴巴雲原生關注微服務、Serverless、容器、Service Mesh 等技術領域、聚焦雲原生流行技術趨勢、雲原生大規模的落地實踐,做最懂雲原生開發者的公眾號。”


免責聲明!

本站轉載的文章為個人學習借鑒使用,本站對版權不負任何法律責任。如果侵犯了您的隱私權益,請聯系本站郵箱yoyou2525@163.com刪除。



 
粵ICP備18138465號   © 2018-2025 CODEPRJ.COM