容器云平台网络架构设计及优化.docx
- 文档编号:9130017
- 上传时间:2023-02-03
- 格式:DOCX
- 页数:32
- 大小:1.21MB
容器云平台网络架构设计及优化.docx
《容器云平台网络架构设计及优化.docx》由会员分享,可在线阅读,更多相关《容器云平台网络架构设计及优化.docx(32页珍藏版)》请在冰豆网上搜索。
容器云平台网络架构设计及优化
容器云平台网络架构设计及优化
1.1容器网络概述
1容器平台网络模型
与传统的虚拟化相比,容器其生命周期更短、数量密度更高、集群变更速度更快。
基于这些特性,容器平台网络就必须对集群节点之间的高速通信进行充分的考量。
除此之外,在企业级的容器云平台上,承载众多租户的计算负载之间资源的安全隔离,也必须要考虑到的因素。
显而易见,传统的物理网络架构无法满足容器平台高灵活性的需求,容器平台网络构建必须要有一种崭新的设计架构来满足,这便推动了容器平台网络设计的发展。
容器网络发展到目前,已经形成了Docker主导的CNM模型和Google、CoreOS、Kubernetes主导的CNI模型两种模型共存的情况。
CNM和CNI并不是网络实现,他们是网络规范和网络体系。
从研发的角度来看就是一些接口,主要是和网络管理相关的问题。
容器平台的网络方案,通常可以从协议栈、穿越方式、隔离方法三个维度去设计方案:
图1网络架构示意图
协议栈:
◎二层(桥接、ARP+MAC)
◎三层(路由转发)
◎二层+三层(节点内部二层转发、跨节点三层转发)穿越方式:
◎Overlay(隧道穿越底层基础设施)
◎Underlay(直接穿越底层基础设施)隔离方法:
◎VLAN
◎VXLAN
1.2容器网络分类介绍
1.2.1协议栈
二层解决方案,常见于传统机房或者虚拟化场景中,针对ARP和MAC(桥接模式)学习,广播风暴是这个方案最核心要解决的问题。
众所周知,二层广播,对整个集群中节点的数量也会有严格的限制。
三层解决方案一般是基于BGP协议实现路由转发,通过自主学习完善整个数据中心的路由状态。
这个方案的优势是IP穿透性,可以实现IP网络透传。
因为基于IP,所以其优势在于规模性,具有非常优秀的扩展性。
但在实际使用过程中,受限于各个企业自身网络安全的考量,例如生产网和开发测试网隔离,或者网络本身不支持BGP,那么这个方案就受限了。
二层+三层的方案,集成了前面两种方案的优势(既解决了二层规模性扩展的问题,又解决三层网络隔离受限的问题),正成为容器云网络场景下首选的协议栈层级的解决方案。
1.2.2穿越方式Underlay网络
提到Underlay网络,就必须从以太网说起,以太网从最开始设计出来就是一个分布式网络,没有中心的控制节点,网路中的各个设备之间通过协议传递的方式学习网络的可达信息,由每台设备自己决定要如何转发,这直接导致了没有整体观念,不能从整个网络的角度对流量进行调控。
由于要完成所有网络设备之间的互通,就必须使用通用的语言,这就是网络协议,RFC就是网络协议的法律,相当于国际法,各个设备供应商遵从国际法行事,就基本保证了整个网络世界的正常运行。
Underlay就是当前数据中心网路基础转发
架构的网络,只要数据中心网络上任意两点路由可达即可,指的是物理基础层。
我们可以通过物理网络设备本身的技术改良、扩大设备数量、带宽规模等完善Underlay网络,其包含了一切现有的传统网络技术。
Overlay网络
Overlay技术可以分为网络Overlay,主机Overlay和混合式Overlay三大类。
网络Overlay是指通过控制协议对边缘的网络设备进行网络构建和扩展,也就是本文所讲的Overlay网络技术。
Overlay网络技术多种多样,一般采用TRILL、VXLAN、GRE、NVGRE等隧道技术。
TRILL(TransparentInterconnectionofLotsofLinks)技术是电信设备厂商主推的新型环网技术;NVGRE(NetworkVirtualizationusingGenericRoutingEncapsu-lation)STT(StatelessTransportTunnelingProtocol)是IT厂商主推的Overlay技术;以及大家非常熟悉的
VXLAN(VirtualExtensibleLAN)等基于隧道的封装技术。
由于这些也都是新增的协议,均需要升级现有网络设备才能支持。
Overlay网络中应用部署的位置将不受限制,网络设备可即插即用、自动配置下发,自动运行,Overlay网络业务变化,基础网络不感知,并对传统网络改造极少,最为重要的是虚拟机和物理服务器都可以接入Overlay网络中。
1.2.3根据基础设施划分
VLAN(VirtualLocalAreaNetwork)意为虚拟局域网,是在交换机实现过程中涉及到的概念,由802.1Q标准所定义。
由于交换机是工作在链路层的网络设备,连接在同一台交换机的终端处于同一个三层网中,同时也处于同一个广播域。
当交换机接入较多的终端时,任意一台终端发送广播报文时(例如:
ARP请求),报文都会传遍整个网络。
对于规模较大的组网场景,广播报文的泛滥对于网络通信将会造成较大的影响。
VLAN技术为这一问题提供了解决方案,VLAN将同一网络划分为多个逻辑上的虚拟子网,并规定当收到广播报文时,仅仅在其所在VLAN中进行广播从而防止广播报文泛滥。
VLAN技术在链路层的层次中实现了广播域的隔离。
随着大数据、云计算技术的兴起以及虚拟化技术的普及,VLAN技术的弊端逐渐显现出来,具体表现为如下3个方面:
(1)虚拟化技术的发展促使大数据、云计算技术公司采用单个物理设备虚拟多台虚拟机的方式来进行组网,随着应用模块的增加,对于支持VLAN数目的要求也在提升,802.1Q标准中的最多支持4094个VLAN的能力已经无法满足当下需求。
(2)公有云提供商的业务要求将实体网络租借给多个不同的用户,这些用户对于网络的要求有所不同,而不同用户租借的网络有很大的可能会出现IP地址、MAC地址的重叠,传统的VLAN仅仅解决了同一链路层网络广播域隔离的问题,而并没有涉及到网络地址重叠的问题,因此需要一种新的技术来保证在多个租户网络中存在地址重叠的情况下依旧能有效通信的技术。
(3)虚拟化技术的出现增加了交换机的负担,对于大型的数据中心而言,单台交换机必须支持数十台以上主机的通信连接才足以满足应用需求,而虚拟化技术使得单台主机可以虚拟化出多台虚拟机同时运行,而每台虚拟机都会有其唯一的MAC地址。
这样,为了保证集群中所有虚机可以正常通信,交换机必须保存每台虚机的MAC地址,这样就导致了交换机中的MAC表异常庞大,从而影响交换机的转发性能。
基于以上需求,VXLAN技术被提出。
VXLAN技术是网络Overlay技术的一种实现,对于Overlay技术,笔者的理解是:
在基于物理网络拓扑的
基础上通过一定的技术来构建虚拟的、不同于物理网络拓扑的逻辑网络,而物理网络的拓扑结构对于Over-
lay终端而言是透明的,终端不会感知到物理网络的存在,
而仅仅能感知到逻辑网络结构。
对于终端的视角,网络的情况和直接通过物理设备实现逻辑拓扑的效果是相同的。
VXLAN技术可以基于三层网络结构来构建二层虚拟网络,通过VLAN技术可以将处于不同网段网络设备整合在同一个逻辑链路层网络中,对于终端用户而言,这些网络设备似乎“真实地”部署在了同一个链路层网络中。
相比VLAN技术,VXLAN技术具有以下的优势:
(1)24位长度的VNI字段值可以支持更多数量的虚拟网络,解决了VLAN数目上限为4094的局限性的问题。
(2)VXLAN技术通过隧道技术在物理的三层网络中虚拟二层网络,处于VXLAN网络的终端无法察觉到VXLAN的通信过程,这样也就使得逻辑网络拓扑和物理网络拓扑实现了一定程度的解耦,网络拓扑的配置对于物理设备的配置的依赖程度有所降低,配置更灵活更方便。
(3)VLAN技术仅仅解决了二层网络广播域分割的问题,而VXLAN技术还具有多租户支持的特性,通过VXLAN分割,各个租户可以独立组网、通信,地址分配方面和多个租户之间地址冲突的问题也得到了解决。
1.3总结
通过本章的学习,可以初步了解容器网络相关的基础概念,主要涉及到了容器网络的协议栈、穿越方式以及隔离方式。
针对协议栈,到底是采用二层互通,还是采用三层互通,还是结合两种方式的优点整合一个综合的方式取决于业务场景;针对穿越方式,是采用传统的Underlay网络,还是基于SDN的Overlay网络,和客户现场情况,以及硬件设备支持的情况都有比较大的关联;同样,隔离方式采用VLAN还是VXLAN,也和场景强相关。
由此可见,容器云网络的设计,需要因地制宜,因材施教,从客户需求以及现场情况发出,才能制定出一个完善的解决方案。
2基于Docker网络基础和实现原理
Docker网络方案基于OpenStack平台网络解决方案,在不断的摸索中,形成了自己的一套网络模型。
Docker网络在整个Docker技术栈中的位置如图:
图2Docker生态技术栈
在容器网络项目探索中,随着容器的发展,容器网络的发展也出现了分歧。
主要分为两派,一个是Docker原生的CNM(ContainerNetworkModel),另一个是兼容性更好的CNI(ContainerNetworkInter-face)。
CNI就是后来为Kubernetes等容器平台广泛推崇使用的接口技术,后面的章节会详细讲述。
这里,我们简要介绍CNM。
原先Docker的网络相关的代码是直接在Docker中的,网络功能也比较简单,对网络的诟病也是比较多。
随着Docker越来越向平台化发展,将功能组件逐渐从Docker中解耦,Docker从1.7把网络相关的代码从Docker的代码中剥离出来新建了一个Libnetwork项目,引入了CNM的网络模型。
图3CNM(ContainerNetworkModel)
CNM模型下的Docker网络模型如上所示。
它由Sandbox,Endpoint,Network三种组件组成。
注意,该模型只是规定了三种组件各自的作用,他们都有各自的具体实现方式。
Sandbox:
Sandbox包含了一个Con-tainer的网络相关的配置,如网卡Interface,路由表等。
Sandbox在Linux上的典型实现是Networknamespace。
在Linux系统上的Docker环境中,Container,Networknamespace,Sandbox这三者是绑定在一起的。
一个Sandbox可以包含多个Endpoint,这些Endpoint可以来自多个Network。
Endpoint:
Sandbox加入Network的方式是通过Endpoint完成的。
Endpoint的典型实现方式是Vethpair,每个Endpoint都是由某个Network创建。
创建后,它就归属于该Network。
同时,Endpoint还可以加入一个Sandbox。
加入后,相当于该Sandbox也加入了此Network。
Network:
Network的一种典型实现是Linuxbridge。
一个Network可以创建多个Endpoint。
将这些Endpoint加入到Sandbox,即实现了多个Sandbox的互通。
总结起来:
如果要想两个Container之间可以直接通信,那么最简单的办法就是由一个Network创建两个Endpoint,分别加入这两个Container对应的Sandbox。
注意:
不同Network之间默认的隔离性是docker通过设置Iptables完成的,通过改变Iptables的设置,可以使得两个Network互通。
标准的Docker网络支持以下4类网络模式:
host模式:
使用--net=host指定
container模式:
使用--net=container:
Name_or_ID指定none模式:
使用--net=none指定
bridge模式:
使用--net=bridge指定,设为默认值
桥接模式是最常见的Docker容器网络类型。
在桥接模式下,Docker会为每个容器分配IP地址及创建虚拟以太网网卡对(Veth)。
所有的容器都被连接到Docker在主机绑定的桥接设备上。
被连接到同一个桥接设备的所有容器,都可以实现互联互通。
如果容器要对外界提供服务,则用户需要将容器内的服务端口与宿主机的某一段口绑定。
这样所有访问苏主机目标端口的请求都将通过Docker代理转发到容器的服务端,最终到达应用。
除了桥接模式,Docker也支持主机(host)模式,让容器直接使用宿主机的网络设备。
宿主机模式使得容器占用宿主机的端口资源,而且要求容器具有更高的权限,因此只有特殊需求的容器,才会使用这种模式,如OpenShift集群中的Router组件。
Router主机需要监听计算节点上的端口,以接受外部的请求,因此Router组件的Pod的容器网络为主机模式。
本章节主要介绍了Docker网络的情况,从Docker整个生态栈入手,分析了基于单机和集群两种不同场景的Docker网络,着重分析了在单机模式下Docker网络的情况(host/bridge/none/container)。
3Kubernetes网络场景分析
在实际的业务场景中,业务组件之间的关系十分复杂,特别是微服务概念的提出,应用部署的粒度更加细小和灵活。
为了支持业务应用组件的通信联系,Kubernetes网络的设计主要致力于解决以下场景:
(1)紧密耦合的容器到容器之间的直接通信;
(2)抽象的Pod到Pod之间的通信;
(3)Pod到Service之间的通信;
(4)集群外部与内部组件之间的通信;
3.1容器到容器的通信
在同一个Pod内的容器(Pod内的容器是不会跨宿主机的)共享同一个网络命名空间,共享同一个Linux协议栈。
所以对于网络的各类操作,就和它们在同一台机器上一样,它们甚至可以用localhost地址访问彼此的端口。
这么做的结果是简单、安全和高效,也能减少将已经存在的程序从物理机或者虚拟机移植到容器的难度。
如图4中的阴影部分就是Node上运行着的一个Pod实例。
容器1和容器2共享了一个网络的命名空间,共享一个命名空间的结果就是它们好像在一台机器上运行似的,它们打开的端口不会有冲突,可以直接用Linux的本地IPC进行通信。
它们之间互相访问只需要使用localhost就可以。
图4容器到容器间通信
3.2Pod之间的通信
每一个Pod都有一个真实的全局IP地址,同一个Node内的不同Pod之间可以直接采用对房Pod的IP地址通信,而不需要使用其他发现机制,例如DNS、Consul或者etcd。
Pod既有可能在同一个Node上运行,也有可能在不用的Node上运行,所以通信也分为两类:
同一个Node内的Pod之间的通信和不同Node上的Pod之间的通信。
1)同一个Node内的Pod之间的通信
如图,可以看出,Pod1和Pod2都是通过Veth连接在同一个Docker0网桥上的,它们的IP地址IP1、IP2都是从Docker0的网段上自动获取的,它们和网桥本身的IP3是同一个网段的。
另外,在Pod1、Pod2的Linux协议栈上,默认路由都是Docker0的地址,也就是说所有非本地的网络数据,都会被默认发送到Docker0网桥上,由Docker0网桥直接中转,它们之间是可以直接通信的。
图5同一个Node内的Pod关系
2)不同Node上的Pod之间的通信
Pod的地址是与Docker0在同一个网段内的,我们知道Docker0网段与宿主机网卡是两个完全不同的IP网段,并且不同Node之间的通信只能通过宿主机的物理网卡进行,因此要想实现位于不同Node上的Pod容器之间的通信,就必须想办法通过主机的这个IP地址来进行寻址和通信。
另外一方面,这些动态分配且藏在Docker0之后的所谓“私有”IP地址也是可以找到的。
Kubernetes会记录所有正在运行Pod的IP分配信息,并将这些信息保存在etcd中(作为Service的Endpoint)。
这些私有IP信息对于Pod到Pod的通信也是十分重要的,因为我们的网络模型要求Pod到Pod使用私有IP进行通信。
之前提到,Kubernetes的网络对Pod的地址是平面的和直达的,所以这些Pod的IP规划也很重要,不能有冲突。
综上所述,想要支持不同Node上的Pod之间的通信,就要达到两个条件:
(1)在整个Kubernetes集群中对Pod分配进行规划,不能有冲突;
(2)找到一种办法,将Pod的IP和所在Node的IP关联起来,通过这个关联让Pod可以互相访问。
根据条件1的要求,我们需要在部署Kubernetes的时候,对Docker0的IP地址进行规划,保证每一个
Node上的Docker0地址没有冲突。
我们可以在规划后手工分配到每个Node上,或者做一个分配规则,由安
装的程序自己去分配占用。
例如Kubernetes的网络增强开源软件Flannel就能够管理资源池的分配。
根据条件2的要求,Pod中的数据在发出时,需要有一个机制能够知道对方Pod的IP地址挂在哪个具体的Node上。
也就是说要先找到Node对应宿主机的IP地址,将数据发送到这个宿主机的网卡上,然后在宿主机上将相应的数据转到具体的Docker0上。
一旦数据到达宿主机Node,则哪个Node内部的Docker0便知道如何将数据发送到Pod。
具体情况,如下图所示。
图6跨Node的Pod通信
在图6中,IP1对应的是Pod1,IP2对应的是Pod2。
Pod1在访问Pod2时,首先要将数据从源Node的
eth0发送出去,找到并到达Node2的eth0。
也就是说先要从IP3到IP4,之后才是IP4到IP2的送达。
3.3Pod到Service之间的通信
为了支持集群的水平扩展、高可用,Kubernetes抽象出Service的概念。
Service是对一组Pod的抽象,它会根据访问策略(LB)来访问这组Pod。
Kubernetes在创建服务时会为服务分配一个虚拟的IP地址,客户端通过访问这个虚拟的IP地址来访问服务,而服务则负责将请求转发到后端的Pod上。
这个类似于反向代理,但是,和普通的反向代理有一些不同
:
首先它的IP地址是虚拟的,想从外面访问需要一些技巧;其次是它的部署和启停是Kubernetes统一自动管理的。
Service在很多情况下只是一个概念,而真正将Service的作用落实的是背后的kube-proxy服务进程。
在Kubernetes集群的每个Node上都会运行一个kube-proxy服务进程,这个进程可以看作Service的透明代理兼负载均衡器,其核心功能是将到某个Service的访问请求转发到后端的多个Pod实例上。
对每一个TCP类型的KubernetesService,kube-proxy都会在本地Node上建立一个SocketServer来负责接收请求,然后均匀发送到后端某个Pod的端口上,这个过程默认采用RoundRobin负载均衡算法。
Kube-proxy和后端Pod的通信方式与标准的Pod到Pod的通信方式完全相同。
另外,Kubernetes也提供通过修改Service的service.spec.-sessionAffinity参数的值来实现会话保持特性的定向转发,如果设置的值为“ClientIP”,则将来自同一个ClientIP的请求都转发到同一个后端Pod上。
此外,Service的ClusterIP与NodePort等概念是kube-proxy通过Iptables和NAT转换实现的,kube-proxy在运行过程中动态创建与Service相关的Iptables规则,这些规则实现了ClusterIP及NodePort的请求流量重定向到kube-proxy进程上对应服务的代理端口的功能。
由于Iptables机制针对的是本地的kube-proxy端口,所以如果Pod需要访问Service,则它所在的那个Node上必须运行kube-proxy,并且在每个Kubernetes的Node上都会运行kube-proxy组件。
在Kubernetes集群内部,对ServiceClusterIP和Port的访问可以在任意Node上进行,这个因为每个Node上的kube-proxy针对该Service都设置了相同的转发规则。
综上所述,由于kube-proxy的作用,在Service的调用过程中客户端无需关心后端有几个Pod,中间过程的通信、负载均衡及故障恢复都是透明的,如下图所示。
图7Service的负载均衡转发
访问Service的请求,不论是用ClusterIP+TargetPort的方式,还是用节点机IP+NodePort的方式,都会被节点机的Iptables规则重定向到kube-proxy监听Service服务代理端口。
Kube-proxy接收到Service的访问请求后,会如何选择后端Pod?
首先,目前kube-proxy的负载均衡只支持RoundRobin算法。
该算法按照成员列表逐个选取成员,如果一轮循环完,便从头开始下一轮,如此循环往复。
Kube-proxy的负载均衡器在RoundRobin算法的基础上还支持Session保持。
如果Service在定义中指定了Session保持,则kube-proxy接收请求时会从本地内存中查找是否存在来自该请求IP的affinityState对象,如果存在该对象,且Session没有超时,则kube-proxy将请求转向该affinityState所指向的后端Pod。
如果本地存在没有来自该请求IP的affinityState对象,记录请求的IP和指向的Endpoint。
后面的请求就会粘连到这个创建好的affinityState对象上,这就实现了客户端IP会话保持的功能。
接下来我们深入分析kube-proxy的实现细节。
kube-proxy进程为每个Service都建立了一个“服务代理对象”,服务代理对象是kube-proxy程序内部的一种数据结构,它包括一个用于监听此服务请求的Socket-Server,SocketServer的端口是随机选择的一个本地空闲端口。
此外,kube-proxy内部也建立了一个“负载均衡器组件”,用来实现SocketServer上收到的连接到后端多个Pod连接之间的负载均衡和会话保持能力。
kube-proxy通过查询和监听APIServer中Service与Endpoint的变化来实现其主要功能,包括为新创建的Service打开一个本地代理对象(代理对象是kube-proxy程序内部的一种数据结构,一个Service端口是一个代理对象,包括一个用于监听的服务请求的SocketServer),接收请求,针对发生变化的Service列表,kube-proxy会逐个处理。
下面是具体的处理流程:
(1)如果该Service没有设置集群IP(ClusterIP),则不做任何处理,否则,获取该Service的所有端口定义列表(spec.ports域)
(2)逐个读取服务端口定义列表中的端口信息,根据端口名称、Service名称和Namespace判断本地是否已经存在对应的服务代理对象,如果不存在就新建,如果存在且Service端口被修改过,则先删除Iptables中和该Service相关的的规则,关闭服务代理对象,然后走新建流程,即为该Service端口分配服务代理对象并为该Service创建相关的Iptables规则。
(3)更新负载均衡器组件中对应Service的转发地址表,对于新建的Service,确定转发时的会话保持策略。
(4)对于已经删除的Service则进行清理。
图8Kube-proxy与
- 配套讲稿:
如PPT文件的首页显示word图标,表示该PPT已包含配套word讲稿。双击word图标可打开word文档。
- 特殊限制:
部分文档作品中含有的国旗、国徽等图片,仅作为作品整体效果示例展示,禁止商用。设计者仅对作品中独创性部分享有著作权。
- 关 键 词:
- 容器 平台 网络 架构 设计 优化