Kubernetes 容器网络确实是一块比较复杂的内容,本文是在学习张磊老师《深入剖析 Kubernetes》之后的理解整理,内容主要总结了 Kubernetes 网络模型和 CNI 插件,后面也介绍了容器跨主机网络的三种方案。
文章目录
Kubernetes 网络模型
1、本地容器间通信原理
为什么需要网络? 本质是为了连通然后通信。
为什么容器之间需要网络?每一个容器进程被 Network Namespace 隔离,都有一套独立的“网络栈”,是无法直接跟其他 Network Namespace 里的容器进程进行交互的。
容器之间如何通信:(分为单机与跨主机)
1)单机上容器间通信:【Veth Pair 设备 + 宿主机网桥】
宿主机上创建一个网桥,起虚拟交换机作用,主要功能是根据 MAC 地址学习来将数据包转发到网桥的不同端口(Port)上。然后利用 Linux 的 Veth Pair 的虚拟设备,将所有容器”连接“到这个网桥上。
注:绿色部分即为 Veth Pair 设备,都是成对出现,一端在容器内充当默认网卡,另一端在宿主机上并插在了 docker0 这个网桥上。
Veth Pair 设备的特点是:它被创建出来后,总是以两张虚拟网卡(Veth Peer)的形式成对出现的。并且,从其中一个“网卡”发出的数据包,可以直接出现在与它对应的另一张“网卡”上,哪怕这两个“网卡”在不同的 Network Namespace 里。
2)难点在于”容器跨主机通信“:【Overlay Network 覆盖网络】
集群中的容器是分布在不同主机上的,所以需要一个容器网络。在已有的宿主机网络上,再通过软件构建一个覆盖在已有宿主机网络之上的、可以把所有容器连通在一起的虚拟网络。所以,这种技术就被称为:Overlay Network(覆盖网络)
实现方式主要有三种:VXLAN、host-gw、UDP。具体内容可看本文最后的补充知识。
2、Kubernetes 网络模型设计
Kubernetes 网络模型:
- 所有容器都可以直接使用 IP 地址与其他容器通信,而无需使用 NAT。
- 所有宿主机都可以直接使用 IP 地址与所有容器通信,而无需使用 NAT。反之亦然。
- 容器自己“看到”的自己的 IP 地址,和别人(宿主机或者容器)看到的地址是完全一样的。
网络模型架构:
- CNI 网桥:Kubernetes 维护一个 cni 网桥,能够起到虚拟交换机作用的网络设备,使连接到上面的容器可以通过它在本地进行通信。
- Veth Pair:利用 Linux 的 Veth Pair 虚拟设备,使容器“连接”到 cni 网桥上。
-
CNI 网络插件 创建了一个特殊的设备(UDP 模式创建的是 TUN 设备,VXLAN 模式创建的则是 VTEP 设备),通过某种方法把不同宿主机上的特殊设备连通,从而达到容器跨主机通信。
个人理解,网络模型的核心是一个网络插件来达到容器跨主机通信,想要使用这个插件自然就需要接口,这就是 CNI 了。
CNI 网络插件
CNI 设计思想
CNI 网络插件不仅负责搭建起来一个“覆盖网络”实现容器跨主机通信,也需要提供接口在每次 kubelet 创建容器时可以设置容器加入到这个网络模型中。
Kubernetes 创建一个 Pod 的时候,它第一个创建的一定是 Infra 容器。所以在这一步,kubelet 就可以通过 CRI 创建并启动 Infra 容器,紧接着执行一个叫作 SetUpPod 的方法。这个方法的作用就是:为 CNI 插件准备参数,然后调用 CNI 插件为 Infra 容器配置网络。
CNI 插件部署实现
安装 kubernetes-cni 包,提供三类CNI 的基础可执行文件:
- 第一类,叫作 Main 插件,它是用来创建具体网络设备的二进制文件。比如,bridge(网桥设备)、ipvlan、loopback(lo 设备)、macvlan、ptp(Veth Pair 设备),以及 vlan。
- 第二类,叫作 IPAM(IP Address Management)插件,它是负责分配 IP 地址的二进制文件。比如,dhcp,这个文件会向 DHCP 服务器发起请求;host-local,则会使用预先配置的 IP 地址段来进行分配。
- 第三类,是由 CNI 社区维护的内置 CNI 插件。用来实现一个给 Kubernetes 用的容器网络方案,通常需要两部分工作:
(1)首先,实现这个网络方案本身。这一部分需要编写的,其实就是 flanneld 进程里的主要逻辑。比如,创建和配置 flannel.1 设备、配置宿主机路由、配置 ARP 和 FDB 表里的信息等等。
(2)然后,实现该网络方案对应的 CNI 插件。这一部分主要需要做的,就是配置 Infra 容器里面的网络栈,并把它连接在 CNI 网桥上。
补充:三种容器跨主机通信方案
这里关注一个核心问题(感觉是容器跨主机通信的核心点):就是容器 IP 与其所在 Node IP的对应,也就是有了容器的 IP 如何知道它是运行在哪个 Node 上的。
解决容器的跨主机通信问题,都是为了构建覆盖网络。Flannel 项目是 CoreOS 公司主推的容器网络方案,这里从 Flannel 项目整理三种主流实现方案:
1、UDP(方案开销大)
-
"容器IP与其node对应" 这一核心问题解决:
一台宿主机上的所有容器,都应该属于该宿主机被分配的一个“子网”,而这些子网与宿主机的对应关系,保存在 Etcd 当中。也就是说 docker0 网桥的地址范围必须是 Flannel 为宿主机分配的子网。
UDP模式下会运行一个 flanneld 用户进程处理由容器传出的 IP 包,可以根据目的容器 IP 的地址,匹配到对应的子网,然后从 Etcd 中找到这个子网对应的宿主机的 IP 地址,完成映射。 -
另外,会利用 Linux 中的TUN 设备(Tunnel 设备)。它会把收到的 IP 包交给创建这个设备的应用程序,实现操作系统内核和用户应用程序之间传递 IP 包。
在 Linux 中,TUN 设备是一种工作在三层(Network Layer)的虚拟网络设备。TUN 设备的功能非常简单,即:在操作系统内核和用户应用程序之间传递 IP 包。
- 实例:基于 Flannel UDP 模式的跨主通信的基本原理
解释:
IP 包从容器经过 docker0 出现在宿主机,然后又根据路由表进入 flannel0 设备后,flannel0 会把收到的 IP 包交给创建这个设备的应用程序,所以宿主机上的 flanneld 进程(Flannel 项目在每个宿主机上的主进程)就会收到这个 IP 包。
然后,flanneld 进程在处理由 flannel0 传入的 IP 包时,就可以根据目的 IP 的地址(比如 100.96.2.3),匹配到对应的子网(比如 100.96.2.0/24),从 Etcd 中找到这个子网对应的宿主机的 IP 地址是 10.168.0.3。
之后 flanneld 进程就可以进行 UDP 封装通过宿主机的 eth0 网卡发送出去了。到了目的主机flanneld 进程监听的端口后,再进行解封装。
- 开销分析:
如上图,Flannel UDP 模式仅在发出 IP 包的过程中,就需要经过三次用户态与内核态之间的数据拷贝,然后Flannel 进行 UDP 封装(Encapsulation)和解封装(Decapsulation)的过程,也都是在用户态完成的。
上下文切换和用户态操作的代价其实是比较高的,所以造成 Flannel UDP 模式性能不好。
2、VXLAN(主流方案)
VXLAN,即 Virtual Extensible LAN(虚拟可扩展局域网),是 Linux 内核本身就支持的一种网络虚似化技术。所以说,VXLAN 可以完全在内核态实现上述封装和解封装的工作,从而通过与前面相似的“隧道”机制,构建出覆盖网络(Overlay Network)。
- 实例:基于 Flannel VXLAN 模式的跨主通信的基本原理
解释:
图中每台宿主机上名叫 flannel.1 的设备,就是 VXLAN 所需的 VTEP 设备,它既有 IP 地址,也有 MAC 地址。
step1:当 container-1 发出请求之后,这个目的地址是 10.1.16.3 的 IP 包,会先出现在 docker0 网桥,然后被路由到本机 flannel.1 设备进行处理。
step2:当有 Node 启动并加入 Flannel 网络时,每台宿主机上的 flanneld 进程会负责维护一些信息:
1)维护路由规则:查到要发往的容器网络网关IP(也就是目的VTEP的IP地址),10.1.16.0
2)维护ARP表:通过目的网关IP(10.1.16.0)得到“目的 VTEP 设备”的 MAC 地址
3)维护叫做 FDB(Forwarding Database)的转发数据库:通过“目的 VTEP 设备”的 MAC 地址查到要发往的目的主机 IP,10.168.0.3。
step3:查到目的主机IP后,封包。Node 1 上的 flannel.1 设备就可以把这个数据帧从 Node 1 的 eth0 网卡发出去。显然,这个帧会经过宿主机网络来到 Node 2 的 eth0 网卡。
step4:Node 2 收到数据帧后,内核网络栈会发现这个数据帧里有 VXLAN Header,并且 VNI=1。所以 Linux 内核会对它进行拆包,拿到里面的内部数据帧,然后根据 VNI 的值,把它交给 Node 2 上的 flannel.1 设备。而 flannel.1 设备则会进一步拆包,取出“原始 IP 包”。最终,IP 包就进入到了 container-2 容器的 Network Namespace 里。
- 容器IP与其node对应的核心问题解决:
每台宿主机上的 flanneld 进程负责维护一系列信息。核心是叫做 FDB(Forwarding Database)的转发数据库,可以通过“目的 VTEP 设备”的 MAC 地址查到要发往的目的主机 IP,而 MAC 地址又可以通过自己维护的 ARP 表查到。
3、host-gw
host-gw 模式的工作原理,其实就是将每个 Flannel 子网(Flannel Subnet,比如:10.244.1.0/24)的“下一跳”,设置成了该子网对应的宿主机的 IP 地址。
利用一些机制来创建路由规则,并维护路由信息。
- 实例1:Flannel host-gw 示意图
- 实例2:Calico工作原理
参考:《深入剖析Kubernetes | 极客时间》张磊,Kubernetes容器网络