http://arthurchiao.art/blog/trip-stepping-into-cloud-native-networking-era-zh/
This post also provides an English version.
本文是我們的前一篇博客 Trip.com: First Step towards Cloud Native Networking 的後續,介紹自上一篇博客以來我們在基於 Cilium 的雲原生網絡和雲原生安全方面的一些 探索和實踐。
1 網絡演進:簡要回顧
從 2013 到 2018 年,我們經歷了物理機到虛擬機再到容器的基礎設施演進,但網絡技 術棧基本都是沿用 Neutron+OVS —— 即使對我們(前期)的 Kubernetes 集羣也是 如此。但業務開始往 Kubernetes 遷移之後,這套 Neutron+OVS 的網絡方案越來越捉襟見肘, 尤其是在部署密度更高、規模更大的容器面前,這種大二層網絡模型的軟件和硬件瓶頸暴露無遺 [1]。
爲了解決這些問題,更重要地,爲了滿足雲原生業務的各種需求(例如,支持Kubernetes 的 Service 模型),我們調研了很多較新的網絡方案,綜合評估之後,選擇了 Cilium+BGP 的組合 [3]。
Fig 1-1. Networking solutions over the past years [2]
Cilium+BGP 方案 2019 年底正式在我們生產環境落地,我們打通了 Cilium 網絡和現有網 絡,因此能灰度將容器從 Neutron 遷移到 Cilium。
2 雲原生網絡實踐
作爲 Cilium 的早起用戶之一,我們對 Cilium 的實現和部署做了一些修改或定製化,以使 這套方案能平滑地落地到我們現有的基礎設施之中,例如 [2],
-
用
docker-compsoe + salt
來部署,而不是採用默認的daemonset+configmap
方式。這樣每臺 node 上的 cilium-agent 都有獨立配置,我們能完全控制發佈灰度,將 變更風險降到最低。
-
用
BIRD
作爲 BGP agent,而不是採用默認的kube-router
。kube-router
開箱即用,但缺少對 ECMP、BFD 等高級功能的支持,不符合我們生產環境的要求。 -
爲了保證某些業務的平滑遷移,我們開發了 StatefulSet/AdvancedStatefulSet 固定 IP 的支持(需要 sticky 調度配合)。
-
定製化了監控和告警。
-
其他一些自定義配置。
我們之前的一篇文章 [2] 對此有較詳細的介紹,有興趣可以移步。 下面討論幾個之前介紹較少或者沒有覆蓋到的主題。
2.1 BGP 建連模型
Cilium+BIRD 方案中,以宿主機爲界,網絡可以大致分爲兩部分,如圖 2-1 所示,
Fig 2-1. High level topology of the Cilium+BGP solution [2]
- 宿主機內部網絡:由 Cilium(及內核協議棧)負責,職責包括,
- 爲容器創建和刪除虛擬網絡。
- 爲容器生成、編譯和加載 eBPF。
- 處理同宿主機內容器之間的網絡通信。
- 跨宿主機網絡:由 BGP(及內核路由模塊)負責,職責包括,
- 與數據中心網絡交換路由(PodCIDRs)。
- 對出宿主機的流量進行路由。
對於跨宿主機部分,需要確定要採用哪種 BGP peering 模型,這個模型解決的問題包括 :
- BGP agent 的職責,是作爲一個全功能路由控制服務,還是僅用作 BGP speaker?
- 宿主機和數據中心的哪些設備建立 BGP 鄰居?
- 使用哪種 BGP 協議,iBGP 還是 eBGP?
- 如何劃分自治域(AS),使用哪種 ASN(自治域系統編號)方案?
取決於具體的網絡需求,這套 BGP 方案可能很複雜。基於我們數據中心網絡能提供的能力 及實際的需求,我們採用的是一種相對比較簡單的模型,
- 每臺 node 運行 BIRD,僅作爲 BGP speaker,
- Node 在上線時會自動分配一個
/25
或/24
的 PodCIDR。 - BIRD 和數據中心網絡中的兩個鄰居建立 BGP 連接。
- BIRD 將 PodCIDR 通告給鄰居,但 不從鄰居接受任何路由。
- Node 在上線時會自動分配一個
- 數據中心網絡只從 node 接受
/25
或/24
路由宣告,但不向 node 宣告任何路由。 - 整張網絡是一張三層純路由網絡(pure L3 routing network)。
這種模型的簡單之處在於,
- 數據中心網絡從各 node 學習到 PodCIDR 路由,瞭解整張網絡的拓撲,因此 Pod 流量在數據中心可路由。
- Node 不從數據中心學習任何路由,所有出宿主機的流量直接走宿主機默認路由(到數據 中心網絡),因此宿主機內部的路由表不隨 node 規模膨脹,沒有路由條目數量導致的性能瓶頸。
Fig 2-2. BGP peering model in 3-tier network topology
在路由協議方面,
- 老數據中心基於“接入-匯聚-核心”三級網絡架構,如圖 2-2 所示,
- 節點和核心交換機建立 BGP 連接。
- 使用 iBGP 協議交換路由。
- 新數據中心基於 Spine-Leaf 架構,
- 節點和直連的 Leaf 交換機(置頂交換機)建立 BGP 連接。
- 使用 eBGP 協議交換路由。
我們已經將這方面的實踐整理成文檔,見 Using BIRD to run BGP [3]。
2.2 典型流量轉發路徑:從 Pod 訪問 Service
來看一下在這套方案中,典型的流量轉發路徑。
假設從一個 Pod 內訪問某個 Service,這個 Service 的後端位於另一臺 Node,如下圖所示,
Fig 2-3. Traffic path: accessing Service from a Pod [4]
主要步驟:
- 在 Node1 上的 Pod1 裏面訪問某個 Service (
curl <ServiceIP>:<port>
)。 - eBPF 處理 Service 抽象,做客戶端負載均衡:選擇某個後端,然將包的目的 IP 地址從 ServiceIP 換成後端 PodIP(即執行 DNAT)。
- 內核路由決策:查詢系統路由表,根據包的目的 IP 地址確定下一跳;對於這個例 子匹配到的是默認路由,應該通過宿主機網卡(或 bond)發送出去。
- 包到達宿主機網卡(bond),通過默認路由發送到宿主機的默認網關(配置在數據中心 網絡設備上)。
- 數據中心網絡對包進行路由轉發。由於此前數據中心網絡已經從各 Node 學習到了 它們的 PodCIDR 路由,因此能根據目的 IP 地址判斷應該將包送到哪個 Node。
- 包達到 Node 2 的網卡(bond):一段 eBPF 代碼負責提取包頭,根據 IP 信息找到 另一段和目的 Pod 一一對應的 eBPF 代碼,然後將包交給它。
- 後一段 eBPF 代碼對包執行 入向策略檢查,如果允許通過,就將包交給 Pod4。
- 包到達 Pod4 的虛擬網卡,然後被收起。
我們有一篇專門的文章詳細介紹整個過程,見 [4]。
2.3 集羣邊界 L4/L7 入口解決方案
在 Kubernetes 的設計中,ServiceIP 只能在集羣內訪問,如果要從集羣外訪問 Service 怎麼辦?例如,從 baremetal 集羣、OpenStack 集羣,或者其他 Kubernetes 集羣訪問?這屬於集羣邊界問題。
K8s 爲這些場景提供了兩種模型:
- L7 模型:稱爲 Ingress,支持以 7 層的方式從集羣外訪問 Service,例如通過 HTTP API 訪問。
- L4 模型: 包括 externalIPs Service、LoadBalancer Service,支持以 4 層的方 式訪問 Service,例如通過 VIP+Port。
但是,K8s 只提供了模型,沒提供實現,具體的實現是留給各廠商的。例如,假如你使 用的是 AWS,它提供的 ALB 和 ELB 就分別對應上面的 L7 和 L4 模型。在私有云,就需要 我們自己解決。
我們基於 Cilium+BGP+ECMP 設計了一套四層入口方案。本質上這是一套四層負載均衡器( L4LB),它提供一組 VIP,可以將這些 VIP 配置到 externalIPs 類型或 LoadBalancer 類 型的 Service,然後就可以從集羣外訪問了。
Fig 2-4. L4LB solution with Cilium+BGP+ECMP [5]
基於這套四層入口方案部署 istio ingress-gateway,就解決了七層入口問題。從集羣外訪 問時,典型的數據轉發路由如下:
Fig 2-5. Traffic path when accesing Service from outside the Kubernetes cluster [5]
我們之前有篇博客詳細介紹這個主題,見 [5]。
3 雲原生安全嘗試
Cilium 提供的兩大核心能力:
- 基於 eBPF 的靈活、動態、高性能網絡。
- L3-L7 安全策略:CiliumNetworkPolicy 是對 K8s 的 NetworkPolicy 的擴展。
在落地了網絡功能後,針對安全需求,我們在嘗試落地基於 Cilium 的安全。
3.1 Cilium 安全策略
首先來看一個簡單的例子,看看 CiliumNetworkPolicy (CNP) 長什麼樣 [6]:
apiVersion: "cilium.io/v2"
kind: CiliumNetworkPolicy
metadata:
name: "clustermesh-ingress-l4-policy"
description: "demo: allow only employee to access protected-db"
spec:
endpointSelector:
matchLabels:
app: protected-db
ingress:
- toPorts:
- ports:
- port: "6379"
protocol: TCP
fromEndpoints:
- matchLabels:
app: employee
上面的 yaml:
- 創建一個 CNP,可以指定
name
和description
等描述字段。 - 對帶
app=protected-db
標籤(labels)的 endpoints(pods)執行這個 CNP。 - 在執行 CNP 的時候,只對入向(
ingress
)流量做控制,並且限制如下流量來源:- 協議是
TCP
,並且端口是6379
. - 流量來自帶
app:employee
labels 的 endpoints(pods)。
- 協議是
可以看到,CNP 非常靈活,使用起來也很方便。但真實世界要遠比想象中複雜,要真正落地 Cilium 安全策略,還存在很多挑戰。
3.2 落地挑戰
下面舉兩個例子,相信這些問題在很多公司都需要面對,並不是我們獨有的。
多集羣問題
如果你所有的應用都運行在 Cilium 集羣中,並且客戶端和服務端都收斂到一個集羣(大部 分公有云廠商都推薦一個 region 只部署一套 K8s 集羣,所有訪問都收斂到這套集羣),那落 地起來會簡單很多。
但大部分有基礎設施演進的公司恐怕都不滿足這個假設,實際的情況很可能是:業務分散在多 個集羣。
混合基礎設施
多集羣還不是最大的問題,因爲業界多少還有一些多集羣解決方案。
更嚴重的一個問題是:業務不僅分散在不同集羣,而且在不同平臺。例如對我們來說,現在 有:
- Bare metal 集羣
- OpenStack 集羣
- 基於 Neutron+OVS 的 Kubernetes 集羣
- 基於 Cilium+BGP 的 Kubernetes 集羣
雖然我們計劃將所有容器從 Neutron 網絡遷移到 Cilium 網絡,但另外兩種,bare metal 和 OpenStack 集羣,還是會長期存在的,雖然規模可能會逐漸減小。
3.3 整體方案設計
我們目前的一個整體方案:在服務端容器做入向安全策略,客戶端可以來自任何平臺、任何集羣:
- 這將範圍框定到了已經在 Cilium 網絡的服務端容器,是一個不錯的起點。
- 傳統網絡裏的服務端容器,會逐漸遷移到 Cilium 網絡。
- BM 和 VM 的服務端實例,第一階段先不考慮安全控制。
那接下來的問題就是:服務端如何具備對所有類型、所有集羣的客戶端進行限制的能力? 我們的解決方案是:
- 首先,用 Cilium 提供 ClusterMesh 將已有 Cilium 集羣連接起來;
- 然後,“擴展” ClusterMesh,讓它能感知到 mesh 之外的 endpoints,即 BM、BM 和 Neutron Pods。
下面分別解釋這兩點。
3.3.1 用 ClusterMesh 做 Cilium 集羣互連
Fig 3-1. Vanilla Cilium ClusterMesh [6]
ClusterMesh [7] 是 Cilium 自帶的一個多集羣解決方案。如果所有應用都在 Cilium 集羣 裏,那這種方式可以解決跨集羣的安全策略問題,即,application 實例可以分佈在不同的集羣。
這樣說來,使用 ClusterMesh 似乎是理所當然的,但其實它並不是我們當初的第一選擇。 因爲多集羣還有其他方案,本質上做的事情就是如何在多個集羣之間同步元數據,並且做到 集羣變動的實時感知。
- 出於多個內部需求,當時有考慮自己做這樣一套元數據同步方案,它能解決包括 Cilium 在內的多個需求。
- 並未看到業界大規模使用 ClusterMesh 的案例,所以對它的可用性還存疑。
但後來綜合對比了幾種選項之後,覺得 ClusterMesh 還是值得嘗試的。
關於 ClusterMesh 的實地(功能)測試,可以參考我們之前的一篇博客 [6]。
3.3.2 擴展 ClusterMesh,感知 mesh 外實例
這裏的外部實例(external endpoints)包括 Neutron Pod、VM、BM。
基於對 Cilium 的理解,我們判斷只要將外部實例信息以 Cilium 能感知的方式(格式)同 步到 Cilium 集羣,那在入向(inbound),Cilium 對這些實例的控制能力,與對原生 Cilium 實例的控制能力並無區別。換句話說,我們“騙一下” Cilium,讓它認爲這些實例都是 Cilium endpoints/pods。
爲此我們開發了一個組件,使得 OpenStack 平臺、Bare metal 平臺和Neutron-powered Kubernetes 平臺能將它們的實例創建/銷燬/更新信息同步更新到 Cilium 集羣,如下圖所示:
Fig 3-2. Proposed security solution over hybrid infrastructures
結合 3.3.1 & 3.3.2,在這套“擴展之後的” ClusterMesh 中,每個 Cilium agent 都對 全局實例(container/vm/bm)有着完整的、一致的視圖,因此能在 Cilium Pod 的入向 對各種類型的客戶端做安全控制。目前計劃支持的是 L3-L4 安全策略,未來考慮支持 L7。
這套方案已經通過了功能驗證,正在進行正式開發和測試,計劃年底開始灰度上線。
4 總結
本文總結了我們自上一篇博客以來,在基於 Cilium 的雲原生網絡和雲原生安全方面的一些 探索和實踐。更多技術細節,可參考下面一些鏈接。
參考文獻
- Ctrip Network Architecture Evolution in the Cloud Computing Era
- Trip.com: First Step towards Cloud Native Networking.
- Cilium Doc: Using BIRD to run BGP
- Life of a Packet in Cilium: Discovering the Pod-to-Service Traffic Path and BPF Processing Logics
- L4LB for Kubernetes: Theory and Practice with Cilium+BGP+ECMP
- Cilium ClusterMesh: A Hands-on Guide
- Cilium Doc: clustermesh