中通快遞關鍵業務和複雜架構挑戰下的 Kubernetes 叢集服務暴露

Bacer發表於2021-09-09

本文是上海站 Meetup 講師王文虎根據其分享內容整理的文章。

KubeSphere 社群的小夥伴們,大家好。我是中通快遞容器雲平臺的研發工程師王文虎,主要負責中通快遞容器雲平臺開發、應用容器化推廣、容器平臺運維等工作。非常感謝 KubeSphere 社群的邀請,讓我有機會跟大家分享中通快遞關鍵業務和複雜架構挑戰下的 Kubernetes 叢集服務暴露實踐。

ZKE 容器管理平臺

首先介紹一下中通的容器雲管理平臺 ZKE。ZKE 平臺是基於 KubeSphere 開發的,現在管理的中通內部叢集超過十個,包含開發、測試、預釋出、生產等環境,所有使用者都透過 ZKE 平臺管理容器應用。

圖片描述

Kubernetes 叢集服務暴露方案

根據中通的實際業務需求和一些探索,梳理出了中通 kubernetes 叢集服務暴露的幾種方案。

圖片描述

Dubbo 服務之間訪問

中通大部分應用都是基於 Java 語言開發的,使用的微服務框架為 Dubbo。在上容器之初,我們考慮到虛擬機器和容器並存的場景可能會持續很長時間,所以在規劃 Kubernetes 叢集的時候,透過把容器網路和物理網路打通的方式,來解決 Dubbo 服務在容器和虛擬機器混布的場景下互相呼叫的問題。

  • 如何打通 Kubernetes 容器網路和物理網路?

我們內部環境中 Kubernetes 叢集網路元件使用 calico BGP 模式,資料中心物理網路也開啟了 BGP 路由協議,透過在物理網路上開啟 BGP RR(Route Reflector),避免後期叢集規模太大導致 BGP 宣告路由條目過多的問題。BGP RR 和 Kubernetes 叢集節點建立 EBGP 鄰居,互相學習路由。

圖片描述

泛域名方式訪問

在初步推廣開發和測試容器化時,我們遇到最多的問題就是使用者在應用釋出到容器環境後如何訪問。

使用者在 ZKE 平臺上建立 Ingress 以後,該域名是不能訪問的,必須要運維把域名指向叢集 Ingress Controller,而且公司申請域名需要走 OA 流程,所以這就使得我們的容器環境在初始推廣階段進度很慢。

我們收集了部分使用者的反饋,加上自己的思考,終於探索出了一條開發/測試環境比較高效的 Ingress 使用之路:

透過給每個叢集分配一個三級泛域名,在公司 DNS 上配置把對應泛域名指向叢集的 Ingress Controller,使用者後續建立業務域名時可以直接在 ZKE 介面上建立 Ingress,該域名便會立即生效,省去了很大部分測試和開發環境上容器的時間,因為公司安全管理要求,Ingress 只提供了暴露 HTTP 協議的功能,但是這一措施也還是很大程度加快了測試開發容器化的推廣速度。

圖片描述

自定義域名訪問

泛域名可以幫我們解決大部分開發/測試環境的域名需求,但是針對生產環境、專案域名需要使用 HTTPS 協議、專案需要自定義域名這些場景時,使用者除了需要建立 Ingres 之外,還是需要透過 OA 流程進行審批的。

圖片描述

服務暴露方案踩坑實踐

以下內容是我們在使用 Kubernetes 的過程中服務暴露以及網路相關踩的坑,供大家參考以避坑。

Ingress Nginx Controller 服務踩坑實踐

下圖是我根據 Ingress Nginx Controller 程式碼啟動流程,畫的啟動流程圖。

圖片描述

Ingress Nginx Controller 啟動流程與一個通用的 K8S Controller 的類似,但是真正執行把 K8S Ingress 及其相關資源同步到 Nginx 配置檔案的業務邏輯是從 n.syncIngress 函式開始的,這個留到下面說。

該問題是我們測試環境使用過程中踩過的一個坑,使用者透過 ZKE 管理平臺建立 Ingress 時觸發了叢集 Ingress Controller 故障。我們在做故障分析時發現了故障復現的條件,如下圖所示:

圖片描述

前面說到 n.syncIngress 函式是 Ingress Nginx Controller 業務邏輯的入口,從該入口到本次故障最終呼叫函式中間的呼叫鏈 PPT 中也有提供,最終的問題點落在了 extractTLSSecretName 函式。

圖片描述

根據程式碼邏輯再分析一下原因:

  1. createServers 函式會遍歷 ing.Spec.Rules,當 ing.Spec.TLS 欄位不為空時會把 rule.Host、ingress 以引數形式傳入 extractTLSSecretName 函式;
  2. extractTLSSecretName 函式首先會遍歷 ing.Spec.TLS,校驗 tls.Hosts 中是否包含 host,如果包含直接返回 tls.SecretName
  3. tls.Hosts 中不包含 host 時,會把 tls.SecretName 對應的 secret 資源轉為 *ingress.SSLCert 型別並且校驗 host 是否匹配證照中的 SAN 或 CN 屬性。然而當配置的 secret 為非 TLS 型別證照時,cert.Certificate 值為 nil,就會導致 cert.Certificate.VerifyHostname(host) 處程式碼會報 panic 導致主程式異常,然後 nginx controller 就掛了;

修復措施分兩部分:

  1. 平臺使用者操作層面避免這種情況:主要是透過使用者建立 ingress 選擇證照時過濾掉非 TLS 型別的 secret,保證絕大部分透過平臺使用者不會觸發此類問題;
  2. 修復程式碼邏輯根治此問題:增加判斷 cert.Certificate 是否為nil的邏輯。

Calico 關閉 natOutgoing 配置

這個配置發生的背景是在 Dubbo 應用生產容器化過程中,生產環境 Zookeeper 對單個 IP 連線限制數比節點上 Pod 數小,導致節點上容器裡的 Dubbo 應用經常會出現連線 Zookeeper 被拒絕的問題。再因為容器網路和物理網路已經打通,透過 calico 配置 natOutgoing 引數為 false,這個問題就迎刃而解了。

圖片描述

來自 “ ITPUB部落格 ” ,連結:http://blog.itpub.net/2768/viewspace-2797107/,如需轉載,請註明出處,否則將追究法律責任。

相關文章