1. 程式人生 > 其它 >中通快遞關鍵業務和複雜架構挑戰下的 Kubernetes 叢集服務暴露實踐

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

本文是上海站 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 程式碼啟動流程,畫的啟動流程圖(關於啟動流程以及這個問題更詳細分析可以檢視連結:https://mp.weixin.qq.com/s/Pw9-_cPXxhfrd6btSXUrqA)。

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,這個問題就迎刃而解了。

本文由部落格一文多發平臺 OpenWrite 釋出!