1、什么是 CNI ?
CNI 是容器网络接口 (Container Network Interface)的缩写。定义了容器运行时如何与网络插件进行交互,从而管理容器网络。只要开发者遵循 CNI 定义的规范就可以接入 kubernetes ,为 Pod 创建虚拟网卡、分配 IP 地址、设置路由规则等,这样就实现 "IP-Per-Pod" 网络模型。
CNI 为网络插件定义了一些以系列通用接口,可以使容器运行时与多种不同的网络插件(Flannel、Calico、Cilium等网络插件)进行交互,不同网络插件可以提供不同的网络策略。
2、Flannel 工作原理
Flannel 是一个用于容器网络的 CNI 插件,它的主要功能是为容器提供一个可以互相通信的网络。
那么,Flannel 是通过什么技术来实现容器之间的通信呢?
目前,Flannel 支持三种网络后端 VXLAN、UDP、Host-GW ,基于这些后端技术来实现容器之间的通信的。
2.1、Flannel 的 UDP 模式
UDP 模式,是 Flannel 最早支持的解决容器通信模式,由于性能非常差,所以,现在基本被弃用。
例子:假设有两台宿主机
- Node 1 container-1,IP 地址是 100.96.1.2,对应的 docker0 网桥的地址是:100.96.1.1/24;
- Node 2 container-2,IP 地址是 100.96.2.3,对应的 docker0 网桥的地址是:100.96.2.1/24;
容器 A 要访问 容器 B,由于是跨主机不在一个网断里,那么目的地址 100.96.2.3 并不在 Node 1 的 docker0 网桥的网段里,此时会根据路由规则通过容器的网关进入 docker0 网桥,在匹配到 flannel0 设备中,然后 flanneld 看到了这个 IP 包的目的地址,是 100.96.2.3,就把它发送给了 Node 2 宿主机。
flannel0 设备它是一个 TUN 设备,TUN 设备是一种工作在三层(Network Layer)的虚拟网络设备。负责,在操作系统内核和用户应用程序之间传递 IP 包
flanneld 又是如何知道这个 IP 地址对应的容器,是运行在 Node 2 上的呢?通过子网(Subnet),一台宿主机上的所有容器,都属于该宿主机被分配的一个"子网"。
总结:
Flannel UDP 模式提供的其实是一个三层的 Overlay 网络,即:它首先对发出端的 IP 包进行 UDP 封装,然后在接收端进行解封装拿到原始的 IP 包,进而把这个 IP 包转发给目标容器。
缺点:
仅在发出 IP 包的过程中,就需要经过三次用户态与内核态之间的数据拷贝
- 第一次,用户态的容器进程发出的 IP 包经过 docker0 网桥进入内核态;
- 第二次,IP 包根据路由表进入 TUN(flannel0)设备,从而回到用户态的 flanneld 进程;
- 第三次,flanneld 进行 UDP 封包之后重新进入内核态,将 UDP 包通过宿主机的 eth0 发出去。
2.2、Flannel 的 VXLAN 模式
VXLAN 的覆盖网络的设计思想是:在现有的三层网络之上,"覆盖"一层虚拟的、由内核 VXLAN 模块负责维护的二层网络,使得连接在这个 VXLAN 二层网络上的"主机"(虚拟机或者容器都可以)之间,可以像在同一个局域网(LAN)里那样自由通信。当然,实际上,这些"主机"可能分布在不同的宿主机上,甚至是分布在不同的物理机房里。
而 VTEP 设备的作用,其实跟前面的 flanneld 进程非常相似。只不过,它进行封装和解封装的对象,是二层数据帧(Ethernet frame);而且这个工作的执行流程,全部是在内核里完成的(因为 VXLAN 本身就是 Linux 内核中的一个模块)。
2.3、host-gw 模式
工作原理非常简单:
假设现在,Node 1 上的 Infra-container-1,要访问 Node 2 上的 Infra-container-2。当你设置 Flannel 使用 host-gw 模式之后,flanneld 会在宿主机上创建这样一条规则,以 Node 1 为例:
bash
$ ip route
...
10.244.1.0/24 via 10.168.0.3 dev eth0
这条路由规则的含义是:
- 目的 IP 地址属于 10.244.1.0/24 网段的 IP 包,应该经过本机的 eth0 设备发出去(即:dev eth0);
- 并且,它下一跳地址(next-hop)是 10.168.0.3(即:via 10.168.0.3)
这样,这个数据帧就会从 Node 1 通过宿主机的二层网络顺利到达 Node 2 上。
当然,Flannel 子网和主机的信息,都是保存在 Etcd 当中的。flanneld 只需要 WACTH 这些数据的变化,然后实时更新路由表即可。
3、Calico
不过,不同于 Flannel 通过 Etcd 和宿主机上的 flanneld 来维护路由信息的做法,Calico 项目使用了一个"BGP"来自动地在整个集群中分发路由信息。
BGP 的全称是 Border Gateway Protocol,即:边界网关协议。它是一个 Linux 内核原生就支持的、专门用在大规模数据中心里维护不同的"自治系统"之间路由信息的、无中心的路由协议。
4、cilium 工作原理
4.1 概述
Cilium 是 kubernetes 的 CNI 网络解决方案,Cilium 在设计和实现上,基于Linux的一种新的内核技术 eBPF,可以在Linux内部动态插入强大的安全性、可观测性和网络控制逻辑,及安全策略。可以在不修改应用程序代码或容器配置的情况下进行应用和更新。
3.2 架构
参考 Cilium 官方的架构,Cilium 位于容器编排系统 和 Linux Kernel之间,向上可以通过编排平台为容器进行网络以及相应的安全配置,向下可以通过在Linux内核挂载eBPF程序,来控制容器网络的转发行为以及安全策略执行。
bash
kubectl exec -it test-1-7cd5798f46-vzf9s -n test-1 bash
root@u18-161:~# kubectl exec -it test-1-7cd5798f46-vzf9s -n test-1 bash
root@test-1-7cd5798f46-vzf9s:/# route -n
Kernel IP routing tableDestination Gateway Genmask Flags Metric Ref Use Iface0.0.0.0 10.244.0.26 0.0.0.0 UG 0 0 0 eth0
10.244.0.26 0.0.0.0 255.255.255.255 UH 0 0 0 eth0
root@test-1-7cd5798f46-vzf9s:/# arp
root@test-1-7cd5798f46-vzf9s:/#
Flannel 的工作原理如下:
-
每个节点上的 Flannel 会为主机分配一个唯一的子网,这个子网可以由用户自定义或者由 Flannel 自动生成。
-
当容器启动时,容器运行时会调用 CNI 插件,通过 CNI 接口请求 Flannel 为容器分配一个 IP 地址。
-
Flannel 会根据容器所在的节点以及容器所在节点的子网信息,为容器分配一个唯一的 IP 地址,并将这个 IP 地址返回给容器运行时。
-
容器运行时会将这个 IP 地址配置到容器的网络接口上,从而使容器可以与其他容器或者主机进行通信。
-
当容器需要访问其他节点上的容器时,Flannel 会使用虚拟网络设备 TUN/TAP 将数据包封装,然后通过底层网络(如 VXLAN、UDP)传输到目标节点上的 Flannel,再解封装数据包将其交给目标容器。
Calico 是一个开源的容器网络解决方案,它使用 BGP 协议来实现容器之间的通信。其工作原理如下:
-
每个节点上的 Calico Agent 会为主机分配一个唯一的 IP 地址,并将这个 IP 地址作为节点的标识符。
-
当容器启动时,容器运行时会调用 CNI 插件,通过 CNI 接口请求 Calico 为容器分配一个 IP 地址。
-
Calico 会为容器分配一个唯一的 IP 地址,并将这个 IP 地址配置到容器的网络接口上。
-
当容器需要与其他容器通信时,容器会将数据包发送到目标 IP 地址,如果目标 IP 地址与本地节点的 IP 地址属于同一个子网,则数据包会直接发送到目标容器;如果目标 IP 地址与本地节点的 IP 地址不属于同一个子网,则数据包会被封装成 BGP 路由,并通过 BGP 协议传输到目标节点上。
-
目标节点上的 Calico Agent 接收到数据包后,会解封装数据包,并将数据包交给目标容器。
Cilium 是一个开源的容器网络解决方案,它使用 Linux 内核中的 eBPF(Extended Berkeley Packet Filter)技术来实现容器之间的通信。其工作原理如下:
-
Cilium Agent 在每个节点上运行,并通过 Linux 内核中的 eBPF 技术来监控所有容器之间的网络通信。
-
当容器启动时,容器运行时会调用 CNI 插件,通过 CNI 接口请求 Cilium 为容器分配一个 IP 地址。
-
Cilium 会为容器分配一个唯一的 IP 地址,并将这个 IP 地址配置到容器的网络接口上。
-
当容器之间需要通信时,Cilium Agent 会根据容器的标签信息和网络策略来判断是否允许通信,并使用 eBPF 技术来实现容器之间的通信。
-
Cilium 还支持通过集成 Istio 来实现服务网格,从而可以对服务之间的通信进行更细粒度的控制和管理。
总之,Cilium 的主要作用是为容器提供一个可以互相通信的网络,并且它的实现方式是使用 Linux 内核中的 eBPF 技术来实现容器之间的通信。这种方式可以使得容器网络的性能更高,同时还支持更细粒度的网络策略和服务网格功能。
参考:
5、总结
Kubernetes通过一个叫做CNI的接口,维护了一个单独的网桥来代替docker0。这个网桥的名字就叫作:CNI网桥,它在宿主机上的设备名称默认是:cni0。
容器"跨主通信"的三种主流实现方法:UDP、host-gw、VXLAN。 之前介绍了UDP和VXLAN,它们都属于隧道模式,需要封装和解封装。接下来介绍一种纯三层网络方案,host-gw模式和Calico项目
Host-gw模式通过在宿主机上添加一个路由规则:
<目的容器IP地址段> via <网关的IP地址> dev eth0
IP包在封装成帧发出去的时候,会使用路由表里的"下一跳"来设置目的MAC地址。这样,它就会通过二层网络到达目的宿主机。
这个三层网络方案得以正常工作的核心,是为每个容器的IP地址,找到它所对应的,"下一跳"的网关。所以说,Flannel host-gw模式必须要求集群宿主机之间是二层连通的,如果宿主机分布在了不同的VLAN里(三层连通),由于需要经过的中间的路由器不一定有相关的路由配置(出于安全考虑,公有云环境下,宿主机之间的网关,肯定不会允许用户进行干预和设置),部分节点就无法找到容器IP的"下一条"网关了,host-gw就无法工作了。
Calico
Calico项目提供的网络解决方案,与Flannel的host-gw模式几乎一样,也会在宿主机上添加一个路由规则: <目的容器IP地址段> via <网关的IP地址> dev eth0
其中,网关的IP地址,正是目的容器所在宿主机的IP地址,而正如前面所述,这个三层网络方案得以正常工作的核心,是为每个容器的IP地址,找到它所对应的,"下一跳"的网关。区别是如何维护路由信息:
Host-gw : Flannel通过Etcd和宿主机上的flanneld来维护路由信息 Calico: 通过BGP(边界网关协议)来实现路由自治,所谓BGP,就是在大规模网络中实现节点路由信息共享的一种协议。
隧道技术(需要封装包和解包,因为需要伪装成宿主机的IP包,需要三层链通):Flannel UDP / VXLAN / Calico IPIP 三层网络(不需要封包和解封包,需要二层链通):Flannel host-gw / Calico 普通模式