k8s网络模型
-
网络的命名空间:Linux在网络栈中引入网络命名空间,将独立的网络协议栈隔离到不同的命令空间中,彼此间无法通信;docker利用这一特性,实现不容器间的网络隔离。
-
Veth设备对:也叫虚拟网络接口对。Veth设备对的引入是为了实现在不同网络命名空间的通信。
-
Iptables/Netfilter:Netfilter负责在内核中执行各种挂接的规则(过滤、修改、丢弃等),运行在内核 模式中;Iptables模式是在用户模式下运行的进程,负责协助维护内核中Netfilter的各种规则表;通过二者的配合来实现整个Linux网络协议栈中灵活的数据包处理机制。
-
网桥:网桥是一个二层网络设备,通过网桥可以将linux支持的不同的端口连接起来,并实现类似交换机那样的多对多的通信。
-
路由:Linux系统包含一个完整的路由功能,当IP层在处理数据发送或转发的时候,会使用路由表来决定发往哪里
-
cni0: cni0是Linux网络桥接设备,所有veth设备都将连接到该桥接器,因此同一节点上的所有Pod都可以相互通信
Kubernetes网络有一个重要的基本设计原则: 每个Pod拥有唯一的IP
Pause容器 - 为解决Pod中的网络问题而生
每个Pod中都运行着一个 Pause 容器,也可称之为根容器,在Pod中第一个启动的容器,其唯一的任务是保留并持有一个网络命名空间(netns),该命名空间被该Pod内的其他容易所共享, 所以说一个 Pod 里面的所有容器,它们看到的网络视图是完全一样的。即:它们看到的网络设备、IP地址、Mac地址等等,跟网络相关的信息,其实全是一份,这一份都来自于 Pod 第一次创建的这个 Infra container。这就是 Pod 解决网络共享的一个解法。
图片:
Pod中容器通信
因为同一个Pod中的容器共享一个网络命名空间,所以他们之间通过localhost就能互相访问
图中的veth即指veth对的一端(另一端未标注,但实际上是成对出现),该veth对是由Docker Daemon挂载在docker0网桥上,另一端添加到容器所属的网络命名空间,图上显示是容器中的eth0。
图中演示了bridge模式下的容器间通信。容器1向容器2发送请求,容器1,容器2均与docker0建立了veth对进行通讯。
当请求经过docker0时,由于容器和docker0同属于一个子网,因此请求经过容器2与docker0的veth对,转发到容器2,该过程并未跨节点,因此不经过Pod的eth0。
同节点Pod间通信
第一步是确保同一节点上的Pod可以相互通信,然后可以扩展到跨节点通信、internet上的通信,等等。
- 对 Pod1 来说,eth0 通过虚拟以太网设备(veth*)连接到 root namespace
- 网桥 docker0 中为 veth* 配置了一个网段。一旦数据包到达网桥,网桥使用ARP (opens new window)协议解析出其正确的目标网段 veth*
- 网桥 docker0 将数据包发送到 veth*
- 数据包到达 veth* 时,被直接转发到 Pod2 的 network namespace 中的 eth0 网络设备
跨节点Pod间通信
Node1 中的 Pod1 向 Node2 中的 Pod3
-
数据包从 Pod1 的网络设备 eth0,该设备通过 veth0 连接到Node1中的 root namespace
-
数据包到达Node中的 root namespace 中的网桥 docker0
-
网桥上执行 ARP 将会失败,因为与网桥连接的所有设备中,没有与该数据包匹配的 MAC 地址。一旦 ARP 失败,网桥会将数据包发送到默认路由(root namespace 中的 eth0 设备)。此时,数据包离开节点进入网络
-
假设网络可以根据各节点的CIDR网段,将数据包路由到正确的节点
-
数据包进入目标节点的 root namespace(Node2 上的 eth0)后,通过网桥路由到正确的虚拟网络设备(veth2)
-
最终,数据包通过 veth2 发送到对应 Pod3 的 eth0,完成了数据包传递的过程