皮皮网

【本地搜索的源码】【舒尔特+源码】【手机抓屏+源码】flanneld 源码

2024-11-20 06:34:59 来源:牧童源码

1.K8s的Flannel网络
2.深入理解kubernetes(k8s)网络原理之五-flannel原理
3.《深入剖析Kubernetes》10. 跨主机容器网络-Flannel 与Calico解决方案
4.带你搞懂 Kubernetes Pod 如何获取 IP 地址
5.Kubernetes 如何为Pod分配地址
6.[知识讲解篇-166] 循序渐进理解CNI机制与Flannel工作原理

flanneld 源码

K8s的Flannel网络

       åŽŸæ–‡ï¼š 一文看懂k8s的Flannel网络 - 知乎 (zhihu.com)

        我们先来看图示例,下面则个是k8s的网络模型图。

        k8s的网络模型

        我们知道,在k8s里面最小的管理单元是pod,一个主机可以跑多个pod,一个pod里面可以跑多个容器。

        如上面所示,一个pod里面所有的容器共享一个网络命名空间(network namespace),所以,pod里面的容器之间通信,可以直接通过localhost来完成,pod里面的容器之间通过localhost+端口的方式来通信(这和应用程序在宿主机的通信方式是一样的)。

        那么pod和pod之间的通信呢?通常来说,我们给应用程序定死端口会给应用程序水平扩展带来很多不便,所以k8s不会使用定死端口这样的方法,而是采用其他方法来解决pod之间寻址的问题

        每个pod都会有一个自己的ip,可以将Pod像VM或物理主机一样对待。这样pod和pod之间的通信就不需要像容器一样,通过内外端口映射来通信了,这样就避免了端口冲突的问题。

        特殊的情况下(比如运维做网络检测或者程序调试),可以在pod所在的宿主机想向pod的ip+端口发起请求,这些请求会转发到pod的端口,但是pod本身它自己是不知道端口的存在的。

        因此,k8s的网络遵循以下原则:

        把上面这个pod替换成容器也是成立的,因为pod里面的容器和pod共享网络。

        基本上的原则就是,k8s的里面的pod可以自由的和集群里面的任何其他pod通信(即使他们是部署在不同的宿主机),而且pod直接的通信是直接使用pod自己的ip来通信,他们不知道宿主机的ip,所以,对于pod之间来说,宿主机的网络信息是透明的,好像不存在一样。

        然后,定了这几个原则之后,具体的实现k8s的这个网络模型有好多种实现,我们这里介绍的是 Flannel ,是其中最简单的一种实现。

        Flannel实现pod之间的通信,是通过一种覆盖网络(overlay network),把数据包封装在另外一个网络来做转发,这个覆盖网络可以给每一个pod分配一个独立的ip地址,使他们看起来都是一台具有独立ip的物理主机一样。

        下面这个就是k8s用覆盖网络来实现的一个例子:

        flannel覆盖网络

        可以看到有3个node,在多个node上建立一个覆盖网络,子网网段是..0.0/,源码然后,最终到容器级别,每个容器在这个网段里面获取到一个独立的ip。而宿主机所在的局域网络的网段是...0/

        看这两个网段,就知道,fannel给这个集群创建了一个更大的网络给pod使用,可以容纳的主机数量达到(2^)个。

        对于每个宿主机,fannel给每个了一个小一点的网络..x.0/,提供给每个这个宿主机的每一个pod使用,也就是说,每一个宿主机可以有(2^8)个pod。docker默认的网桥docker0用的就是这个网络,也就是所有的docker通过docker0来使用这个网络。即是说,对于容器来说,都是通过docker0这个桥来通信,和我们平常单机的容器是一样的(如果你不给创建的容器指定网络的话,默认用的是docker0,参考这篇 docker bridge 的文章)

        那么,对于同一个host里面的容器通信,我们上面说了是通过这个台宿主机的里面的docker0这个网桥来通信。那对于跨宿主机,也即是两个宿主机之间的容器是怎么通信的呢?fannel使用了宿主机操作系统的kernel route和UDP(这是其中一种实现)包封装来完成。下图演示了这个通信过程:

        fannel网络中跨宿主机的容器通信

        如图所示,..1.2(container-1) 要和..2.3(container-2)通信,两个容器分别处于不同的宿主机。

        假设有一个包是从..1.2发出去给..2.3,它会先经过docker0,因为docker0这个桥是所有容器的网关。 然后这个包会经过route table处理,转发出去到局域网...0/. 而这个route table的对应处理这类包的规则又是从哪里来的呢?它们是由fannel的一个守护程序flanneld创建的。

        每一台宿主机都会跑一个flannel的deamon的进程,这个进程的程序会往宿主机的route table里面写入特定的路由规则,这个规则大概是这样的。

        Node1的route table

        图例的数据包发出去的目标地址是..2.3,它属于网段..0.0/,这个目标地址命中第二条规则,也就是这个包会发到flannel0这个设备(dev),这 flannel0 是一个TUN设备。是在内核里面的一个 虚拟网络设备(虚拟网卡) 。

        在内核(kernel)里面,有两种虚拟网卡设备,分别是TUN和TAP,其中TAP处理的是第二层(数据链路层)的帧,而TUN处理的是第三层(网络层)的ip包。

        应用程序可以绑定到TUN和TAP设备,内核会把数据通过TUN或者TAP设备发送给这些程序,反过来,应用程序也可以通过TUN和TAP向内核写入数据,进而由内核的路由处理这些发出去的数据包。

        那么上面这个 flannel0 就是一个这样的TUN设备。这个设备连到的是一个flannel的守护进程程序 flanneld

        而这个 flanneld 是干嘛的呢?它可以接受所有发往 flannel0 这个设备的数据包,然后做数据封装处理,它的封装的逻辑也很简单,就是根据 目标地址 ,找到这个这地址对应的在整个flannel网络里面对应 物理ip和端口 (这里是Node2对应的物理ip),然后增加一个包头,增加的包头里面 目标地址 为这个 实际的物理ip和端口 (当然源地址也改成了局域网络的ip),将原来的数据包嵌入在新的数据包中,然后再把这个封装后的包扔回去给内核,内核根据目标地址去路由规则匹配规则,发现目标地址ip是...,端口是. 根据ip匹配不到任何特定的规则,就用第一条default(默认)的规则,通过eth0这个物理网卡,把数据包发给局域网(这里是UDP广播出去)

        当Node2的收到这个包后,然后根据 端口 发现他的目标地址原来是发给flanneld的,然后就直接交给flanneld这程序,flanneld收到包后,把包头去掉,发现原来目标地址是..2.3,然后就交换flannel0,flannel0把这个解开后的原包交给内核,内核发现它的目标地址是..2.3,应该交给docker0来处理。(图例里面画的是直接由flannel0交给docker0,没有图示出内核,实际上flannel0是一个TUN设备,是跑在内核的,数据经过它后可以交给内核,由内核根据路由决定进一步怎么forward)

        以上就是这个通信的过程,那么这里有一个问题: flanneld是怎么知道..2.3对应的目标地址是...:的呢?

        这是因为flanneld维护了一个映射关系,每创造一个虚拟的容器ip(分配给容器新ip的时候),它就知道这个容器的ip实际上是在哪台宿主机上,然后把这个映射关系存储起来,在k8s里面flanneld存储的这个映射关系放在etd上,这就是为什么flanneld为什么知道这个怎么去封装这些包了,下面就是etcd里面的数据的:

        看上面这个数据,etcd里面存储的..2.0-这个网段的容器是放在...这台宿主机上的。

        那么还有一个问题,端口又是怎么知道的?

        这个很简单,flanneld的默认监听的端口就是这个端口,flanneld启动的时候,就监听了UDP端口. 所以发给Node2:的所有UDP数据包,flanneld这个进程会直接处理,然后去掉包头就还原出来原来的包了,还原后交给TUN设备flannel0,由flannel0交给内核,内核根据Node2的路由规则交给docker0(Node2的路由规则和node1是基本上一样的,除了第三位的网段标识不一样,一个是..1一个是..2):

        看Node2的这个规则,flannld去掉包头解出来的原包的目标ip是..2.3,由flannel0交回去给kennel,kennel发现命中第三条规则,所以会把这个包叫给docker0,继而就进入了docker0这个桥的子网了,接下去就是docker的事情了, 参考以前写的文章 。

        最后一个问题,怎么配置docker去使用..x.0/这个子网呢,如果是手工创建容器的话,这个也是非常简单的, 参考以前写的关于docker bridge的这篇文章 ,但是在k8s里面,是通过配置来实现的:

        flanneld会把子网信息写到一个配置文件 /run/flannel/subnet.env 里

        docker会使用这个配置的环境变了来作为它的bridge的配置

