Cilium
作为近两年最火的云原生网络计划,堪称是风头无两。作为第一个通过 ebpf 实现了 kube-proxy 所有性能的网络插件,它的神秘面纱到底是怎么的呢?本文次要介绍Cilium
的倒退演进,性能介绍以及具体应用示例。
背景
随着云原生的普及率越来越高,各大厂商基本上或多或少都实现了业务的 K8s 容器化,头部云计算厂商更是不用说。
而且随着 K8s 的 遍及,以后集群逐步呈现出以下两个特点:
- 容器数量越来越多,比方:K8s 官网单集群就曾经反对 150k pod
- Pod 生命周期越来越短,Serverless 场景下甚至短至几分钟,几秒钟
随着容器密度的增大,以及生命周期的变短,对原生容器网络带来的挑战也越来越大。
以后 K 8s Service 负载平衡 的实现现状
在 Cilium 呈现之前,Service 由 kube-proxy 来实现,实现形式有 userspace
,iptables
,ipvs
三种模式。
Userspace
以后模式下,kube-proxy 作为反向代理,监听随机端口,通过 iptables 规定将流量重定向到代理端口,再由 kube-proxy 将流量转发到 后端 pod。Service 的申请会先从用户空间进入内核 iptables,而后再回到用户空间,代价较大,性能较差。
Iptables
存在的问题:
- 可扩展性差。随着
service
数据达到数千个,其管制面和数据面的性能都会急剧下降。起因在于 iptables 管制面的接口设计中,每增加一条规定,须要遍历和批改所有的规定,其管制面性能是O(n²)
。在数据面,规定是用链表组织的,其性能是O(n)
。 - LB 调度算法仅反对随机转发。
Ipvs 模式
IPVS 是专门为 LB 设计的。它用 hash table 治理 service,对 service 的增删查找都是 O(1)的工夫复杂度。不过 IPVS 内核模块没有 SNAT 性能,因而借用了 iptables 的 SNAT 性能。
IPVS 针对报文做 DNAT 后,将连贯信息保留在 nf_conntrack 中,iptables 据此接力做 SNAT。该模式是目前 Kubernetes 网络性能最好的抉择。然而因为 nf_conntrack 的复杂性,带来了很大的性能损耗。
Cilium 的倒退
Cilium
是基于 eBpf
的一种开源网络实现,通过在 Linux 内核动静插入弱小的安全性、可见性和网络管制逻辑,提供网络互通,服务负载平衡,平安和可观测性等解决方案。简略来说能够了解为 Kube-proxy + CNI 网络实现。
Cilium
位于容器编排零碎和 Linux Kernel 之间,向上能够通过编排平台为容器进行网络以及相应的平安配置,向下能够通过在 Linux 内核挂载 eBPF 程序,来管制容器网络的转发行为以及安全策略执行。
简略理解下 Cilium
的倒退历程:
- 2016 Thomas Graf 创建了 Cilium, 现为 Isovalent (Cilium 背地的商业公司)的 CTO
- 2017 年 DockerCon 上 Cilium 第一次公布
- 2018 年 公布 Cilium 1.0
- 2019 年 公布 Cilium 1.6 版本,100% 代替 kube-proxy
- 2019 年 Google 全面参加 Cilium
- 2021 年 微软、谷歌、FaceBook、Netflix、Isovalent 在内的多家企业发表成立 eBPF 基金会(Linux 基金会下)
性能介绍
查看官网,能够看到 Cilium
的性能次要蕴含 三个方面,如上图:
-
网络
-
高度可扩大的 kubernetes CNI 插件,反对大规模,高动静的 k8s 集群环境。反对多种租网模式:
Overlay
模式,反对 Vxlan 及 GeneveUnerlay
模式,通过 Direct Routing(间接路由)的形式,通过 Linux 宿主机的路由表进行转发
- kube-proxy 替代品,实现了 四层负载平衡性能。LB 基于 eBPF 实现,应用高效的、可有限扩容的哈希表来存储信息。对于南北向负载平衡,Cilium 做了最大化性能的优化。反对 XDP、DSR(Direct Server Return,LB 仅仅批改转发封包的指标 MAC 地址)
- 多集群的连通性,Cilium Cluster Mesh 反对多集群间的负载,可观测性以及平安管控
-
<!—->
- 可观测性
- 提供生产可用的可观测性工具 hubble, 通过 pod 及 dns 标识来辨认连贯信息
- 提供 L3/L4/L7 级别的监控指标,以及 Networkpolicy 的 行为信息指标
- API 层面的可观测性 (http,https)
- Hubble 除了本身的监控工具,还能够对接像 Prometheus、Grafana 等支流的云原生监控体系,实现可扩大的监控策略
-
平安
- 不仅反对 k8s Network Policy,还反对 DNS 级别、API 级别、以及跨集群级别的 Network Policy
- 反对 ip 端口 的 平安审计日志
- 传输加密
总结,Cilium 不仅包含了 kube-proxy + CNI 网络实现,还蕴含了泛滥可观测性和平安方面的个性。
装置部署
linux 内核要求
4.19
及以上
能够采纳 helm
或者 cilium cli
,此处笔者应用的是 cilium cli
(版本为 1.10.3
)
- 下载
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
- 装置
cilium
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
cilium install --kube-proxy-replacement=strict # 此处抉择的是齐全替换,默认状况下是 probe,(该选项下 pod hostport 个性不反对)
- 可视化组件 hubble(选装)
cilium hubble enable --ui
- 期待 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
cilium cli
还反对 集群可用性查看(可选)
[root@~]# cilium connectivity test
ℹ️ Single-node environment detected, enabling single-node connectivity test
ℹ️ Monitor aggregation detected, will skip some flow validation steps
✨ [kubernetes] Creating namespace for connectivity check...
✨ [kubernetes] Deploying echo-same-node service...
✨ [kubernetes] Deploying same-node deployment...
✨ [kubernetes] Deploying client deployment...
✨ [kubernetes] Deploying client2 deployment...
⌛ [kubernetes] Waiting for deployments [client client2 echo-same-node] to become ready...
⌛ [kubernetes] Waiting for deployments [] to become ready...
⌛ [kubernetes] Waiting for CiliumEndpoint for pod cilium-test/client-6488dcf5d4-rx8kh to appear...
⌛ [kubernetes] Waiting for CiliumEndpoint for pod cilium-test/client2-65f446d77c-97vjs to appear...
⌛ [kubernetes] Waiting for CiliumEndpoint for pod cilium-test/echo-same-node-745bd5c77-gr2p6 to appear...
⌛ [kubernetes] Waiting for Service cilium-test/echo-same-node to become ready...
⌛ [kubernetes] Waiting for NodePort 10.251.247.131:31032 (cilium-test/echo-same-node) to become ready...
⌛ [kubernetes] Waiting for Cilium pod kube-system/cilium-vsk8j to have all the pod IPs in eBPF ipcache...
⌛ [kubernetes] Waiting for pod cilium-test/client-6488dcf5d4-rx8kh to reach default/kubernetes service...
⌛ [kubernetes] Waiting for pod cilium-test/client2-65f446d77c-97vjs to reach default/kubernetes service...
ð Enabling Hubble telescope...
⚠️ 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"
ℹ️ 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)。
cilium status
次要展现 cilium
的一些简略配置信息及状态,如下:
[root@~]# 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)
cilium service list
展现 service
的实现,应用时可通过 ClusterIP
来过滤,其中,FrontEnd
为 ClusterIP
,Backend
为 PodIP
。
[root@~]# 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
# 防止过多,此处不一一展现
cilium service get
通过 cilium service get < ID> -o json
来展现详情:
[root@~]# 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
)。