# 2025 香港 KubeCon 參加心得:Cilium 如何達到高性能網路
聽了很多個議程,挑了以下議程跟大家分享:
Simplifying the Networking and Security Stack With Cilium, Hubble, and Tetragon
以下文章皆來自講者分享的內容。
# Cilium 如何達到高性能網路
## 1. 什麼是 eBPF

eBPF 是 Linux Kernel 的技術,你可以編寫一些程序放在 Kernel 當中,當特定的事件發生的時候,Kernel 會自動調用你的程序來實現你想要的功能。
Cilium 其實就是很多 eBPF 的程序來實現網路的轉發、安全性和可觀測。

除了這些之外,Cilium 其實還使用到了 envoy 來實現 Service Mesh 和 7 層相關的功能,根據上圖,大家可以得知,Cilium 已經可以部署到大多數的雲上了,而且大多數的 Kubernetes 的發行版都已經支持了。
## 2. Cilium features

以上是 Cilium 網路部分支持的功能,今天主要關注的是最左上角**高性能網路**的部分。
## 3. Standard Container Networking
Letʼs look at a standard container networking packet path:
* The pod to ClusterIP service that backend pod is on the same node.
* The pod access the Internet.

提到高性能網路,我們就必須看一下標準的網路轉發路徑,我們在這兩個場景下,就考慮 Kubernetes 的一個節點,然後一個節點就 2 個 pods,左邊的 Pod 就是 Pod A,IP 地址是 `1.1.1.1`,右邊的 Pod B IP 地址就是 `1.1.1.2`。
第一個場景是,在同一個 node 中 Pod A 透過 Service IP 存取 Pod B,第二個場景是 Pod A 直接訪問外部互聯網大概是一個什麼樣的場景,網路封包會怎麼流轉。
從 Pod A 假設要訪問 Service IP 是 `10.96.0.1` 然後網路封包就會從 Pod A 的網卡發送到主機側,主機側會開始進入主機的網路內核站,這個時候它一般會流向有一個表叫 prerouting nat 的表,然後這個地方會有 kubeproxy 生成 Iptable 的規則,把 IP 的目的地址改成 Pod B 的,然後這個封包會繼續流轉,然後在查詢到路油表後,就會發現是去 Pod B 的,然後會轉發到 Pod B 主機側的網卡,主機側的網卡會把封包發給 Pod B,這樣 Pod B 就收到了。
> 主機側網卡指的是 veth pair 中連接在 Host 主機上那一端的網卡,從技術的角度看,veth pair 是指有一對網卡會跨 Linux Network Namespace 互相連接,一端在 Pod 的 Linux Network Namespace,另一端就是在 Host 主機裡面 root 的 Linux network namespace 中的網卡。
第二個場景是 Pod A 直接連線出外部的互聯網時,Pod A 查路油表時,會發現是出去的流量,一般情況下會有 SNAT 的行為發生,Pod A 的 IP 會變成主機的實體網卡。
## 4. Iptables and IPVS

通常提到網路優化,很多時候會提到 IPVS 對 Iptables 的優化,
大家都知道 iptables 的查詢複雜程度是隨著服務數量或後端 Pod 數量的增加,查詢時間會線性增長,IPVS 則是在服務數量或後端 Pod 數量增加後,查詢時間並不會受到影響,也就是說大叢集的網路選 ipvs 的效率更高,但是具體情況發生什麼還是稍微有點複雜的。
## 5. IPVS
下圖就可以看到 IPVS 到底做了哪些事情,其實 IPVS 在這個地方只是替換了 prerouting nat 的表,當叢集很大時 IPVS 確實是有優勢的,問題是它只替換了這一部份,那你的封包還是在主機側的網路內核協議站走了整個內核協議站,這是其一,其二是當叢集沒那麼大時,IPVS 對 Iptables 的優化是未知的,IPVS 在運作上其實也有自己的開銷。

## 6. Kube-proxy replacement

從 cilium 的角度來看,cilium 有提供一個角度是 kube-proxy replacement,其實就是代替了 Kube-proxy,會有一個 eBPF 的程序掛載到 veth-pair 在主機側的網卡上,當 Pod A 到 Pod B 的流量在轉發時,Pod A 發給 Service IP,然後主機側的網卡收到封包後,會直接查詢的動作,然後把 IP 地址改到 Pod B,改到 Pod B 之後就不再通過整個內核協議站去查詢這些了,因為它就已經知道,要發到哪一張網卡上了,就直接透過 eBPF 程序把封包發給 Pod B 主機側的網卡,然後主機側的網卡就會再把封包發給 Pod B。
大家可以看到這已經跳過了很多內核協議站的網路部分,但因為是 Kube-proxy replacement,它只管理 Service 相關的,但這個時候 Pod A 出向的流量還是會查路由表,有的時候還是會通過 iptables 做 SNAT,在這種情況下。
## 7. eBPF host routing

Cilium 另一個優化的點其實是叫 eBPF host routing,這個地方一般情況下我們會說它有兩個優化 :
1. Pod A 出向的流量,會直接在 Pod A 主機側的網卡收到封包後,透過 eBPF 程序查詢,根據路由表,就直接發到出向的實體網卡。
2. 如同剛剛的場景,eBPF 程序收到了 Pod A 的封包後,他不解釋發到 Pod B 主機側的網卡,它其實是直接發到 Pod B 裡面,這樣的話又節省了一次從主機側將封包發給 Pod B 網卡的動作,這樣的話又減少了一點傳輸時間。
以上是兩個常見的優化。
## 8. Netkit
第三個是叫 Netkit,這是 Cilium 1.16 引入的,它其實是根據 Linux 核心中新的網路類型叫 Netkit 網路類型,這時候 eBPF 程序就掛載到了 pod 側,這種情況下就非常有意思,當 Pod A 發出一個流量到外部時,eBPF 程序就在 Pod 側就已經抓到了程序,可以直接發到物理網卡側,這樣 Pod A 就不需要把封包傳到主機側,這樣的話是一個非常大的優化,但比較可惜的是 Pod A 到 Pod B 的流量,他沒辦法做到 Pod A 到 Pod B 的直接轉發,雖然他在 Pod A 的容器側收到了,還是要發到 Pod B 主機側,還是沒有特別完美的轉發到 Pod B 這側。
