ITPub博客

首页 > 架构设计 > 数据架构 > Kubernetes的容器网络通信机制

Kubernetes的容器网络通信机制

原创 数据架构 作者:科技中通 时间:2020-07-24 16:30:41 0 删除 编辑


1

简介

容器化的近几年的飞速发展可以预见,以Docker为代表的轻量级容器虚拟化技术,将成为今后企业应用发布的标准形态,而以Kubernetes(K8S)为代表的云原生编排系统,将成为分布式集群架构的核心。随着容器虚拟化技术的兴起与微服务理念的普及,云计算正向着“云原生”(Cloud Native)的方向发展。为了适应这个趋势,网络也需要进行相应的改造以更好地支撑云原生平台。Kubernetes网络一直是一个非常复杂的主题,本文介绍了Kubernetes网络模型和通信机制。

2

Docker容器网络

Docker容器的隔离特性依赖于Linux内核虚拟化技术,所以Docker对Linux内核的特性有很强的依赖。这里介绍一下Docker使用到的与Linux网络有关虚拟化技术:网络命名空间、Veth设备对、网桥。

2.1. 网络命名空间

Linux内核为了提供对系统资源的封装和隔离,提供了多种Namespace,比如:IPC,Mount,PID,Network,User等等,一个进程可以在某一个Namespace下运行,只能看到自己所在的Namespace下的资源,Docker使用了这些功能来实现容器间的隔离。其中的Network Namespace就实现了整个网络栈的隔离,在不同的NetworkNamespace下,有独立的网卡、IP地址、端口号、路由表、iptables规则等等。每个Docker容器在创建的时候都会创建一个属于自己的网络命名空间。    

图表 1 Linux下的网络名字空间


2.2. veth设备对

容器有了不同的网络命名空间,保证了它们之间的网络隔离,但这个网络空间内只有一个Loopback接口,无法和外部通讯,我们还需要将容器用某种方法连接起来,实现互通。Linux kernel提供了一个叫做veth pair的机制,可以创建两个虚拟的网卡,它们之间有一个双向的管道可以互相通讯,类似于两个网卡间使用网线直连。通过ip命令可以将这两个网卡加入到不同的namespace中去,两个namespace间的进程可以通过这两块网卡实现网络通讯。

图表 2 veth设备对的连接

2.3. 网桥

通过veth对,可以实现两个namespace中的通讯,但是多个容器多个namespace的情况下,就不能采用这样的方法。这时需要Kernel提供的虚拟网桥设备了。Linux网桥是一个简单的2层设备,可以想象成一个软交换机,把多个网卡添加到这个软交换机上,就组成一个网络。
根据这个原理,我们可以在主机上创建一个网桥设备,对于每一个新的容器,为其创建一对veth网卡,将其中的一个端口加入到容器所在的namespace中配置好IP地址,同时把另一个端口添加到网桥设备中。所有的容器就可以通过主机上的网桥来进行报文的转发了。比如下面的图中创建了3个不同的网络名字空间,每个名字空间使用一个veth对连接到br0的网桥上。

图表 3使用网桥连接不同的网络名字空间

这个网络内部已经联通,还需要能够访问外部世界或者被外部世界访问。Linux网桥虽然是一个二层设备,但是它可以配置一个IP,作为虚拟网络的网关,发往这个IP的报文会进入到host的网络协议栈,利用host上的路由表、iptables等工具,就可以实现容器的虚拟网络到外部网络的访问。

如下图所示: Docker缺省的情况下会在主机上创建一个叫做docker0的网桥,并设置IP,并使用iptables来实现虚拟网络的NAT功能以及端口映射。docker1、docker2两个容器发出的对外访问的报文首先会经过docker0的NAT网关,然后主机将报文中的源地址(172.17.0.xxx)改成物理网卡IP地址(10.10.0.186)然后发出去。

图表 4 Docker的缺省网络结构
 
3

Kubernetes网络

Kubernetes在物理节点上基本沿用了上面介绍的Docker缺省网络结构,但它作为容器的编排系统和容器的集群,在此基础上还有着自己一套集群网络模型:

  1. 每个Pod都有集群内的唯一IP地址,在Pod启动的时候会自动分配一个IP。
  2. 集群内部所有的Pod之间可以直接通过IP地址进行访问,不需要NAT地址转换。
  3. Node上的agent可以直接访问其上运行的Pod