深入理解kubernetes(k8s)网络原理之五-flannel原理

       flannel在Kubernetes(k8s)网络架构中扮演着关键角色,其提供多种网络模式,源码其中最为广泛应用的源码是VXLAN模式。本文旨在深入探讨VXLAN模式下flannel的源码运作原理,同时对UDP模式进行简要介绍。源码

       VXLAN模式下的源码本地搜索的源码flannel依赖于VXLAN协议,实现跨主机Pod间的源码通信。这种模式下,源码flannel的源码组件工作流程涉及多个关键步骤。首先,源码flannel-cni文件作为CNI规范下的源码二进制文件,负责生成配置文件并调用其它CNI插件(如bridge和host-local),源码从而实现主机到主机的源码网络互通。flannel-cni文件并非flannel项目源码,源码而是源码位于CNI的plugins中。

       在flannel-cni工作流程中,kubelet在创建Pod时,会启动一个pause容器,并获取网络命名空间。随后,它调用配置文件指定的CNI插件(即flannel),以加载相关参数。flannel读取从/subnet.env文件获取的节点子网信息,生成符合CNI标准的配置文件。接着,flannel利用此配置文件调用bridge插件,完成Pod到主机、同主机Pod间的数据通信。

       kube-flannel作为Kubernetes的daemonset运行,主要负责跨节点Pod通信的编织工作。它完成的舒尔特+源码主要任务包括为每个节点创建VXLAN设备,并更新主机路由。当节点添加或移除时,kube-flannel会相应地调整网络配置。在VXLAN模式下,每个节点上的kube-flannel会与flanneld守护进程进行通信,以同步路由信息。

       在UDP模式下,每个节点运行flanneld守护进程,参与数据包转发。flanneld通过Unix域套接字与本地flanneld通信,而非通过fdb表和邻居表同步路由信息。当节点新增时,kube-flannel会在节点间建立路由条目,并调整网络配置以确保通信的连续性。

       flannel在0.9.0版本前,使用不同策略处理VXLAN封包过程中可能缺少的ARP记录和fdb记录。从0.9.0版本开始,flannel不再监听netlink消息,优化了内核态与用户态的交互,从而提升性能。

       通过理解flannel的运行机制,可以发现它在VXLAN模式下实现了高效的跨节点Pod通信。flannel挂载情况不影响现有Pod的通信,但新节点或新Pod的加入需flannel参与网络配置。本文最后提示读者,了解flannel原理后,可尝试自行开发CNI插件。

