1.Linux网络基础知识1.1名词解释网络命名空间(NetworkNamespace):Linux在网络栈中引入了一个网络命名空间,用来隔离独立的网络协议栈,在不同的命令空间中,它们之间不能相互通信;docker就是利用这个特性来实现容器之间的网络隔离。iptables/Netfilter:Netfilter负责执行各种hooking规则(过滤、修改、丢弃等)的规则表;通过分析进入主机的网络包,提取包头数据并进行分析,以确定连接是允许还是阻塞的机制。由于这种方法可以直接分析包头数据,因此可以过滤分析包括硬件地址(MAC)、软件地址(IP)、TCP、UDP、ICMP等包信息。Veth设备对:Veth设备对的引入是为了实现不同网络命名空间的通信。网桥:网桥是二层网络设备,是最简单的CNI网络插件。它首先在Host上创建一个网桥,然后通过一个vethpair将网桥连接到容器netns。另外,在Bridge模式下,多主机网络通信需要额外配置主机路由Route(路由):Linux系统包含了完整的路由功能。IP层在处理数据发送或转发时,会使用路由表来决定将数据发送到哪里。ContainerNetworkInterface(CNI)最初是由CoreOS发起的容器网络规范,是Kubernetes网络插件的基础。基本思路是:ContainerRuntime在创建容器时,首先创建一个networknamespace,然后调用CNI插件为这个netns配置网络,然后启动容器中的进程。2.Kubernetes网络模型Kubernetes网络有一个重要的基本设计原则:每个Pod都有一个唯一的IP。这个PodIP被Pod中的所有容器共享,所有其他Pod都可以路由到该Pod。您是否注意到您的Kubernetes节点上运行着一些“暂停”容器?它们被称为“沙盒容器”,它们的唯一任务是保留和维护Pod中所有容器共享的网络命名空间(netns)。这样即使一个容器死了,创建一个新的容器来代替它,PodIP也不会改变。这种IP-per-pod模型的巨大优势在于Pod和底层主机之间不会发生IP或端口冲突。我们不必担心应用程序使用什么端口。满足这一点后,Kubernetes唯一的要求就是这些PodIP可以被所有其他Pod访问,无论这些Pod在哪个节点上。2.1节点内通信首先要保证同一节点上的Pod可以相互通信,然后可以扩展到跨节点通信、互联网通信等。在每个Kubernetes节点(本场景指的是Linux机器)上,都有一个根(root)命名空间(root用作引用,不是超级用户)——rootnetns(根网络命名空间)。主网络接口eth0在此根netns下。同样,每个Pod都有自己的netns(网络命名空间),通过虚拟以太网对连接到根netns。这基本上是一对管道,一端在根netns内,另一端在Pod的netns内。我们将Pod端的网络接口称为eth0,这样Pod不需要知道底层主机,它认为它有自己的根网络设备。另一端的名称类似于vethxxx。您可以使用ifconfig或ip命令列出节点上的所有这些接口。节点上的所有Pod都会经历这个过程。为了相互通信,这些Pod需要使用Linux以太网桥cbr0。Docker使用一个名为docker0的类似桥接器。您可以使用brctlshow命令列出所有网桥。假设一个网络包是从pod1到pod2的,从pod1中netns的eth0网口离开,通过vethxxx进入rootnetns。然后它被传递给cbr0,它使用ARP请求说“谁拥有这个IP”,从而发现目标地址。vethyyy说它有这个IP,因此网桥知道将数据包转发到哪里。数据包到达vethyyy,穿过管道对,到达pod2的netns。这是同一节点内容器之间的通信流程。当然也可以采用其他方式,但这无疑是最简单的方式,也是Docker采用的方式。2.2不同节点之间的通信正如我前面提到的,Pod也需要跨节点可达。Kubernetes不关心它是如何实现的。我们可以使用L2(跨节点的ARP)、L3(跨节点的IP路由,如云提供商的路由表)、覆盖网络,甚至信鸽。没关系,只要流量能到达另一个节点上想要的pod即可。每个节点为PodIP分配一个唯一的CIDR块(IP地址范围),因此每个Pod都有一个唯一的IP,不会与其他节点上的Pod冲突。在大多数情况下,尤其是在云环境中,云提供商的路由表将确保数据包到达正确的目的地。我们也可以通过在每个节点上建立正确的路由来达到同样的目的。许多其他网络插件以他们自己的方式做到这一点。这里我们有两个节点,类似于我们之前看到的。每个节点都有不同的网络名称空间、网络接口和网桥。假设数据包将从pod1到达pod4(在不同的节点上)。从pod1中netns的eth0网口离开,通过vethxxx进入rootnetns。然后传递给cbr0,cbr0通过发送ARP请求找到目标地址。此节点上没有Pod具有pod4的IP地址。根据路由判断,数据包从cbr0传输到主网接口eth0。数据包的源地址为pod1,目的地址为pod4。它以这种方式离开node1并进入电缆。路由表对每个节点的CIDR块都有路由设置,它将数据包路由到CIDR块包含pod4的IP的节点。因此数据包到达节点2的主要网络接口eth0。现在即使pod4不是eth0的IP,数据包仍然可以转发到cbr0,因为该节点配置了启用IP转发。节点的路由表查找与pod4的IP匹配的任何路由。它发现cbr0是该节点的CIDR块的目标地址。可以使用route-n命令列出本节点的路由表,会显示cbr0的路由,类型如下:网桥收到数据包,发送ARP请求,发现目的IP所属到vethyyy。数据包通过管道对到达pod4。这是Kubernetes网络的基础。下次遇到问题,一定要先检查这些网桥、iptables规则表和路由表。
