Kubernetes网络模型和典型实现总结

简介: 前文[Kubernetes中的ClusterIP、NodePort、LoadBalancer、Ingress服务访问方式比较](https://www.atatech.org/articles/156810)中总结了服务接入访问的主要方式,以及它们之间隐含关系。有了这些概念基础后,K8S应用开发和服务部署就容易很多了,但Under the hood服务访问究竟是如何实现的呢?这篇内容就Kubern

前文Kubernetes中的ClusterIP、NodePort、LoadBalancer、Ingress服务访问方式比较中总结了服务接入访问的主要方式,以及它们之间隐含关系。有了这些概念基础后,K8S应用开发和服务部署就容易很多了,但Under the hood服务访问究竟是如何实现的呢?这篇内容就Kubernetes的网络模型和典型的容器网络实现,特别是阿里云自己的容器网络插件(Terway)的实现做了一个较详细的总结。

Pod之间Container-to-Container networking

Linux networking namespace为进程通讯提供了一个逻辑网络栈,包括network devices、routes、firewall rules。Network namespace(NS)管理实际是为其中的所有进程提供了一个独立的逻辑网络Stack。

缺省情况下,Linux将每个进程挂载在Root NS下,这些进程通过eth0通往外面的世界。
image.png

在Pod世界里所有其中的容器共享一个NS,这些容器都有相同的IP和Port空间,通过localhost访问也是互通的。Shared storage也是可以访问的,通过SharedVolume挂载到容器中。如下一个NS per pod图例:
image.png

同Node中Pod-to-Pod networking

先看同一个Node下Pod之间的networking如何实现?答案是通过Virtual Ethernet Device (or veth pair)的两块Virtual interfaces,每块veth挂载在一个NS上,来实现跨NS的连接。比如,一块挂在Root NS(host)上,另一块挂在Pod NS上,好比一根网线把两个在不同网络空间的traffic连接起来了,如图:
image.png

有了veth pair这条网线,Pods网络可以连通到Root NS了,但在Root NS上如何实现对来自不同Pod的packet通讯呢?答案是通过Linux Ethernet Bridge,一个虚拟的Layer2网络设备来实现不同network segments之间的Ethernet packet switching。不得不提这个old-school协议:ARP,实现了MAC地址到IP地址的发现协议。Bridge广播ethframe到所有连接的设备(除发送者外),收到ARP回复后将packet forward到对应veth设备上。如图:
image.png

跨Node之间Pod-to-Pod networking

进入这部分之前,先提及K8S在其(Pod)networking设计上的3个fundamental requirements,任何networking部分的实现都必须遵循这三个需求。

  • 在不使用NAT下,所有Pods都能和其它任何Pods通讯
  • 在不使用NAT下,所有Nodes都能和所有Pods通讯
  • Pod所看到自己的IP和其它Pods看到它的IP一定是相同的

简要来看,K8S网络模型要求Pod IP在整个网络中都能通达。具体实现方案有三方面:

  • Layer2(Switching)Solution
  • Layer3(Routing)Solution,如,Calico, Terway
  • Overlay Solution,如Flannel

这部分下文介绍,目前且认为Pod IP的网络通达性是确保的。

在Pod获得IP之前,kubelet为每个Node分配一个CIDR地址段(Classless inter-domain routing),每个Pod在其中获取唯一IP,CIDR 地址块的大小对应于每个Node的最大 Pod 数量(默认110个)。在Pod IP和跨Node网络层部署成功后,从源Pod1到目的Pod4的通讯如图:
image.png

Pod-to-Service networking

K8S Service管理服务的Pods状态,在Pod有变化下管理对应IP的变化,并管理对外提供服务的Virtual IP到Pod IPs路由访问,实现外部对服务Virtual IP的访问路由到Pod IP,以此屏蔽外部对服务后端的实现形态。所以在服务创建时,会对应生成一个Virtual IP(也即是Cluster IP),任何对该Virtual IP的访问将打散路由到服务所属的Pods上。

K8S的服务是如何实现对Virtual IP的访问负载均衡呢?答案是netfilter和iptables。netfilters是Linux built-in networking framework,为Linux提供网络包过滤、NAT和Port translation等丰富的自定义handler实现。iptables是运行在Linux user-space的规则管理系统,为netfilter框架提供丰富的包转发规则管理。

在K8S实现中kube-proxy(node deamon)通过watch apiserver来获得服务配置的变化,比如,服务的Virtual IP变化、Pod IP变化(ie, pod up/down)。iptables规则随之变化并将请求路由到服务对应的Pod上,Pod IP选取是随机的,这样看iptables起到了Pod负载均衡作用。在访问请求Return path上,iptables会做一次SNAT以替换IP header的Pod IP为服务Virtual IP,这样使得Client看起来请求仅在服务Virtual IP上进行通讯。

从K8S v1.11中IPVS(IP Virtual Server)被引入成为第二种集群内负载均衡方式。IPVS同样也是构建基于netfilter之上,在创建服务定义时可指定使用iptables或IPVS。IPVS是特定适合于服务负载均衡的解决方案,提供了非常丰富的均衡算法应用场景。

使用DNS

每个服务会设置一个DNS域名,kubelets为每个容器进行配置--cluster-dns=<dns-service-ip>,用以解析服务所对应DNS域名到对应的Cluster IP或Pod IP。1.12后CoreDNS成为缺省DNS方式。服务支持3种类型DNS records(A record、CNAME、SRV records)。其中常用的是A Records,比如,在cluster.local的DNS name下,A record格式如pod-ip-address.my-namespace.pod.cluster.local,其中Pod hostname和subdomain字段可以设置为标准的FQDN格式,比如,custom-host.custom-subdomain.my-namespace.svc.cluster.local

CNI

网络模型的实现上K8S在Pod资源管控(kubelet)和一套标准Container Networking Interface(CNI)定义和实现共同完成的。CNI在其中充当了"胶水"作用:各种容器网络实现能在一致的操作接口下由kubelet统一管控调度。另外,多个容器网络也能共存于一个集群内,为不同Pod的网络需求提供服务,都是在kubelet的统一管控下完成。

Overlay networking: Flannel

Flannel是CoreOS为K8S networking开发的解决方案,也是阿里云ACK产品支持的容器网络解决方案。Flannel的设计原理很简洁,在host网络之上创建另一个扁平网络(所谓的overlay),在其上地址空间中给每个pod容器设置一个IP地址,并用此实现路由和通讯。

主机内容器网络在docker bridge docker0上完成通讯,不再赘述。主机间通讯使用内核路由表和IP-over-UDP封装进行实现。容器IP包流经docker bridge会转发到flannel0网卡(TUN)设备上,进而流入到flanneld进程中。flanneld会对packet目标IP地址所属的网段信息查询其对应的下一跳主机IP,容器子网CIDR和所属主机IP的映射(key-value)保存在etcd中,flanneld查询得到packet目标IP所属的主机IP地址后,会将IP packet封装到一个UDP payload中并设置UDP packet目标地址为所得到的目标主机IP,最后在host网络中发送出UDP packet。到达目标主机后,UDP packet会流经flanneld并在这里解封出IP packet,再发送至flannel0docker0最后到达目标容器IP地址上。下图示意流程:

image.png

值得一提是,容器CIDR和下一跳主机IP的映射条目容量没有特殊限制。在阿里云ACK产品上该条目容量需要在VPC/vSwitch控制面中进行分发,考虑到整体性能因素,在数量上做了一定数量限制(缺省48个)。但在自建主机网络部署中,该数量限制就不会明显了,因为主机下一跳主机网络在一个大二层平面上。

Flannel新版本backend不建议采用UDP封装方式,因为traffic存在3次用户空间与内核空间的数据拷贝,(如下图)性能上存在比较大的损耗。新版本推荐用VxLan和云服务商版本的backends进行优化。

image.png

L3 networking: Calico

Calico是L3 Routing上非常流行容器网络架构方案。主要组件是Felix,BIRD和BGP Route Reflector。Felix和BIRD均是运行在Node上的deamon程序。

Felix完成网卡的管理和配置,包括Routes programming和ACLs。实现路由信息对Linux kernel FIB的操作和ACLs的管理操作。由于Felix功能完整性和运行独立性非常好,其功能作为Off-the-shelf被集成到阿里云Terway网络插件中,实现其网络策略功能。

BIRD(BGP client)完成内核路由FIB条目向集群网络侧分发,使其路由条目对所有网络节点中可见,并实现BGP路由协议功能。每一个BGP client会连接到网络中其它BGP client,这对规模较大的部署会是明显的瓶颈(due to the N^2 increase nature)。鉴于该限制引入了BGP Route Reflector组件,实现BGP clients路由分发的中心化汇聚。在集群网站中Reflector组件可以部署多个,完全能于部署规模大小来决定。Reflector组件仅仅执行路由信令和条目的分发,其中不涉及任何数据面流量。如下简要的Calico架构:

image.png

L3 networking:Terway

Terway是阿里云自研CNI插件,提供了阿里云VPC互通和方便对接阿里云产品的基础设施,没有overlay网络带来的性能损耗,同时提供了简单易用的backend功能。

Terway功能上可分为三部分:1. CNI插件,一个独立的binary运行程序;2. Backend Server(也称为daemon),程序以独立daemonSet方式运行在每个Node上;3. Network Policy,完全集成了Calico Felix实现。

CNI插件binary是通过daemonSet部署中initContainer安装到所有节点上,实现了ADDDELCHECK三个接口供kubelet调用。这里以一个Pod在创建过程中的网络setup步骤来说明:

  • 当一个Pod被调度到节点上时,kubelet监听到Pod创建在自己节点上,通过runtime(docker...)创建sandbox容器来打通所需namespace。
  • kubelet调用插件binary的cmdAdd接口,插件程序对接口参数设置检查后,向backendServer发起AllocIP调用。
  • backendServer程序的networkService根据Pod的网络类型进行相应的Pod IP申请,支持三种网络类型ENIMultiIPVPCENIVPCIP

    • ENIMultiIP是eni网卡带多IP类型,由networkService中的ResourceManager在自己的IP地址池中进行IP地址分配
    • VPCENI是为Pod创建和挂载一个eni,由networkService中的allocateENI向阿里云Openapi发起对所属ecs实例的eni创建、挂载,并获得对应eni IP地址
    • VPCIP是为Pod在VPC网络平面上分配一个IP地址,这是在插件程序中通过调用ipam接口从vpc管控面获取的IP地址
  • 在backendServer返回AllocIP调用(IP地址)结果后,插件调用不同网络类型的driver完成net namespace link setup。

综上图示:
image.png

为什么需要支持上述三种网络类型?根本上是由阿里云vpc网络基础设施所决定,同时覆盖阿里云主流应用对vpc网络资源的使用场景需求。另一方面是对标Amazon AWS的容器网络解决方案,在基于VPC和ENI的网络设施上能支持同等功能。

ENI多IP、VPC ENI和VPC IP的主要区别在于前两者下的Pod网段和VPC网段是相同的,而VPC IP的网段和节点的宿主机网段不同。这样使得在ENI网络环境下的IP路由完全在VPC的L2网络平面上进行,而VPC IP网络需要在VPC路由表中进行配置Pod网段的下一跳主机,和Flannel的路由模式类似。可以看出,ENI网络能带来更灵活的路由选择和更好的路由性能。如下两个截图反映其不同路由特点:

VPC ENI网络:
image.png

VPC IP网络:
image.png

ENI多IP(1个主IP/多个辅助IP)网络下有2种路由模式:veth策略路由ipvlan。两者本质区别在于使用不同的路由模式,前者使用veth pair的策略路由,后者使用ipvlan网络路由。策略路由需要在节点上配置策略路由条目来保证辅助IP的流量经过它所属的弹性网卡。ipvlan实现了一个网卡虚拟出多个子网卡和不同的IP地址,eni将其辅助IP绑定到这些虚拟出来的子网卡上形成一个与vpc平面打通的L3网络。这种模式使ENI多IP的网络结构比较简单,性能相对veth策略路由网络也更好。两种网络模式切换通过配置即可完成(缺省是vethpair):

值得一提的是Terway还实现了ENI多IP地址资源池的管理和分配机制。networkService中的eniIPFactory为每个eni网卡创建一个goroutine,该eni网卡上的eniIP的分配释放都在这个goroutine中完成。在创建一个eniIP时扫描已经存在的eni网卡,如该eni还存在空闲的eniIP,该goroutine会通过ipResultChan返回给eniIPFactory一个分配的IP。如果所有的eni网卡的eniIP都分配完毕,会先创建一个新的eni网卡和对应的goroutine,首次创建eni网卡时无需做IP分配,直接返回eni网卡主IP即可。eniIP释放是逆向的,在eni网卡的最后一个eniIP释放时,整个eni网卡资源会释放掉。

另外,有一个startCheckIdleTickergoroutine会定期扫描地址池的MaxPoolSizeMinPoolSize水位,在低于和高出水位阀值时会对地址池eniIP资源进行进行创建和释放,使得地址池IP资源处于一个可控水位范围中。为了保证资源状态一致性,有一个startGarbageCollectionLoopgoroutine会定期扫描IP地址是否在用或过期状态,如检测到会进行资源GC操作。最后,Pod资源状态数据都持久化在本地的一个boltDB文件中/var/lib/cni/terway/pod.db,即使Pod已经在apiServer中删除,GetPod会从本地boltDB中读取副本数据。在Pod已经删除但副本还存在DB的情况下,GC goroutine检测到会执行清理。截图简述:

image.png

总结下,从这些backend功能可以看到Terway为阿里云vpc网络资源设施连通性做了很好的封装,让基于阿里云Kubernetes的应用开发和部署带来更加简便和高效的优点。

相关实践学习
深入解析Docker容器化技术
Docker是一个开源的应用容器引擎,让开发者可以打包他们的应用以及依赖包到一个可移植的容器中,然后发布到任何流行的Linux机器上,也可以实现虚拟化,容器是完全使用沙箱机制,相互之间不会有任何接口。Docker是世界领先的软件容器平台。开发人员利用Docker可以消除协作编码时“在我的机器上可正常工作”的问题。运维人员利用Docker可以在隔离容器中并行运行和管理应用,获得更好的计算密度。企业利用Docker可以构建敏捷的软件交付管道,以更快的速度、更高的安全性和可靠的信誉为Linux和Windows Server应用发布新功能。 在本套课程中,我们将全面的讲解Docker技术栈,从环境安装到容器、镜像操作以及生产环境如何部署开发的微服务应用。本课程由黑马程序员提供。 &nbsp; &nbsp; 相关的阿里云产品:容器服务 ACK 容器服务 Kubernetes 版(简称 ACK)提供高性能可伸缩的容器应用管理能力,支持企业级容器化应用的全生命周期管理。整合阿里云虚拟化、存储、网络和安全能力,打造云端最佳容器化应用运行环境。 了解产品详情: https://www.aliyun.com/product/kubernetes
相关文章
|
网络协议 算法 Java
基于Reactor模型的高性能网络库之Tcpserver组件-上层调度器
TcpServer 是一个用于管理 TCP 连接的类,包含成员变量如事件循环(EventLoop)、连接池(ConnectionMap)和回调函数等。其主要功能包括监听新连接、设置线程池、启动服务器及处理连接事件。通过 Acceptor 接收新连接,并使用轮询算法将连接分配给子事件循环(subloop)进行读写操作。调用链从 start() 开始,经由线程池启动和 Acceptor 监听,最终由 TcpConnection 管理具体连接的事件处理。
374 2
基于Reactor模型的高性能网络库之Tcpconnection组件
TcpConnection 由 subLoop 管理 connfd,负责处理具体连接。它封装了连接套接字,通过 Channel 监听可读、可写、关闭、错误等
315 1
|
12月前
|
JSON 监控 网络协议
干货分享“对接的 API 总是不稳定,网络分层模型” 看电商 API 故障的本质
本文从 OSI 七层网络模型出发,深入剖析电商 API 不稳定的根本原因,涵盖物理层到应用层的典型故障与解决方案,结合阿里、京东等大厂架构,详解如何构建高稳定性的电商 API 通信体系。
基于Reactor模型的高性能网络库之Poller(EpollPoller)组件
封装底层 I/O 多路复用机制(如 epoll)的抽象类 Poller,提供统一接口支持多种实现。Poller 是一个抽象基类,定义了 Channel 管理、事件收集等核心功能,并与 EventLoop 绑定。其子类 EPollPoller 实现了基于 epoll 的具体操作,包括事件等待、Channel 更新和删除等。通过工厂方法可创建默认的 Poller 实例,实现多态调用。
499 60
|
安全 调度
基于Reactor模型的高性能网络库之核心调度器:EventLoop组件
它负责:监听事件(如 I/O 可读写、定时器)、分发事件、执行回调、管理事件源 Channel 等。
518 57
基于Reactor模型的高性能网络库之时间篇
是一个用于表示时间戳(精确到微秒)**的简单封装类
332 57
|
9月前
|
机器学习/深度学习 数据采集 人工智能
深度学习实战指南:从神经网络基础到模型优化的完整攻略
🌟 蒋星熠Jaxonic,AI探索者。深耕深度学习,从神经网络到Transformer,用代码践行智能革命。分享实战经验,助你构建CV、NLP模型,共赴二进制星辰大海。
|
10月前
|
机器学习/深度学习 传感器 算法
【无人车路径跟踪】基于神经网络的数据驱动迭代学习控制(ILC)算法,用于具有未知模型和重复任务的非线性单输入单输出(SISO)离散时间系统的无人车的路径跟踪(Matlab代码实现)
【无人车路径跟踪】基于神经网络的数据驱动迭代学习控制(ILC)算法,用于具有未知模型和重复任务的非线性单输入单输出(SISO)离散时间系统的无人车的路径跟踪(Matlab代码实现)
628 2
|
10月前
|
机器学习/深度学习 并行计算 算法
【CPOBP-NSWOA】基于豪冠猪优化BP神经网络模型的多目标鲸鱼寻优算法研究(Matlab代码实现)
【CPOBP-NSWOA】基于豪冠猪优化BP神经网络模型的多目标鲸鱼寻优算法研究(Matlab代码实现)
254 8
|
11月前
|
算法 安全 网络安全
【多智能体系统】遭受DoS攻击的网络物理多智能体系统的弹性模型预测控制MPC研究(Simulink仿真实现)
【多智能体系统】遭受DoS攻击的网络物理多智能体系统的弹性模型预测控制MPC研究(Simulink仿真实现)
386 0

推荐镜像

更多