《深入剖析Kubernetes》. 跨主机容器网络-Flannel 与Calico解决方案

       跨主机容器通信的关键在于创建集群级别的网络连接,以实现容器间的直接通信。在 Docker 默认配置下,手机抓屏+源码不同宿主机的 docker0 网桥是孤立的,为此,Overlay Network技术应运而生。它通过软件创建一个集群共享的网桥,使所有容器都能连接并通信。

       四种主要的Overlay解决方案包括Flannel和Calico,下面逐一介绍:

       Flannel网络解决方案

       Flannel通过UDP模式实现,每个宿主机的flanneld客户端监听 UDP报文,作为容器通信的载体。它在宿主机间建立隧道,使用三层的TUN设备flannel0进行IP包转发,前提是docker0网桥的地址范围需包含Flannel分配的子网。

       VXLAN模式

       VXLAN则是在三层网络上添加一层虚拟二层网络,通过VTEP设备作为隧道端点,提供高性能的二层通信。VNI(VXLAN网络标识符)是区分数据帧的关键标识,宿主机上的VTEP设备名称通常包含VNI值。

       Host-gw模式

       Host-gw模式是纯三层解决方案,通过配置宿主机路由表实现,无需额外的封装和解封装,性能损失相对较低,但要求宿主机之间有二层连通性。

       Calico网络解决方案(IPIP模式)

       Calico的IPIP模式更轻量级,它通过IPinIP隧道将容器间的通信伪装成宿主机间的通信,通过Linux的tunl0隧道接口进行封装和解封装,实现容器之间的直接通信。

       以上这些解决方案都是为了克服单机容器通信的局限性,提供分布式集群中的高效通信。