3.1 CNI

Kubernetes作为容器的编排框架,在网络层面,并没有进入更底层的具体容器互通互联的网络解决方案的设计中,比如:一个Pod应该配置什么IP,如何配置主机节点使之符合网络模型。Kubernetes没有提供明确的实现方案,而是提供了一个CNI标准接口,依靠开源社区、各大网络厂商、云服务提供商等,以插件的形式来实现具体底层的网络连接。
CNI插件包括两部分:CNI Plugin和IPAM Plugin。CNI Plugin用来配置容器的网络,接口实际上很简单,主要就是:添加网络、删除网络。当容器创建的时候调用添加网络的接口,让CNI plugin将容器添加到CNI plugin构建的网络中;当容器销毁时调用删除网络的接口,让CNI plugin将容器从网络中删除。而IPAM Plugin是负责给容器分配全局唯一IP。

现在CNI的插件非常多,物理机上部署常用Flannel、Calico、Cilium等,而AWS、GCE、阿里云等云服务商都提供了自己的CNI插件,直接使用云上的网络资源。管理员应该根据实际的需求和物理网络特征选择不同的CNI插件来实现Kubernetes规定的网络模型。

3.2. Pod内部容器的通信

一个Pod可以包含多个容器,同一个Pod内的容器共享同一个网络命名空间,共享同一个Linux协议栈。所以同一Pod内的容器,就和它们在同一台机器上一样,它们甚至可以用localhost地址访问彼此的端口。一般会把高度耦合的,或者之间的通讯十分频繁的容器放在一个Pod内部,实现他们之间的高效访问。

3.3. 节点内部的Pod之间的通信

节点上Docker容器底层的网络结构和上面介绍一样,所有的容器通过veth对,接入一个docker0网桥。只要他们都是在一个网段,那么就可以直接使用对方的IP地址进行通信。

图表 5同一节点内的Pod间通讯


如上图,Pod1和Pod2可以直接通过IP1和IP2进行互相的通行。

3.4. Pod间网络互通

Kubernetes网络模型要求节点之间的Pod可以直接通过对方的IP进行访问。但节点上的容器都位于docker0网桥中,形成了一个个独立的网络。由于外部网络并不知道这些网络的存在,所以他们的地址无法在外部网络中直接互通。如果要实现节点间Pod可以直接使用IP互联,需要满足两个条件:
a) 在整个Kubernetes集群中对Pod的IP分配进行规划,不能有冲突。

b) 找到一种办法,能够把Pod发出的报文正确的转发到目标节点和Pod上。

由于CNI插件负责了Pod的IP分配,所以它可以保证给每个Pod分配一个唯一的IP地址。此外它通过Kubernetes清楚地知道每个Pod位于哪个节点上,所以能够把Pod发出的报文转发到正确的目标节点上。不同的CNI插件使用了很多方案来实现Pod间报文的转发,但总体分为两大类:
a) Underlay方式:利用当前数据中心网路基础转发架构,配置L3层交换机、路由器、服务器上的路由等信息,打通所有节点上的容器网络来实现各个节点间pod的通讯

b) Overlay方式: 基于VXLAN、GRE、Geneve等在基础网络上建立一层叠加的虚拟网络,节点的所有Pod接入这个虚拟网络实现互通。

  •  Underl ay网络(基于路由)

将集群每个节点的docker网桥规划成一个网络,并且将所有的节点打造成路由器(Linux服务器本来就可以作为路由器使用),使用BGP等动态路由协议来同步每个节点上的Pod网络信息,更新节点上路由表。节点根据路由表对报文进行正确的转发。下图描述了路由的过程:

图表 6使用L3路由来转发Pod间报文

Pod1内的容器把报文发向自己所在的docker0网桥的IP,这个网桥对于容器来说相当于是一个网关,报文最终来到主机Node1节点的协议栈,协议栈通过路由表确定报文的下一 ,如果目标IP是Pod2,下一条应该是目标Pod所在的节点Node2的IP。通过物理网络将报文转发到Node2节点上后,Node2根据路由表信息再将报文转发到Pod所在的docker网桥网关上,再由网关转发到目标Pod。
节点中的路由表是关键的信息,如果路由表不正确,没有匹配的记录,报文只能被丢弃。
这种方案的优点是无需对原始报文再次封装,通过内核的路由转发,效率比较高;缺点是在超大的集群规模下,路由表会变的很大,性能会下降,并且所有的节点都必须在一个网络内才能直 接路由。

  • Overlay网络

