【理解 Cilium 系列文章】(一) 初識 Cilium

語言: CN / TW / HK

Cilium 作為近兩年最火的雲原生網路方案,可謂是風頭無兩。作為第一個通過 ebpf 實現了 kube-proxy 所有功能的網路外掛,它的神祕面紗究竟是怎樣的呢?本系列文章將帶大家一起來慢慢揭曉

作為 《理解 Cilium 系列文章》 的第一篇,本文主要介紹 Cilium 的發展,相關功能以及使用,深入理解及底層原理將在後續文章中繼續介紹

背景

隨著雲原生的普及率越來越高,各大廠商基本上或多或少都實現了業務的 k8s 容器化,頭部雲端計算廠商更是不用說。

而且隨著 k8s 的 普及,當前叢集逐漸呈現出以下兩個特點:

  1. 容器數量越來越多,比如:k8s 官方單叢集就已經支援 150k pod

  2. Pod 生命週期越來 越短 ,Serverless 場景下甚至短至幾分鐘,幾秒鐘

隨著容器密度的增大,以及生命週期的變短,對原生容器網路帶來的挑戰也越來越大

當前 k8s Service 負載均衡的實現現狀

在 Cilium 出現之前, Service 由 kube-proxy 來實現,實現方式有 userspaceiptablesipvs 三種模式。

Userspace

當前模式下,kube-proxy 作為反向代理,監聽隨機埠,通過 iptables 規則將流量重定向到代理埠,再由 kube-proxy 將流量轉發到 後端 pod。Service 的請求會先從使用者空間進入核心 iptables,然後再回到使用者空間,代價較大,效能較差。

Iptables

存在的問題:

1.可擴充套件性差。隨著 service 資料達到數千個,其控制面和資料面的效能都會急劇下降。原因在於 iptables 控制面的介面設計中,每新增一條規則,需要遍歷和修改所有的規則,其控制面效能是 O(n²) 。在資料面,規則是用連結串列組織的,其效能是 O(n)

2.LB 排程演算法僅支援隨機轉發

Ipvs 模式

IPVS 是專門為 LB 設計的。它用 hash table 管理 service,對service 的增刪查詢都是O(1)的時間複雜度。不過 IPVS 核心模組沒有 SNAT 功能,因此借用了 iptables 的 SNAT 功能。

IPVS 針對報文做 DNAT 後,將連線資訊儲存在 nf_conntrack 中,iptables 據此接力做 SNAT。該模式是目前 Kubernetes 網路效能最好的選擇。但是由於 nf_conntrack 的複雜性,帶來了很大的效能損耗。騰訊針對該問題做過相應的優化 【繞過conntrack,使用eBPF增強 IPVS優化K8s網路效能】

Cilium 的發展

Cilium 是基於 eBpf 的一種開源網路實現,通過在 Linux 核心動態插入強大的安全性、可見性和網路控制邏輯,提供網路互通,服務負載均衡,安全和可觀測性等解決方案。簡單來說可以理解為 Kube-proxy + CNI 網路實現。

Cilium 位於容器編排系統和 Linux Kernel 之間,向上可以通過編排平臺為容器進行網路以及相應的安全配置,向下可以通過在 Linux 核心掛載 eBPF 程式,來控制容器網路的轉發行為以及安全策略執行

簡單瞭解下 Cilium 的發展歷程:

  1. 2016 Thomas Graf 創立了 Cilium, 現為 Isovalent (Cilium 背後的商業公司)的 CTO

  2. 2017 年 DockerCon 上 Cilium 第一次釋出

  3. 2018 年 釋出 Cilium 1.0

  4. 2019 年 釋出 Cilium 1.6 版本,100% 替代 kube-proxy

  5. 2019 年 Google 全面參與 Cilium

  6. 2021 年 微軟、谷歌、FaceBook、Netflix、Isovalent 在內的多家企業宣佈成立 eBPF 基金會(Linux 基金會下)

功能介紹

檢視官網,可以看到 Cilium 的功能主要包含 三個方面,如上圖

一、網路

  1. 高度可擴充套件的 kubernetes CNI 外掛,支援大規模,高動態的 k8s 叢集環境。支援多種租網模式:

    1. Overlay 模式,支援 Vxlan 及 Geneve
    2. Unerlay 模式,通過 Direct Routing (直接路由)的方式,通過 Linux 宿主機的路由表進行轉發
  2. kube-proxy 替代品,實現了 四層負載均衡功能。LB 基於 eBPF 實現,使用高效的、可無限擴容的雜湊表來儲存資訊。對於南北向負載均衡,Cilium 作了最大化效能的優化。支援 XDP、DSR(Direct Server Return,LB 僅僅修改轉發封包的目標 MAC 地址)

  3. 多叢集的連通性,Cilium Cluster Mesh 支援多叢集間的負載,可觀測性以及安全管控