带你搞懂 Kubernetes Pod 如何获取 IP 地址

       Kubernetes 的核心网络要求每个 Pod 都拥有独立的 IP 地址,以支持通信。itchat+源码分析本文将解释网络组件如何协作,以及在 Flannel 作为网络提供商和 Containered 作为 container runtime 的场景下,Pod 如何获取 IP 地址。

       首先,了解背景:Kubernetes 提供多种网络设置,其中 Flannel 通过 vxlan 在节点间封装数据包,而 CNI 插件(如Flannel CNI)负责配置 Pod 网络。在每个节点,Flanneld 与apiserver通信获取网络元数据,Flannel CNI 则与Bridge CNI 交互,为Pod配置 veth pair,连接到 Linux Bridge。

       对于同一主机上的容器,通过 Linux Bridge 和 veth pair 实现通信。对于不同主机上的容器,Flannel 使用 vxlan 将数据包封装并发送到目标节点,然后在目标节点解封装并路由到相应 Pod。

       节点 IPAM 控制器分配 podCIDR,确保每个 Pod 有唯一的 IP。kubelet 调用 CRI 插件,如containerd,后者再调用 CNI 插件来配置 Pod 的网络。CNI 插件交互包括调用 Bridge CNI 设置 veth pair,并使用主机本地 IPAM 插件为Pod分配 IP 地址。

       总结来说,Kubernetes 的网络配置涉及节点分配的 podCIDR,CNI 插件的交互,以及如何在container runtime 和网络提供商之间协调,共同确保每个 Pod 都能获得其专属的 IP 地址,以便进行有效通信。框分类信息+源码

Kubernetes 如何为Pod分配地址

       Kubernetes为每个Pod分配IP地址的核心网络要求,由网络提供者如flannel、calico、canal等实现。

       在开始使用Kubernetes时,不清楚如何为Pod分配IP地址。了解组件独立工作,但不清楚组件组合方式。例如,了解CNI插件,但不清楚其调用机制。因此,撰写本文分享对网络组件的理解,如何将它们集成到Kubernetes集群中,使每个Pod获得IP地址。Kubernetes有多种网络设置方法和容器运行时选项。本文使用Flannel作为网络提供者,Containerd作为容器运行时。假设熟悉容器网络原理,并在上下文中简要介绍。

       容器网络概述涉及Linux网桥网络和数据包封装。同一主机上的容器通过Linux桥相互通信,使用veth设备连接容器网络命名空间与主机网络上的Linux桥。不同主机上的容器通过数据包封装相互通信,Flannel通过VXLAN支持此功能,封装数据包在UDP数据包中传输。Kubernetes集群中,Flannel在每个节点上创建VXLAN设备和路由表条目,封装数据包后通过VXLAN设备传输,在目标位置检索并路由至目的地Pod。

       容器运行时接口(CRI)允许kubelet使用不同容器运行时,各种运行时实现CRI API,支持在Kubernetes安装中使用首选运行时。容器网络接口(CNI)项目提供通用插件联网解决方案规范,包含各种插件执行网络配置功能。CNI插件遵循规范,是可执行文件,本文将讨论一些插件。

       为每个节点分配Pod IP地址的子网确保集群中所有Pod具有唯一IP地址。使用Node IPAM控制器分配专用子网,确保不相交子网允许为每个Pod分配唯一IP地址。当Kubernetes节点首次向集群注册时,分配专用子网。更改节点分配的Pod子网需要先注销节点,使用Kubernetes控制平面的配置更改重新注册节点。列出节点Pod子网的命令。

       在节点上调度Pod时,启动Pod引发网络配置和应用程序容器启动。容器运行时与CNI插件交互,为Pod配置网络。使用Containerd作为运行时,Containered CRI插件调用CNI插件。网络提供商CNI插件配置并调用基本CNI插件。Flannel作为网络提供者时,Flanneld守护程序配置pod网络。Flanneld初始化容器install-cni在每个节点创建CNI配置文件,并将podCIDR和其他网络元数据存储在文件中。创建Pod时,Flanneld配置路由允许Pod通过IP地址相互连接。

       Containered CRI插件调用CNI插件配置网络,CNI插件间交互如下。Flannel CNI插件与Flanneld结合,从apiserver获取podCIDR等信息。Bridge CNI插件创建Linux桥,为每个Pod创建veth对,主机上所有容器连接至Linux桥。配置完成后,Bridge插件调用主机本地IPAM插件,配置并存储分配给容器的IP地址。

       总结,Kube-controller-manager为每个节点分配podCIDR,为节点上的Pod分配唯一IP地址。Kubernetes集群管理员配置、安装kubelet、容器运行时、网络提供商代理,并在每个节点分发CNI插件。网络提供商代理启动生成CNI配置,节点上调度Pod后,kubelet调用CRI插件创建Pod。如果是Containerd,则调用CNI插件配置Pod网络,确保Pod获得IP地址。