其原理是在当前网络上,再构建一个覆盖网络,通过这个网络来转发Pod之间的报文。从报文角度上看,就是把Pod的报文封装一次,在实际网络上发送到对方节点。Flannel的overlay模式就是使用这种方案。
从具体实现上看,Flannel通过路由的配置,把docker0网桥出来的报文转发到一个flannel0的tun虚拟网卡上,tun虚拟网卡收到的数据实际上发送给了flanneld后台服务。flanneld收到Pod发出的报文后,对其进行封装,通过物理网络发送到目标Pod对应的节点上去,对方节点上的flanneld收到后对其进行解封装,然后再通过tun虚拟网卡将报文转发到目标Pod所在的docker网桥,网桥最终转发给Pod。不同的封装方法,构造了不同的overlay网络,Flannel自己实现了一个简单的基于UDP的封装协议,整体网络结构如下图:

图表 7 Overlay网络模型(Flannel)

Flannel还支持使用vxlan方式进行封装,使用的是kernel提供的vxlan虚拟网卡,流程和上述类似,但不再需要tun网卡和flanneld程序进行报文封装和发送,kernel会创建一个vxlan的虚拟网卡,docker0流量只需要导入这个vxlan网卡既可。

3.5. Calico

Calico 是一个典型的基于路由的underlay方案,Calico 在每一个计算节点利用 Linux Kernel 实现了一个高效的 vRouter 来负责数据转发,而每个vRouter 通过 BGP 协议负责把自己上运行的 workload 的路由信息像整个 Calico 网络内传播——小规模部署可以直接互联,大规模下可通过指定的 BGP route reflector来完成。这样保证最终所有的 workload 之间的数据流量都是通过 IP 路由的方式完成互联的。此外,Calico 基于 iptables 还提供了丰富而灵活的网络Policy,保证通过各个节点上的 ACLs 来提供 Workload 的多租户隔离、安全组以及其他可达性限制等功能。

3.6.Flannel

前面已经介绍过,Flannel通过给每台宿主机分配一个子网的方式为容器提供虚拟网络,它基于LinuxTUN/TAP,使用多种类型的封装方案来创建overlay网络,并借助etcd维护网络的分配情况。封装方式支持UDP,VXLAN。此外Flannel也支持host-gw这样的underlay方案。

3.7. Cilium

Cilium 是一个基于 eBPF 和 XDP 的高性能容器网络方案。Cilium同样实现了基于路由的underlay模式和基于VXLAN和Geneve的overlay模式,由于使用了eBPF+XDP技术,数据处理转发的速度提高了数倍。eBPF和XDP是Kernel的新特性,eBPF允许用户态程序将报文处理代码插入到Kernel内核态,由内核来执行报文的定制化过滤。而XDP类似DPDK可以旁路掉内核协议栈,直接对报文进行定制化处理。

图表 8 Cilium

3.8.多CNI网络

一般情况下Kubernetes集群只需配置一个集群网络,每个Pod只有一个虚拟网卡和IP地址。multus可以为运行在Kubernetes的POD提供多个网络接口,它可以将多个CNI插件组合在一起为POD配置不同类型的网络;最新的multus还支持使用Kubernetes CDR为不同功能的POD提供不同数目的单个或者多网络配置,为Kubernetes下面的网络解决方案提供了更加广阔的空间。multus支持几乎所有的CNI plugin,比如Flannel、Calico、Weave、Cilium等等。

它使用"delegates"的概念将多个CNI插件组合起来,并且指定一个master plugin作为Pod的主网络并且被Kubernetes所感知。


图表 9 Multus Pod多接口

4

总结

网络永远是个非常复杂的话题,网络虚拟化和容器虚拟化更是对网络提出很多的挑战。各种网络解决方案层出不穷。这篇文章是对Docker和Kubernetes网络模型的原理介绍,希望能帮助您对Kubernetes网络的工作方式有更好的了解。

来自 “ ITPUB博客 ” ,链接:http://blog.itpub.net/69960698/viewspace-2706800/,如需转载,请注明出处,否则将追究法律责任。

请登录后发表评论 登录
全部评论

注册时间:2020-04-03

  • 博文量
    4
  • 访问量
    1595