Cilium架构 (Cilium 2)
Cilium架构
译自:http://docs.cilium.io/en/stable/architecture/
本文档描述了Cilium的架构。它通过记录BPF数据路径(datapath)的钩子来实现Cilium数据路径,那么Cilium数据路径是如何与容器编排层继承,以及如何在各层(如BPF数据路径和Cilium代理)之间更新对象的?
数据路径
Linux内核在网络栈中支持一个BPF钩子集,使用这些勾子可以允许BPF程序(即使用回调函数运行)。Cilium数据路径使用这些钩子加载BPF程序,当一起使用时,这些程序会创建更高级别的网络结构。
下面是Cilium使用的钩子列表以及简要概述。更详细的介绍可以参见BPF and XDP Reference Guide
XDP:XDP BPF钩子最早可以在网络驱动中使用,在报文接收时触发BPF程序。由于BPF程序能够(在进行其他处理前)直接作用于报文数据,因此能够获取最好的报文处理性能。该钩子可用于过滤程序丢弃恶意的或非期望的流量,以及其他常见的DDOS防护机制。
Ingress/Egress流控:与XDP相同,附加到tc(traffic control) ingress钩子的BPF程序会附加到网络接口上,但是在网络栈完成初始的报文处理之后运行。该钩子在协议栈的L3层之前运行,但可以访问与报文相关的大多数元数据,适用于本地节点的处理,如配置L3/L4 endpoint策略以及限制达到endpoints的流量。对于面向设备的网络,tc ingress钩子可以与上面的XDP钩子耦合。完成该操作后,可以合理地假设此时的大多数流量是合法的,并且目的地是主机。
容器通常会使用一个虚拟设备,称为veth对,可以看作是连接容器和主机的虚拟线路。通过连接到这对veth的主机侧的TC ingress钩子,Cilium可以监控和对一个容器中存在的所有流量强制执行制订的策略(在主机侧监控和限制本机的容器的流量)。通过将一个BPF程序附加到与每个容器关联的veth对上,然后使用另外一个附加到tc ingress钩子上的BPF程序将所有网络流量路由到主机侧的虚拟设备上,这样Cilium也可以监控和对到达本节点或节点中存在的流量强制执行制订的策略(在容器侧监控和限制本机的流量)。
根据场景的需要,容器也可能使用ipvlan设备进行连接。这种模式下,主机的物理设备作为ipvlan的master,容器中的虚拟ipvlan设备被设置为slave模式。使用ipvlan而不是veth对的好处是可以减少网络栈将报文推送到位于另一个网络命名空间中的ipvlan slave所需要的资源,因此可以获得更好的延迟结果。为了使用Cilium配置L3/L4 endpoint策略,需要将用于tc的BPF程序附加到容器网络命名空间中的ipvlan slave设备的tc egress钩子上。例如,与在ipvlan master的tc ingress钩子上运行的另一个BPF程序相结合,这样也可以限制节点上的传入流量。
socket操作:socket操作钩子附加到一个特定的cgroup上,根据TCP时间运行。Cilium将BPF socket操作程序附加到根cgroup上,并使用该程序监控TCP状态变更,特别是对ESTABLISHED 状态变更。当一个socket转换为ESTABLISHED 状态,如果TCP socket的对端位于本地节点上(可能是本地代理),则会附加socket 发送/接受程序。
socket 发送/接收:当一个TCP socket执行发送操作时会运行socket 发送/接受钩子。此时,钩子或检查消息,最终会丢弃该消息,会将该消息发送到TCP层,会直接将该消息重定向到另外一个socket。如下所述,Cilium使用它来加速数据路径的重定向。
将上述钩子与虚拟接口(cilium_host, cilium_net),可选的overlay接口(cilium_vxlan),Linux内核加密支持以及用户空间代理(Envoy)相结合,Cilium可以创建如下网络对象。
预过滤(prefilter):预过滤对象会运行一个XDP程序,并提供一组预过滤规则来过滤网络上的流量来达到更好的性能。特别使用一组Cilium agent提供的CIDR映射来查找报文,如在目的地不是一个有效的endpoint时丢弃报文,或允许网络栈处理该报文。可以很容易通过扩展来构建一个新的预过滤标准/能力。
endpoint策略:endpoint策略对象实现了Cilium endpoint的执行方式。它使用一个映射来查找与身份相关的报文,且该层(layer)可以很好地扩展到多个endpoint。取决于本层的策略,可能会丢弃报文,转发到本地的endpoint或服务对象,或转发到L7策略对象,用于后续L7规则。它是Cilium数据路径中负责报文和身份映射以及执行L3和L4策略的主要对象。
服务(service):服务对象会根据该对象接收到的每个报文的目的IP(可能包含目的端口)来进行映射查找。如果找到一个匹配的表项,则将该报文转发到一个配置到的L3/L4 endpoint上。服务块可以使用TC ingress钩子在任何接口上实现一个独立的负载均衡,或集成到endpoint策略对象中。
L3加密:在ingress上,可以使用L3加密对象标识需要解密的报文,然后将报文传递到Linux xfrm(转换)层进行解密,在解密报文后,该对象会接受报文,然后将报文传递到网络栈,后续给其他对象进行处理。根据网络的模式(直接路由或overlay),可能是BPF尾部调用或将数据包传递到下一个对象的Linux路由栈。解密需要的密钥编码在IPsec首部,这样我们不需要在ingress上使用映射查找来定位解密密钥。
在egress上,会首先对目的地址执行映射查找来缺点该报文是否被加密,如果被加密,则找出目的节点上可用的密钥。在选出的节点上挑选最近使用的可用的密钥,并将报文标记为加密。然后改报文会传递到Linux xfrm层执行加密。当接收到现在加密的报文时,它被传递到下一层,或通过发送到Linux 栈进行路由,或(如果正在使用overlay)直接执行尾部调用。
socket层强制(Enforcement):socket层强制会使用两个钩子,socket 操作钩子和socket 发送/接收钩子来监控并附加到所有与Cilium管理的endpoint相关的TCP socket,包括L7代理。socket操作钩子会识别要加速的候选套接字,这些候选套接字包括所有的本地节点连接(endpoint到endpoint)以及所有到Cilium代理的连接。这些标识的连接将会包含所有由socket 发送/接收钩子处理的消息,并且使用sockmap快速重定向进行加速。快速重定向保证Cilium中实现的所有策略对于关联的socket/endpoint映射均有效,并假设它们会直接向对端socket发送消息。sockmap send/recv钩子确保消息不会被上面提到的任何对象处理。
L7策略:L7策略对象将代理的流量重定向到一个Cilium用户空间代理实例中。Cilium使用一个Envoy作为它的用户空间代理。Envoy要么转发流量,要么会根据配置的L7策略生成拒绝消息。
Cilium通过连接这些组件实现了灵活高效的数据路径。下面将展示连接单个节点上的endpoint可能存在的数据流(进入一个endpoint以及endpoint到网络设备)。在每种情况下,都会通过一个额外的图显示启用socket层强制时的可用的TCP加速路径。
Endpoint到Endpoint
首先展示的是本地endpoint到endpoint的数据流,在engress和ingress上使用了L7策略。紧跟着展示了启用socket层强制下相同endpoint到endpoint的数据流走向。通过对TCP流量启用socket层强制,发起连接的握手将遍历endpoint策略对象,直到TCP的状态变为ESTABLISHED。最后只有L7策略对象允许之后,连接状态才能变为ESTABLISHED。
从Endpoint出站(Egress from Endpoint)
下面展示了本地endpoint使用overlay网络进行出站的场景。overlay网络流量通过与overlay对应的Linux网络接口进行转发。默认的overlay接口称为cilium_vxlan。与上面类似,通过启用socket层强制并使用L7代理可以避免在TCP通信的endpoint和L7策略之间运行endpoint策略块。L3加密块可以在启用时加密报文。
入站到Endpoint(Ingress to Endpoin)
最后展示了使用overlay网络时入站到endpoint的场景。与上面类似,通过启用socket层强制可以避免在代理和endpoint socket之间遍历策略集。如果接收到的报文被加密,则首先需要进行解密,并使用正常流程处理。
基于veth的数据路径和基于ipvlan的数据路径的对比
|基于ipvlan的数据路径目前仅在技术预览中,用于实验目的。该限制会在后续的Cilium发布中移除。
默认的Cilium CNI运行在基于veth的数据路径模式下,由于所有的BPF程序都由Cilium在主机网络命名空间之外进行管理,因此使用该模式可以获得更大的灵活性,这样容器就可以被授予其命名空间(如CAP_NET_ADMIN)的特权,而不会影响安全性(因为容器无法访问主机中的BPF强制点)。鉴于BPF程序是从主机的网络名称空间附加的,BPF也能够接管并有效地管理本地容器到主机之间的转发逻辑。但由于veth模式下,网络栈内部在处理从一个veth设备到位于另一个网络命名空间中的对端设备时需要重新遍历网络栈,因此会造成延迟。当在本地Cilium endpoint间进行通信时,这种出站到入站的转变需要执行两次,对于正在到达或从主机发送出去的数据包,则为一次。
对于更具延迟优化的数据路径,Cilium CNI还支持ipvlan L3/L3S模式,但存在大量限制。为了支持老的且不存在ipvlan发夹模式的内核,Cilium会在tc egress层将BPF程序附加到位于容器的网络命名空间内的slave设备上,意味着这种数据路径模式只能用于使用非CAP_NET_ADMIN 和CAP_NET_RAW特权运行的容器。ipvlan使用内部转发逻辑直接进行slave-to-slave或slave-to-master的重定向,因此BPF程序本身不会执行到设备的转发。由于网络栈不需要像基于veth的数据路径一样在处理外部报文时重新遍历,因此能够更有效地切换命名空间。主机到容器网络命名空间的切换直接发生在L3层,在后续的ingress处理中无需排队和重新调度。在本地endpoint之间通信的情况下,会执行一次egress-to-ingress的且华北,而不必执行两次。
目前的实现中,Cilium的ipvlan模式还有很多限制需要在接下来的工作中解决:目前还无法启用NAT64以及通过代理启用L7策略强制。当前未启用到本地endpoint的服务负载平衡以及容器到主机的本地通信。如果需要使用这些功能,仅以使用基于veth的数据路径模式。
Cilium的CNI ipvlan模式运行在Cilium daemon中,例如--datapath-mode=ipvlan --ipvlan-master-device=bond0
,后者通常指定了物理网络设备,同时也作为ipvlan的master设备。注意在ipvlan 数据路径模式在kubernetes中部署在L3S模式下。确保有一个稳定运行内核,包括以下ipvlan修复:d5256083f62e。
更多BPF的特性参见 BPF and XDP Reference Guide,可以在 Envoy 章节了解如何扩展L7策略。
BPF 映射的限制
所有创建的BPF映射都有上限限制。超出限制的插入将会失败,从而限制了数据路径的可伸缩性。下表展示了映射的默认值。每个限制都可以在源代码中进行修改,如果需要,可以根据请求添加配置选项。
Map Name | Scope | Default Limit | Scale Implications |
---|---|---|---|
Connection Tracking | node or endpoint | 1M TCP/256K UDP | Max 1M concurrent TCP connections, max 256K expected UDP answers |
Endpoints | node | 64k | Max 64k local endpoints + host IPs per node |
IP cache | node | 512K | Max 256K endpoints (IPv4+IPv6), max 512k endpoints (IPv4 or IPv6) across all clusters |
Load Balancer | node | 64k | Max 64k cumulative backends across all services across all clusters |
Policy | endpoint | 16k | Max 16k allowed identity + port + protocol pairs for specific endpoint |
Proxy Map | node | 512k | Max 512k concurrent redirected TCP connections to proxy |
Tunnel | node | 64k | Max 32k nodes (IPv4+IPv6) or 64k nodes (IPv4 or IPv6) across all clusters |
kubernetes集成
下图显示了kube-proxy安装的iptables规则和Cilium安装的iptables规则的集成。