前言
iptables/netfilter的弊端
-
规则太多
集群中pod的创建和销毁是很频繁的,pod的ip也就会经常发生变化,目前常用的CNI插件比如flannel和基于BGP的calico都是使用iptables的,而iptables是基于ip和TCP/UDP端口的。这种在集群规模小的时候基本没有什么性能问题。但当集群规模较大时,iptables规则可能多大几十万条,不停的变动会给系统带来了很大的压力,维护这些规则也会变得非常困难。
(PS:目前calico已经支持了基于eBPF) -
链路太长
netfilter框架在IP层,报文需要经过链路层,IP层才能被处理,如果是需要丢弃报文,会白白浪费很多CPU资源,影响整体性能; -
规则匹配
iptables有4表(nat,filter,mangle,raw)5链(prerouting,input,forward,output,postrouting),极端情况下,要匹配所有规则,才能命中,影响性能。
CNI的发展阶段
总体来说,CNI插件的发展大致分为以下几个阶段:
- 基于Linux bridge以及基于ovs实现的overlay网络。
- 基于BGP等三层路由能力的网络。
- 基于macvlan,ipvlan等偏物理网络的underlay网络。
- 基于Kernel的eBPF技术实现的网络。
- 基于dpdk/sriov/offload等实现的用户态的网络。
其中前三种都是基于netfilter,也就是iptables,直接使用内核的能力。
而第四种也就是cilium也会用到iptables,但是它会尽量的绕过netfilter/iptables,使用基于内核的eBPF技术实现网络设备之间的redirect,让数据包的路径尽量的短,进而达到高性能的目的。
第五种方案网络处理速度是最快的,dpdk让数据包从网卡到用户态程序再到目标网卡。需要使用独立的CPU,也会对硬件有限制,这里暂不介绍。
什么是Cilium
官网地址:https://cilium.io/
GitHub地址:https://github.com/cilium/cilium
Cilium是一款开源软件,用于透明地保护使用Docker和Kubernetes等Linux容器管理平台部署的应用程序服务之间的网络连接。
Cilium基于内核的eBPF技术。它支持在各种集成点(如网络IO、应用socket和跟踪点)上动态插入eBPF字节码到Linux内核,以实现安全性、网络和可见性逻辑。
eBPF是高效和灵活的。由于eBPF在Linux内核中运行,因此可以应用和更新Cilium安全策略,并且不需要更新应用代码或重启服务就可以生效。
Cilium是怎么避开iptables的
Cilium提供了基于service/pod/container作为标识,而非传统的 ip地址,并且可以对应用层进行过滤(例如HTTP)。
因此,通过将安全性与寻址解耦,Cilium不仅简化了在高度动态环境中应用安全策略的工作,而且除了提供传统的L3,L4层隔离之外,还可以提供L7层更强的网络策略。
Cilium的功能
透明的防护策略和安全API
能够保护现代应用协议,如REST/HTTP, gRPC和Kafka。传统防火墙在第3层和第4层运行,要么允许要么拒绝访问。Cilium提供了过滤个别应用协议请求的能力,例如:
- 允许所有带有GET方法和路径/public/.*的HTTP请求。拒绝所有其他请求。
- 允许service1生成Kafka主题topic1, service2消费topic1。拒绝所有其他Kafka消息。
基于身份的服务通信
基于标签的安全性可以实现集群内部的访问控制。有相同Identity标签的容器组是具有相同安全身份的,在处理安全策略的时候,是同样的验证逻辑。这样有一个好处是,不会随着Pod重启导致Pod ip变化,而让policy需要重新生成或者配置的问题。
安全访问内部服务和对外访问
支持基于传统CIDR的进出安全策略。这允许限制外部对特定IP范围的应用访问和内部可以访问的外部应用。
简单的网络
能够跨越多个集群的L3网络连接所有应用程序容器。通过使用IPAM,可以让每台主机之间不需要协调就可以分配ip地址。支持的组网类型有:
- Overlay :基于封装的虚拟网络,横跨所有主机。目前,VXLAN和geneva是内置的,但Linux支持的所有封装格式都可以启用。只要网络通,都可以使用。
- Native Routing:使用Linux主机的路由表。要求网络能够访问应用容器的IP地址。
负载均衡
Cilium实现了pod之间和外部服务之间的分布式负载平衡,并且能够完全替代kube-proxy。负载平衡在eBPF中使用一致性哈希表。具体就是在客户端访问时,使用一致性Hash的算法来决定由哪一个 Pod 提供服务,这样可以保证选择的Pod是固定的,以及当提供服务的Pod机器出现故障时,访问不受影响。
对于南北向的LB,外部客户端通过负载均衡访问集群内部服务的方式。如Client访问NodePort类型的Service。
Cilium的eBPF有非常高的性能,可以附加到XDP (eXpress Data Path),并支持直接服务器返回(DSR)。
对于东西向的LB,指的是集群内部,通过内部负载均衡实现的跨主机的容器网络通信。如Pod访问ClusterIP类型的Service。
Cilium在Linux内核的套接字层(例如TCP连接时)执行高效的服务到后端转换,这样每个包的NAT操作开销可以在较低的层中避免。
监控和故障诊断
获得可见性和故障排除的能力是任何分布式系统操作的基础。Cilium可以提供以下工具:
- 使用元数据进行事件监控:当一个数据包被丢弃时,该工具不仅报告数据包的源和目的IP,还提供发送方和接收方的完整标签信息以及许多其他信息。
- 通过Prometheus导出指标:通过Prometheus导出关键指标,以便与现有的仪表板集成。
- Hubble :为Cilium专门编写的可观测平台。它提供服务依赖关系映射、操作监视和告警,以及基于流日志的应用安全可见性。(后续介绍)
架构图
相关概念
Cilium
Agent:
- 以DaemonSet的方式运行在所有的节点上,并且提供 API。负责全局eBPF程序的编辑和挂载,以及为Pod编译和挂载Pod对应的eBPF程序,当有 Pod 被创建的时候,CNI就会在完成容器本身网卡,地址等设置之后,调用Cilium Agent的EndpointCreate方法完成eBPF/Identity相关数据路径以及安全策略的创建;
- 负责相关iptables的初始化和维护,因为在内核版本还不是足够高的情况下,还是需要iptables来完成一些工作,如在支持Network Policy的时候,使用到基于iptables的tproxy,以及基于Envoy实现的Network Policy时,需要的iptables chains等;
- 负责eBPF程序所需要的全局的Maps的初始化和维护以及 Pod 相关的Maps的创建和维护,因为有一些Maps是全局性的,所以需要启动的时候初始化和恢复,有一些是随着Pod的创建而创建的;
- 内置Hubble Server,提供Metrics和Trace的能力,并且提供API。同时Cilium Agent也内置实现了基于透明代理的DNS Network Policy能力的DNS Proxy Server。
Client (CLI):
用于和本地的Cilium Agent通信,提供操作Cilium的能力。虽然只和本地的Cilium Agent通信,但是可以拿到完整的Cilium网络数据。因为每一个Cilium Agent都会和控制平面通信。
Operator:
- 负责部分的IPAM的工作,主要是给主机节点分配CIDR,接下来给Pod分配ip地址由主机上的Cilium Agent来完成;
- 负责对存储Provider进行健康检查,现在支持Cilium的存储Provider有K8s CRD,还有外置的etcd,当发现存储设施不健康会触发Cilium Agent重启;
- 优化K8s的Endpoint的发现机制,在早期一点的版本,Cilium Agent要处理的Endpoint不是使用的EndpointSlice的方式,会导致数据量很大,增加Cilium Agent 的压力,现在基于Operator进行转换,让Cilium Agent只处理Operator转换出来的EndpointSlice,极大的减小了数据量,这样支持的集群的节点规模就可以增大。
CNI Plugin:
- 实现了CNI接口的组件,由Kubelet调用在Pod的网络命名空间中完成容器网络的管理,包括容器网卡的创建,网关的设置,路由的设置等。
- 因为依赖eBPF的网络能力,这里还会调用Cilium Agent的接口,完成Pod所需要的eBPF程序的编译,挂载,配置,以及和Pod相关的eBPF Maps的创建和管理。
Proxy
- 用于完成L7/Proxylib类型的Network Policy的合法检查,检查通过就会继续处理数据包,不通过就返回。实现的方式是使用 C++扩展Envoy实现的一整套filters,包括Listener Filter,Network Filter,Http Filter。可以支持K8s Network Policy,支持Kafka的Policy等都是在这里完成的。
- Cilium Agent会负责处理Proxy相关的控制流,包括启动一个定制化配置的Envoy。对于L3/L4层的Network Policy是在eBPF的程序中直接完成验证的。
DNS Proxy:
- 拦截和验证访问的DNS是不是可以访问,这里的DNS Proxy不是独立的组件,而是Cilium Agent内置实现的一个独立的Server,在这里单独提出来,只是为了强调能力的独立性。
- 主要的实现方式是基于tproxy的能力将请求转发到DNS Proxy Server,完成DNS请求的验证。
Hubble
Server:
在每个节点上运行,并从Cilium获取基于eBPF的可见性。它被嵌入到Cilium agent中,以实现高性能和低开销。它提供了一个gRPC服务来访问Prometheus指标。
Relay:
调用所有集群节点的Hubble Server的API接口,对观测数据进行汇总,然后由Hubble UI统一展示。
UI:
用于展示Hubble Server收集的观测数据,这里会直接连接到Relay去查询数据。
OTEL:
用于将Hubble Server的观测数据以OTLP的协议导出到OpenTelemetry框架中。由于OpenTelemetry有丰富的生态,可以很好地对Cilium的观测数据进行管理和分析。
eBPF
- eBPF是一种可以在操作系统内核中运行沙盒程序的技术。它可以安全有效地扩展内核的功能,而不需要更改内核源代码或加载内核模块。它用于许多Linux内核子系统,最突出的是网络,跟踪,安全,观测。
- 此外,LLVM的编译器后端允许用C编写程序并编译成eBPF指令。内核内验证器确保eBPF程序可以安全运行,JIT编译器将eBPF指令映射成处理器的原生指令,以提高本机执行效率。
- eBPF程序可以在内核中的各种hook点上运行,比如入站出站数据包、系统调用、kprobes、uprobes等。
- Cilium利用eBPF来执行核心数据路径过滤、变形、监控和重定向,Cilium能够探测Linux内核中可用的特性,并在检测到最新的特性时自动使用它们。需要Linux内核版本为4.8.0或更高。
更多eBPF的详细信息参考:
https://zhuanlan.zhihu.com/p/475638461
https://mp.weixin.qq.com/s?__biz=Mzg3ODUxNzM0MA==&mid=2247484375&idx=1&sn=375e71d3ac79790253fd8d4f1fae6319&scene=21#wechat_redirect
XDP
全称是eXpress Data Path。是数据包进入主机后,最早的一个支持eBPF的Hook点。可以在此阶段完成如过滤包、LB 等场景的能力。同时从运行的时机,又可以分为是硬件级的、网络驱动级的、内核级的,依次执行时机是硬件级的最早 (性能最好),网络驱动级的其次,内核级的是最晚。可以基于此实现防护DDOS的功能。