K8S网络四层结构
Node网络是保证k8s集群当中的节点之间能够正常做IP寻址和互通的一个网络,这个一般是由底层的网络基础设施组成的,比如公有云或自建的数据中心。
Pod是k8s云平台提供的虚拟机,是k8s基本的调度单位,所谓pod网络就是能够保证k8s集群当中所有的pod,包括同一节点上的pod和不同节点上的pod逻辑上看起来都在同一个平面网络内,能够相互做ip寻址并且相互通信的这样的网络。
pod网络构建于节点网络之上,又是上层service网络的基础。
同一节点上的pod网络
pod相当于k8s云平台所提供的虚拟机,实际上一个pod当中可以启一个或多个应用容器。
大部分场景下一个pod当中启一个容器,也有一些场景一个pod中启多个容器,这些容器共享pod的网络栈,也共享其他的一些资源,比如veth0。
上图展示了pod网络所依赖的3个网络设备,先看eth0,这个是节点主机上的网卡,它是支持节点流量出入的一个设备,也支持k8s集群节点中间做ip寻址和互通的设备。
第二个设备docker0叫虚拟网桥简单可以理解为一个虚拟交换机,它是支持节点上面的pod之间进行ip寻址和互通的一个设备。
第三个设备叫veth0,是pod1的虚拟网卡,支持pod内容器互通并且相互访问的一个虚拟设备。
docker0和veth0都是linux所支持并且所创建的虚拟网络设备,pod1内部有三个容器,都共享这个虚拟网卡veth0,内部的这些容器可以通过localhost相互访问这就是共享网络栈的意思。
注意pod内部的容器不能在同一个端口上同时开启服务,否则会有端口冲突问题。
pod1当中还有一个比较特殊的容器叫pause,这个容器运行的唯一目的是为pod建立共享的veth0网络接口,如果ssh到k8s集群当中一个有pod运行的节点上面去运行docker ps就可以看到pause这个容器。
pod1的ip是由docker0网桥所分配的,比如docker0网桥是172.17.0.1给第一个pod分配了一个ip是172.17.0.2,如果这个节点上面再启一个pod2,那么这个网桥会相应的给pod2分配ip 172.17.0.3,如果再启pod就可以以此类推,因为这些pod都是连在同一个网桥上面的,在同一个网段内,它们可以进行ip寻址和互通。
这是2个pod通过docker0网桥实现ip寻址互通互联的场景。
节点内的pod网络在172.17.0.0/24这个地址空间内,但是节点的主机在10.100.0.0/24这个地址空间内,也就是说pod网络和节点网络不在同一个网络内。
不同节点上的pod网络
不同节点之间的pod该如何做ip寻址互通呢?
假设有2个节点主机,一个是host1,ip为10.100.0.2 ,另外host2,ip是10.100.0.3,2个节点都在10.100.0.0/24这个地址空间内,host1上有一个pod x ,ip是172.17.0.2,pod2上有一个pod y,它的ip是172.17.1.3,
pod网络在172.17.0.0/16这个地址空间内,pod网络的ip地址是由k8s统一管理和分配的,可以保证集群内的pod ip是唯一的。
节点网络和pod网络不在同一个地址空间内,host1上的pod x是如何与host2上的pod y进行互通的?
不同节点上的pod互通有很多种技术实现方案,底层的技术细节也很复杂。
大体分为2类,一类是路由,另一类是覆盖网络方案。
路由
如果底层的网络是你可以控制的比如企业内部自建的数据中心并且你和运维团队的关系比较好就可以采用路由方案。
这个方案简单理解的话,通过路由设备为k8s集群的pod网络单独的划分网段并且配置路由器支持pod网络的转发,比如对于目标为172.17.1.0/24这个范围内的包转发到10.100.0.3这个主机上,同样对于目标为172.17.0.0/24这个范围内的包转发到10.100.0.2这个主机上。
当主机上的eth0接受到来自pod网络的包就会向内部的pod网桥进行转发,这样不同节点之间的pod就可以做相互的ip寻址和通讯。
这种方案依赖底层的网络设备,但是引入额外的性能开销比较小,这是路由方案。
覆盖网络
覆盖网络也叫overlay方案,如果底层网络是无法控制的,比如公有云网络或者企业的运维团队不支持路由方案,这个时候就可以采用覆盖网络方案,就是在现有网络的基础上再建立一个虚拟网络,实现的技术有很多比如flannel、Weavenet,这些方案大都采用隧道封包的技术,简单理解pod网络的数据包在出节点之前会先被封装成节点网络的数据包,当数据包经过底层网络到达目标节点,这个pod网络数据包就会被解封出来,再转发给内部的pod网络。
这种方案对底层的网络没有特别的依赖,但是封包和解包会引入额外的性能开销,这是覆盖网络方案。
CNI简介
考虑到pod网络实现技术众多,为了简化集成,k8s支持CNI(容器网络接口)这样一个标准,不同的网络技术可以通过CNI以插件的形式和k8s进行集成,k8s当中的kubelet通过CNI接口去操作pod网络比如删除或添加网络接口都通过CNI这个plugin操作,就可以做到不需要关心这个pod网络的底层的具体实现细节。
总结
1、k8s网络可以抽象成4层网络,第0层是节点网络,第1层是pod网络,第2层是service网络,第3层是外部接入网络,除了第0层其他各层都是建立在上一层之上的。
2、一个节点内的pod网络依赖于虚拟网桥和虚拟网卡,这些linux的虚拟设备保证同一节点上的pod之间可以做正常的ip寻址和互通。
一个pod内的容器是共享pod的网络栈的,这个网络栈是由pause容器所创建。
不同节点间的pod网络可以采用路由方案也可以采用覆盖网络方案。
路由方案依赖底层的网络设备,但是没有额外的性能开销或者额外的性能开销比较小。
覆盖网络不依赖于底层的网络,但是有额外的封包解包的开销。
3、CNI是一个pod网络的集成标准,简化k8s和不同的pod网络实现技术的集成。
有了pod网络,k8s集群内的所有的pod在逻辑上都可以看作在一个平面网络内,可以正常的做ip寻址和互通,
但是pod仅仅是k8s云平台的虚拟机抽象,最终需要在k8s集群中运行的是应用或者说是服务,而一个服务背后一般是由多个pod组成集群,这个时候就会引入服务发现和负载均衡的问题。