[知识讲解篇-] 循序渐进理解CNI机制与Flannel工作原理

       CNI(Container Network Interface)是kubernetes网络集成的解决方案,专注于容器网络连接和容器销毁时的资源释放,支持多种网络模式,易于实现。常见的CNI实现有Flannel、Calico、Weave等。CNI插件有三种实现模式:UDP、VxLAN、host-gw。

       Flannel采用Overlay网络模式,将TCP数据包装在另一种网络包中进行路由转发和通信。它会在每一个宿主机上运行名为flanneld的代理,为宿主机预先分配一个子网,并为Pod分配IP地址。数据包通过VXLAN、UDP或host-gw后端机制进行转发。不同宿主机下的Pod属于不同的子网,通过Etcd存储网络配置、子网和主机公共IP信息。

       Flannel支持三种实现:UDP、VxLAN、host-gw。host-gw模式性能最高,但要求节点处于同一网段。VxLAN模式使用内核VxLAN模块维护二层网络,构建Overlay网络,源VTEP设备通过二层数据帧进行通信,将原始IP包封装并发送给目的VTEP设备。在Linux内核中,网络设备进行转发的依据来自FDB转发数据库。UDP模式下,数据包从容器经过docker0出现在宿主机,根据路由表进入flannel0设备后,宿主机上的flanneld进程收到IP包。flanneld根据目的IP地址匹配到对应的子网,从Etcd中找到宿主机的IP地址。然后将UDP封装的IP包发送给Node2。

       VxLAN模式下,flannel.1设备作为VTEP,封装原始IP包,并通过二层数据帧发送给目的VTEP设备。封装过程只是在原始IP包前面加上一个VxLAN头,包含VNI标识。Linux内核会对数据桢进行拆包,根据VNI值交给flanneld处理。最终数据包通过宿主机网络传输到目的Node。

       在host-gw模式下,每个Flannel子网的下一跳设置为对应宿主机的IP地址,宿主机充当容器通信路径的网关。数据包封装成三层IP包,使用路由表的下一跳设置MAC地址,通过二层网络传输到目的宿主机。如果两个Pod所在节点在同一网段,可以配置VxLAN支持host-gw功能,直接通过物理网卡的网关路由转发,提高VxLAN性能。

0-overlay和underlay,这两种容器网络你分得清吗

       本文主要探讨了容器网络中的两种模式:0-overlay和underlay。在理解云容器网络时,它们的区别至关重要。首先,让我们来看underlay网络,它指的是容器运行在底层虚拟机或物理机的网络环境中,这个环境可以直接识别和转发容器的IP地址。具体来说,有两种实现方式:一是通过将每个节点的容器子网注入到VPC的路由表中,使内部ECS和容器可以直接访问容器IP;二是直接从VPC分配IP给容器,提供直接的网络连接。

       相比之下,overlay网络则更为复杂。在这种模式下,底层网络环境本身无法识别或转发容器IP,需要通过每个节点上的封装和解封装过程来处理网络流量。例如,Flannel的vxlan模式和Calico的ipip模式,通过隧道封装技术,仅要求kubernetes管理的节点间三层网络可达。以Flannel的vxlan为例,客户端容器的请求会被物理机上的flanneld进程封装成vxlan报文,然后通过三层网络发送到对端,服务端收到后由flanneld解封装并传递给容器。

       关键的区别在于,overlay网络虽然灵活性高,但因为涉及到封装和解封装,可能导致性能损耗。相比之下,云厂商倾向于发展underlay网络,以实现更低延迟的直通能力,如ELB直接连接容器或者容器直接绑定EIP,以提高网络效率。