二、可觀測性

  1. 提供生產可用的可觀測性工具 hubble, 通過 pod 及 dns 標識來識別連線資訊

  2. 提供 L3/L4/L7 級別的監控指標,以及 Networkpolicy 的 行為資訊指標

  3. API 層面的可觀測性 (http,https)

  4. Hubble 除了自身的監控工具,還可以對接像 Prometheus、Grafana 等主流的雲原生監控體系,實現可擴充套件的監控策略

三、安全

  1. 不僅支援 k8s Network Policy,還支援 DNS 級別、API 級別、以及跨叢集級別的 Network Policy

  2. 支援 ip 埠 的 安全審計日誌

  3. 傳輸加密

總結,Cilium 不僅包括了 kube-proxy + CNI 網路實現,還包含了眾多可觀測性和安全方面的特性。

安裝部署

linux 核心要求 4.19 及以上

可以採用 helm 或者 cilium cli ,此處筆者使用的是 cilium cli (版本為 1.10.3

  1. 下載 cilium cli
wget https://github.com/cilium/cilium-cli/releases/latest/download/cilium-linux-amd64.tar.gz
tar xzvfC cilium-linux-amd64.tar.gz /usr/local/bin
  1. 安裝 cilium
cilium install --kube-proxy-replacement=strict # 此處選擇的是完全替換,預設情況下是 probe,(該選項下 pod hostport 特性不支援)
  1. 視覺化元件 hubble(選裝)

cilium hubble enable --ui
  1. 等待 pod ready 後,檢視 狀態如下:

~# cilium status
/¯¯\
/¯¯\__/¯¯\ Cilium: OK
\__/¯¯\__/ Operator: OK
/¯¯\__/¯¯\ Hubble: OK
\__/¯¯\__/ ClusterMesh: disabled
\__/

DaemonSet cilium Desired: 1, Ready: 1/1, Available: 1/1
Deployment cilium-operator Desired: 1, Ready: 1/1, Available: 1/1
Deployment hubble-relay Desired: 1, Ready: 1/1, Available: 1/1
Containers: hubble-relay Running: 1
cilium Running: 1
cilium-operator Running: 1
Image versions cilium quay.io/cilium/cilium:v1.10.3: 1
cilium-operator quay.io/cilium/operator-generic:v1.10.3: 1
hubble-relay quay.io/cilium/hubble-relay:v1.10.3: 1
  1. cilium cli 還支援 叢集可用性檢查(可選)
[[email protected]~]# cilium connectivity test
:information_source: Single-node environment detected, enabling single-node connectivity test
:information_source: Monitor aggregation detected, will skip some flow validation steps
:sparkles: [kubernetes] Creating namespace for connectivity check...
:sparkles: [kubernetes] Deploying echo-same-node service...
:sparkles: [kubernetes] Deploying same-node deployment...
:sparkles: [kubernetes] Deploying client deployment...
:sparkles: [kubernetes] Deploying client2 deployment...
:hourglass: [kubernetes] Waiting for deployments [client client2 echo-same-node] to become ready...
:hourglass: [kubernetes] Waiting for deployments [] to become ready...
:hourglass: [kubernetes] Waiting for CiliumEndpoint for pod cilium-test/client-6488dcf5d4-rx8kh to appear...
:hourglass: [kubernetes] Waiting for CiliumEndpoint for pod cilium-test/client2-65f446d77c-97vjs to appear...
:hourglass: [kubernetes] Waiting for CiliumEndpoint for pod cilium-test/echo-same-node-745bd5c77-gr2p6 to appear...
:hourglass: [kubernetes] Waiting for Service cilium-test/echo-same-node to become ready...
:hourglass: [kubernetes] Waiting for NodePort 10.251.247.131:31032 (cilium-test/echo-same-node) to become ready...
:hourglass: [kubernetes] Waiting for Cilium pod kube-system/cilium-vsk8j to have all the pod IPs in eBPF ipcache...
:hourglass: [kubernetes] Waiting for pod cilium-test/client-6488dcf5d4-rx8kh to reach default/kubernetes service...
:hourglass: [kubernetes] Waiting for pod cilium-test/client2-65f446d77c-97vjs to reach default/kubernetes service...
🔭 Enabling Hubble telescope...
:warning: Unable to contact Hubble Relay, disabling Hubble telescope and flow validation: rpc error: code = Unavailable desc = connection error: desc = "transport: Error while dialing dial tcp [::1]:4245: connect: connection refused"
:information_source: Expose Relay locally with:
cilium hubble enable
cilium status --wait
cilium hubble port-forward&
🏃 Running tests...

等 hubble 安裝完成後,hubble-ui service 修改為 NodePort型別, 即可通過 NodeIP+NodePort 來登入 Hubble 介面 檢視相關資訊

Cilium 部署完後,有以下幾個元件 operator、hubble(ui, relay),Cilium agent(Daemonset 形式,每個節點一個),其中關鍵元件為 cilium agent。

Cilium Agent作為整個架構中最核心的元件,通過DaemonSet的方式,以特權容器的模式,執行在叢集的每個主機上。Cilium Agent作為使用者空間守護程式,通過外掛與容器執行時和容器編排系統進行互動,進而為本機上的容器進行網路以及安全的相關配置。同時提供了開放的API,供其他元件進行呼叫。

Cilium Agent在進行網路和安全的相關配置時,採用eBPF程式進行實現。Cilium Agent結合容器標識和相關的策略,生成 eBPF 程式,並將 eBPF 程式編譯為位元組碼,將它們傳遞到 Linux 核心。

相關命令介紹

Cilium agent 中內建了一些除錯用的命令,下面介紹,agent  中的 cilium 不同與上述介紹的 cilium cli ( 雖然同為 cilium)

  1. cilium status

主要展示 cilium 的一些簡單配置資訊及狀態,如下

[[email protected]~]# kubectl exec -n kube-system cilium-s62h5 -- cilium status
Defaulted container "cilium-agent" out of: cilium-agent, ebpf-mount (init), clean-cilium-state (init)
KVStore: Ok Disabled
Kubernetes: Ok 1.21 (v1.21.2) [linux/amd64]
Kubernetes APIs: ["cilium/v2::CiliumClusterwideNetworkPolicy", "cilium/v2::CiliumEndpoint", "cilium/v2::CiliumNetworkPolicy", "cilium/v2::CiliumNode", "core/v1::Namespace", "core/v1::Node", "core/v1::Pods", "core/v1::Service", "discovery/v1::EndpointSlice", "networking.k8s.io/v1::NetworkPolicy"]
KubeProxyReplacement: Strict [eth0 10.251.247.131 (Direct Routing)]
Cilium: Ok 1.10.3 (v1.10.3-4145278)
NodeMonitor: Listening for events on 8 CPUs with 64x4096 of shared memory
Cilium health daemon: Ok
IPAM: IPv4: 68/254 allocated from 10.0.0.0/24,
BandwidthManager: Disabled
Host Routing: Legacy
Masquerading: BPF [eth0] 10.0.0.0/24 [IPv4: Enabled, IPv6: Disabled]
Controller Status: 346/346 healthy
Proxy Status: OK, ip 10.0.0.167, 0 redirects active on ports 10000-20000
Hubble: Ok Current/Max Flows: 4095/4095 (100.00%), Flows/s: 257.25 Metrics: Disabled
Encryption: Disabled
Cluster health: 1/1 reachable (2021-08-11T09:33:31Z)
  1. cilium service list

展示 service 的實現,使用時可通過 ClusterIP 來過濾,其中, FrontEndClusterIPBackendPodIP

[[email protected]~]# kubectl exec -it -n kube-system cilium-vsk8j -- cilium service list
Defaulted container "cilium-agent" out of: cilium-agent, ebpf-mount (init), clean-cilium-state (init)
ID Frontend Service Type Backend
1 10.111.192.31:80 ClusterIP 1 => 10.0.0.212:8888
2 10.101.111.124:8080 ClusterIP 1 => 10.0.0.81:8080
3 10.101.229.121:443 ClusterIP 1 => 10.0.0.24:8443
4 10.111.165.162:8080 ClusterIP 1 => 10.0.0.213:8080
5 10.96.43.229:4222 ClusterIP 1 => 10.0.0.210:4222
6 10.100.45.225:9180 ClusterIP 1 => 10.0.0.48:9180
# 避免過多,此處不一一展示
  1. cilium service get

通過 cilium service get < ID> -o json 來展示詳情

[[email protected]~]# kubectl exec -it -n kube-system cilium-vsk8j -- cilium service get 132 -o json
Defaulted container "cilium-agent" out of: cilium-agent, ebpf-mount (init), clean-cilium-state (init)
{
"spec": {
"backend-addresses": [
{
"ip": "10.0.0.213",
"nodeName": "n251-247-131",
"port": 8080
}
],
"flags": {
"name": "autoscaler",
"namespace": "knative-serving",
"trafficPolicy": "Cluster",
"type": "ClusterIP"
},
"frontend-address": {
"ip": "10.98.24.168",
"port": 8080,
"scope": "external"
},
"id": 132
},
"status": {
"realized": {
"backend-addresses": [
{
"ip": "10.0.0.213",
"nodeName": "n251-247-131",
"port": 8080
}
],
"flags": {
"name": "autoscaler",
"namespace": "knative-serving",
"trafficPolicy": "Cluster",
"type": "ClusterIP"
},
"frontend-address": {
"ip": "10.98.24.168",
"port": 8080,
"scope": "external"
},
"id": 132
}
}
}

還有很多有用的命令,限於篇幅,此處不一一展示,留給讀者自己去探索( cilium status --help

《理解 Cilium 系列文章》 的第一篇到此就講完了,後續文章將按照 Cilium 涉及的基礎知識及相關原理進行介紹,敬請期待

關注公眾號:瞭解更多雲原生 Serverless 熱點。 回覆 “進群”,即可與眾多雲原生 Serverless 技術大佬探討技術,探討人生。