searchusermenu
  • 发布文章
  • 消息中心
点赞
收藏
评论
分享
原创

K8s网络基本原理

2024-08-29 02:13:47
117
0

随着IT基础设施的发展,应用的部署形态发生了很大的变化,从集中式到分布式,从物理机部署到虚拟机部署,再到现在的容器化部署,应用间的通信也从经历了从物理机网络,到虚拟机网络,再到容器集群网络的发展过程。

容器技术本质上是一种虚拟化技术,容器网络也依托网络虚拟化技术而呈现丰富的多样性,在这里特别地,指Kubernetes的网络模型。


连通场景

K8s对Pod如何接入网络有着明确规定,简单来说就是每个Pod都有一个IP,而且内部获取和外部通信相同,这就要求一个无需NAT转换的扁平网络,体现在Pod和Node的相互通信上。

在K8s的设计规范里,提出了4个需要解决的网络问题,分别是Container-to-Container、Pod-to-Pod、Pod-to-Service和External-to-Internal。在实际中,由于通信端点所在位置不同(如是否同一主机、是否集群内外)和访问方式不同(如PodIP、ClusterIP、ExternalIP),场景会更多一些。此外,Pod网段、Node网段和Service网段各不相同,也增加了网络连通的复杂性。

上图基于K8s的结构,简要归纳了主要的端到端互联场景,这些场景最终的连通路径和方式可能会有重叠的地方,但作为行为分类有不同的代表意义。
  • 主机内
    • (1)Pod内容器互通
    • (2)主机内Pod互通
    • (3)主机内访问Pod
    • (4)Service的后端节点在相同主机
  • 集群内
    • (5)主机之间互通
    • (6)不同主机Pod互通、Service的后端节点在不同主机
  • 集群外
    • (7)集群内访问集群外服务
    • (8)集群外访问集群内服务

基本原理

网络的拓扑结构一般是个有向图,连通的节点间路径长度不定,所以我们也可以说网络是分段的,分段包含的意思是数据包下一跳被送到哪里,从这个角度来说,需要探明的是什么设备(物理的或虚拟的)承担了怎样的中转(或转发)职能,在这基础上,又还有隔离(如地址、端口冲突)和可见性(如路由转换和IP抓取)问题。

在K8s中,要求Pod有独立IP,实际上是把Pod当作一个小型主机来看待,这也是传统应用迁移到容器的便捷性的一个来源,在网络方面,隔离就是指网络栈的隔离了,网络栈包括有接口、设备、路由表、iptables规则等,主要是通过网络命名空间(Network Namespace)来实现的。

 

Pod内容器互通

每个Pod对应不同的网络命名空间,拥有各自的网络栈,端口相同也不会冲突,IP和MAC地址由逻辑网络管理分配,与同一主机内的情况类似,Pod内的容器通过localhost即可实现互相访问,由虚拟的环回接口(Loopback Interface)转发到对应端口。


 

主机内Pod互通

根据前面网络分段的说法,主机内不同Pod的容器服务之间互通实际也就是主机内的Pod互通,只要流量能到达Pod的虚拟网卡上,自然就能发送到对应端口的容器里。

在传统的分层网络认知里,数据包流转由二层/三层设备根据一定的协议和规则传递,除了网卡(NIC,Network Interface Card/Controller)外,核心设备有交换机(Switch)和路由器(Router),算上逻辑功能还有网桥(Bridge)和网关(Gateway)等,了解虚拟网络很大程度上也就是了解使用哪些虚拟设备。

一般来说,主机内的Pod应该在二层互通,不需要三层路由出去再回来,从物理机的连接方式来说,可以用网线直连两台主机的网卡,也可以通过交换机或网桥来连通,虚拟网络也相应模拟这些行为。

Linux Veth

  • Linux Veth(Virtual Ethernet)是Linux内核中的一种虚拟网络设备,它常用于创建虚拟网络接口对,即Veth Pair,可以将Veth Pair的一端放在一个网络命名空间中,另一端放在另一个网络命名空间中,实现不同命名空间之间的网络通信。

Linux Veth是同一主机内Pod互通的一种基本方式,上图创建了veth-1-a/veth-1-b这一组Veth Pair,两端分别插(设置)到P1和P2网络命名空间(NS)中。形象上有点像用网线把P1和P2这两台带网卡的机器直连了起来,实际上是将Veth设备作为Pod的虚拟网卡,根据Pod CIDR网段设置IP ,流量经由这张网卡时,可以通过ARP协议问询到对端MAC地址,实现数据包传递。

这种点对点的连接方式在多个Pod的场景就不太适用了,多个设备互联一般需要交换机类的角色进行集成中转,Linux内核也有相应的虚拟设备。

Linux Bridge

Linux Bridge是一种在Linux内核中实现的虚拟网络设备,它在数据链路层(二层)上工作,用于连接多个网络接口,包括物理和虚拟接口。


Linux Bridge模拟的是物理交换机的功能,如上图的br0,虚拟网桥设备创建在根网络命名空间(Root NS)下,除了可以连通不同网络命名空间中的Pod,也是容器连接宿主机(Node)网络的桥梁,与前面直连两个Pod不同,这里Veth Pair的另一端连接到虚拟网桥的接口上,就像将网线插在交换机上一样,各个Pod仍可以通过ARP协议实现通信。

MACvlan、IPvlan

MACvlan和IPvlan都是Linux内核中的网络虚拟化技术,它们允许多个虚拟接口共享同一个物理网络接口,简单地理解就是可以把一张物理网卡虚拟成多张子网卡。

MACvlan每个虚拟接口都分配不同的MAC地址,IPvlan每个虚拟接口则与物理接口共享MAC地址,两者没有绝对的替代关系,得看具体网络环境的要求,例如MAC数量限制和IP分配规则等。

MACvlan能提供接近原生物理设备的性能,IPvlan也依赖底层父接口处理ARP等广播报文,三层工作模式下能直接进行路由转发,减少网络栈开销,一般情况下性能均好于单纯的虚拟设备。


MACvlan工作在数据链路层,IPvlan支持二层(L2)和三层(L3)工作模式,另外都还支持不同的类型(mode flags),如bridge、private、VEPA等,总的来说,除了三层必要路由配置外,子接口的连通性归根结底是谁来转发数据包,这个无论是二层还是三层都是类似的。

  • 在bridge模式下,子接口可以直接通信,由父接口承担交换机或路由器的角色,如图绿色线条所示。
  • 其他不支持子接口直接通信的模式,就由父接口将流量转到外部设备,再通过外部设备寻址或路由转发回来,如图蓝色和紫色线条所示。特别地,外部设备不一定是指主机外的设备,主机内部互通使用前面提到的虚拟网桥也可以。

另外,一般情况下交换机和网桥设备是不支持将流量发回同一接口的,例如受生成树协议(STP)的回环限制,在虚拟化场景物理接口存在复用,所以外部二层设备需要打开发卡模式(hairpin mode),允许流量发回同一接口,以保障子接口间能正常通信。

主机内访问Pod

主机内访问Pod也可以说是如何实现宿主机和容器互通,主机网段和容器网段一般来说是不同的,当然也不是强制要求,即使二者的CIDR是相同网段,这个场景也类比于跨网互通,所以问题重点在于连接两边的网关角色。

主机内部也是跨网络命名空间互通场景,基本方式就是找一个既能连通根空间(主机默认的网络命名空间),也能连通容器空间(Pod所在的网络命名空间)的“设备”,并在宿主机和Pod内分别配置跳转路由。


虚拟网桥比物理网桥更灵活,能给它设置IP用作网关,配合路由规则不仅可以实现本机和容器网络互通,也可以实现虚拟网络跨主机互通,如上图绿色线条。

  • Pod内,默认流量经网桥转发,如“default via 10.0.0.1 dev eth0 ……”
  • 主机内,目标为容器的流量经网桥转发,如“10.0.0.0/24 dev br0 ……”

MACvlan和IPvlan的父接口和子接口网络隔离,可以在父接口的网络空间下创建另一个子接口(如上图eth1),通过它来转发实现主机和容器互通(需要bridge模式),主要是从宿主机能到达容器,如上图蓝色线条。

  • 主机内,配置访问容器的路由,如“10.0.0.102 dev eth1 ……”

Pod访问Service

Service可以说是Pod虚拟的负载均衡,也是虚拟的反向代理,访问一个IP实际导向一组后端IP,常规做法是中间人代理模式(例如Nginx),在主机内示意如下图。


中间人模式将原本“客户端-服务器”的连接拆成两段,分别是“客户端-代理”和“代理-服务器”,“实体的中间人”有两个明显的问题,一是会占用端口,需要特别规划避免与业务冲突,二是数据会在用户态和内核态复制,容易导致性能瓶颈。

另外,Service的访问IP是虚拟IP(如ClusterIP),不与任何设备关联,无法监听,中间代理的方案要行得通需要将ServiceIP转成localhost,也就是DNAT(Destination Network Address Translation,目标网络地址转换),这是网络地址转换(NAT)的一种形式,相对的还有SNAT(Source Network Address Translation,源网络地址转换)。

不过,既然DNAT能够修改连接目标,也就没必要多一个代理节点,直接修改成可达的后端Pod地址,再加上负载均衡规则就实现主机访问Service的功能了,这是由内核提供的。

netfilter

netfilter是Linux内核中的一个网络包过滤和处理的框架,所有的流量都会经过当前网络栈的netfilter处理器,其中定义了五个处理节点(钩子,hook points),如下图。


iptables

iptables是netfilter的用户空间接口,用于配置和管理网络数据包,iptables有五个内置的规则表,通常主要使用以下四张表:

  • Filter 表:这是默认的表,用于控制数据包的访问控制,即决定哪些数据包可以进入、离开或穿过系统。它包含三条内置链:INPUTFORWARDOUTPUT
  • NAT 表:用于网络地址转换,它可以在数据包进入(PREROUTING链)、离开(POSTROUTING链)系统或在系统内部路由(OUTPUT链)时修改数据包的源或目的地址。
  • Mangle 表:用于修改数据包的内容,如调整 TTL 值、设置 QoS 标记等。它在数据包的处理流程中的多个点上都有作用,包括 PREROUTINGINPUTFORWARDOUTPUTPOSTROUTING链。
  • Raw 表:用于决定数据包是否被连接跟踪系统跟踪,这通常用于某些需要绕过连接跟踪的场景。它主要在PREROUTINGOUTPUT链上使用。

除了这四张常用的表,还有:

  • Security 表:这是一个较少使用的表,它与 SELinux 集成,用于强制访问控制策略。

对于前述中间人的例子,如果使用iptables来做,就是添加NAT表规则,在OUTPUT链中实现DNAT转换。

iptables的规则匹配是链表式的,时间复杂度为O(n),所以在大规模集群,也就是包含大量规则的情况下,性能可能会受影响。除此之外,集群规则需要推送到每个Node,规则变更的时间复杂度接近O(n2)。

IPVS

IPVS(IP Virtual Server)是一个构建在Linux内核中的高性能负载均衡器,它通过虚拟IP地址(VIP)将网络请求分发到多个后端服务器上,从而实现负载均衡。IPVS也是在netfilter上构建的,设计时面向水平扩展,采用类哈希表的数据结构,查找时间复杂度接近O(1),规则变更复杂度也比iptables相应降低一个量级,性能相对较好。

Service的虚拟IP一般情况下是ping不通的,不过IPVS会创建一个虚拟接口,能够处理ICMP指令,如果采用的是这个模式,Service的虚拟IP就可以ping通。

eBPF

eBPF(Extended Berkeley Packet Filter)是一种革命性的技术,起源于Linux内核,能够在操作系统内核中安全有效地运行沙盒程序。它允许开发者在不更改内核代码的前提下,实时获取和修改操作系统的行为,从而扩展内核的功能。eBPF程序经过内核的验证器校验,确保安全执行,并且可以利用即时编译器(JIT)实现接近直接运行机器码的速度。

eBPF的工作原理基于事件驱动,可以在内核或应用程序经过特定的钩子点时运行程序。这些钩子包括系统调用、函数入口/退出、内核跟踪点、网络事件等,也可以通过创建内核探针(kprobe)或用户探针(uprobe)来附加eBPF程序。

简单来说,eBPF能够通过可编程的方式在内核态植入自定义逻辑,除了扩展性和函数丰富程度外,还有两点明显的优势:

  • eBPF能够在连接级别(socket level)进行NAT,建连后不需要每个包都过滤,对比iptables和IPVS包级别(packet level)的重复拦截,显然性能更好。
  • iptables和IPVS一般配置在宿主机网络命名空间下,Pod访问Service的基本方式是想办法先转到宿主机网络命名空间,再通过netfilter进行地址转换,这种情况下,一方面会多转一次网络协议栈,另一方面对Pod流量不经过宿主机网络空间的连网方式不好支持。eBPF可以配置在任何网络命名空间中,包括宿主机和容器的网络命名空间,相对来说更加灵活。

跨主机Pod互通

网络包的投递方式有点像是邮局,对于民政部门正式确立的官方地址,如“XX市XX区XX街道XX号”,各地邮局能根据系统指引正常中转,邮递员也能准确地送上门,但是对于当地某些非正式的地址,如“XX村XX山北面王二家”,就得依靠熟识的老乡带路才行了。

主机内的容器互通是靠官方还是要靠老乡,对应Underlay和Overlay两种不同的网络方案。

  • Underlay网络:Underlay网络就是我们理解的传统网络,也是物理网络,通过物理或光纤电缆连接网络设备和服务器,包括交换机和路由器等设备,借助以太网协议、路由协议和VLAN协议等驱动。
  • Overlay网络:Overlay网络是建立在现有的Underlay网络之上的一种虚拟网络技术,通过在物理网络上封装数据包,能够创建一个分离的、逻辑上的网络层。

不难想象,Underlay方案性能更好,但对物理网络有侵入,Overlay方案则相反,主要对比如下。

方案

underlay

overlay

实现

  • MACvlan
  • IPvlan
  • VXLAN
  • IPIP

优点

  • 性能较好
  • 网络流量可精确管理、监控
  • 对物理网络无侵入
  • 网络管理相对简单

缺点

  • 对当前组网有侵入
  • 占用现网IP,需规划
  • 维护和管理较复杂
  • 容器网络较难监控
  • 容器对外需要通过Node SNAT,较难精确管理流量

其中,VXLAN(Virtual Extensible LAN,虚拟可扩展局域网)是一种网络虚拟化技术,它通过在现有的IP网络上创建虚拟网络,允许数据中心实现大规模的网络隔离和扩展。VXLAN使用MAC-in-UDP封装技术,将第二层的以太网帧封装在第三层的IP包中,实现跨越物理网络边界的虚拟网络通信。

VXLAN的核心组件包括VTEP(VXLAN Tunnel Endpoint,VXLAN隧道终端),它负责封装和解封VXLAN数据包,以及VXLAN隧道,即VTEP之间的逻辑通道用于传输VXLAN数据包。VXLAN数据包结构包括外层以太网头、外层IP头、外层UDP头、VXLAN头(包含VNI和其他控制信息)和内层以太网帧。

VXLAN的工作原理是,当主机发送数据包时,源VTEP将数据包封装在VXLAN头和外层IP、UDP头中,然后发送到目标VTEP。封装后的VXLAN数据包通过物理网络传输,目标VTEP接收到数据包后解封,恢复出原始的以太网帧并发送到目标主机。


常规的Overlay方案,如VXLAN,需要额外协议解封装,性能往往较差,如果宿主机之间本身二层互通,可以在宿主机配置路由规则,将宿主机当作容器互通的网关,通过直接转发的方式减少性能损失,如下图。


无论采用哪种模式,避免不了的一个问题是节点和容器是动态加入集群的,如何维护路由表是一项大的挑战,一种方式是利用控制面的etcd来存储和通知,通过在Node上部署的后台进程来更新本地路由,另一种方式是利用路由学习协议,例如BGP(边界网关协议,Border Gateway Protocol),进行路由表数据交换。

容器访问集群外

在这里,容器访问集群外特指访问公网,实际上是私有网络访问公共网络的问题,基本方法也是在当地讲当地话,IP需要在指定域内可路由,一般需要一台能通公网的NAT网关,如下图所示。


集群外访问容器

从前面的内容可以知道,集群外访问容器只要流量能到达宿主机,就有办法可以转到指定容器,这里主要介绍一下NodePort。

NodePort是K8s中的一种服务(Service)类型,它允许通过集群中每个节点的特定端口来访问服务,也就是说NodePort服务会在所有节点上打开一个指定的端口(或随机选择一个端口,如果未指定),任何发往该端口的流量都会被转发到服务后端的Pod。

基本原理如前“Pod访问Service”所述,通过netfilter或eBPF拦截转发,流量示意如上图。

0条评论
0 / 1000
陈一之
20文章数
1粉丝数
陈一之
20 文章 | 1 粉丝
原创

K8s网络基本原理

2024-08-29 02:13:47
117
0

随着IT基础设施的发展,应用的部署形态发生了很大的变化,从集中式到分布式,从物理机部署到虚拟机部署,再到现在的容器化部署,应用间的通信也从经历了从物理机网络,到虚拟机网络,再到容器集群网络的发展过程。

容器技术本质上是一种虚拟化技术,容器网络也依托网络虚拟化技术而呈现丰富的多样性,在这里特别地,指Kubernetes的网络模型。


连通场景

K8s对Pod如何接入网络有着明确规定,简单来说就是每个Pod都有一个IP,而且内部获取和外部通信相同,这就要求一个无需NAT转换的扁平网络,体现在Pod和Node的相互通信上。

在K8s的设计规范里,提出了4个需要解决的网络问题,分别是Container-to-Container、Pod-to-Pod、Pod-to-Service和External-to-Internal。在实际中,由于通信端点所在位置不同(如是否同一主机、是否集群内外)和访问方式不同(如PodIP、ClusterIP、ExternalIP),场景会更多一些。此外,Pod网段、Node网段和Service网段各不相同,也增加了网络连通的复杂性。

上图基于K8s的结构,简要归纳了主要的端到端互联场景,这些场景最终的连通路径和方式可能会有重叠的地方,但作为行为分类有不同的代表意义。
  • 主机内
    • (1)Pod内容器互通
    • (2)主机内Pod互通
    • (3)主机内访问Pod
    • (4)Service的后端节点在相同主机
  • 集群内
    • (5)主机之间互通
    • (6)不同主机Pod互通、Service的后端节点在不同主机
  • 集群外
    • (7)集群内访问集群外服务
    • (8)集群外访问集群内服务

基本原理

网络的拓扑结构一般是个有向图,连通的节点间路径长度不定,所以我们也可以说网络是分段的,分段包含的意思是数据包下一跳被送到哪里,从这个角度来说,需要探明的是什么设备(物理的或虚拟的)承担了怎样的中转(或转发)职能,在这基础上,又还有隔离(如地址、端口冲突)和可见性(如路由转换和IP抓取)问题。

在K8s中,要求Pod有独立IP,实际上是把Pod当作一个小型主机来看待,这也是传统应用迁移到容器的便捷性的一个来源,在网络方面,隔离就是指网络栈的隔离了,网络栈包括有接口、设备、路由表、iptables规则等,主要是通过网络命名空间(Network Namespace)来实现的。

 

Pod内容器互通

每个Pod对应不同的网络命名空间,拥有各自的网络栈,端口相同也不会冲突,IP和MAC地址由逻辑网络管理分配,与同一主机内的情况类似,Pod内的容器通过localhost即可实现互相访问,由虚拟的环回接口(Loopback Interface)转发到对应端口。


 

主机内Pod互通

根据前面网络分段的说法,主机内不同Pod的容器服务之间互通实际也就是主机内的Pod互通,只要流量能到达Pod的虚拟网卡上,自然就能发送到对应端口的容器里。

在传统的分层网络认知里,数据包流转由二层/三层设备根据一定的协议和规则传递,除了网卡(NIC,Network Interface Card/Controller)外,核心设备有交换机(Switch)和路由器(Router),算上逻辑功能还有网桥(Bridge)和网关(Gateway)等,了解虚拟网络很大程度上也就是了解使用哪些虚拟设备。

一般来说,主机内的Pod应该在二层互通,不需要三层路由出去再回来,从物理机的连接方式来说,可以用网线直连两台主机的网卡,也可以通过交换机或网桥来连通,虚拟网络也相应模拟这些行为。

Linux Veth

  • Linux Veth(Virtual Ethernet)是Linux内核中的一种虚拟网络设备,它常用于创建虚拟网络接口对,即Veth Pair,可以将Veth Pair的一端放在一个网络命名空间中,另一端放在另一个网络命名空间中,实现不同命名空间之间的网络通信。

Linux Veth是同一主机内Pod互通的一种基本方式,上图创建了veth-1-a/veth-1-b这一组Veth Pair,两端分别插(设置)到P1和P2网络命名空间(NS)中。形象上有点像用网线把P1和P2这两台带网卡的机器直连了起来,实际上是将Veth设备作为Pod的虚拟网卡,根据Pod CIDR网段设置IP ,流量经由这张网卡时,可以通过ARP协议问询到对端MAC地址,实现数据包传递。

这种点对点的连接方式在多个Pod的场景就不太适用了,多个设备互联一般需要交换机类的角色进行集成中转,Linux内核也有相应的虚拟设备。

Linux Bridge

Linux Bridge是一种在Linux内核中实现的虚拟网络设备,它在数据链路层(二层)上工作,用于连接多个网络接口,包括物理和虚拟接口。


Linux Bridge模拟的是物理交换机的功能,如上图的br0,虚拟网桥设备创建在根网络命名空间(Root NS)下,除了可以连通不同网络命名空间中的Pod,也是容器连接宿主机(Node)网络的桥梁,与前面直连两个Pod不同,这里Veth Pair的另一端连接到虚拟网桥的接口上,就像将网线插在交换机上一样,各个Pod仍可以通过ARP协议实现通信。

MACvlan、IPvlan

MACvlan和IPvlan都是Linux内核中的网络虚拟化技术,它们允许多个虚拟接口共享同一个物理网络接口,简单地理解就是可以把一张物理网卡虚拟成多张子网卡。

MACvlan每个虚拟接口都分配不同的MAC地址,IPvlan每个虚拟接口则与物理接口共享MAC地址,两者没有绝对的替代关系,得看具体网络环境的要求,例如MAC数量限制和IP分配规则等。

MACvlan能提供接近原生物理设备的性能,IPvlan也依赖底层父接口处理ARP等广播报文,三层工作模式下能直接进行路由转发,减少网络栈开销,一般情况下性能均好于单纯的虚拟设备。


MACvlan工作在数据链路层,IPvlan支持二层(L2)和三层(L3)工作模式,另外都还支持不同的类型(mode flags),如bridge、private、VEPA等,总的来说,除了三层必要路由配置外,子接口的连通性归根结底是谁来转发数据包,这个无论是二层还是三层都是类似的。

  • 在bridge模式下,子接口可以直接通信,由父接口承担交换机或路由器的角色,如图绿色线条所示。
  • 其他不支持子接口直接通信的模式,就由父接口将流量转到外部设备,再通过外部设备寻址或路由转发回来,如图蓝色和紫色线条所示。特别地,外部设备不一定是指主机外的设备,主机内部互通使用前面提到的虚拟网桥也可以。

另外,一般情况下交换机和网桥设备是不支持将流量发回同一接口的,例如受生成树协议(STP)的回环限制,在虚拟化场景物理接口存在复用,所以外部二层设备需要打开发卡模式(hairpin mode),允许流量发回同一接口,以保障子接口间能正常通信。

主机内访问Pod

主机内访问Pod也可以说是如何实现宿主机和容器互通,主机网段和容器网段一般来说是不同的,当然也不是强制要求,即使二者的CIDR是相同网段,这个场景也类比于跨网互通,所以问题重点在于连接两边的网关角色。

主机内部也是跨网络命名空间互通场景,基本方式就是找一个既能连通根空间(主机默认的网络命名空间),也能连通容器空间(Pod所在的网络命名空间)的“设备”,并在宿主机和Pod内分别配置跳转路由。


虚拟网桥比物理网桥更灵活,能给它设置IP用作网关,配合路由规则不仅可以实现本机和容器网络互通,也可以实现虚拟网络跨主机互通,如上图绿色线条。

  • Pod内,默认流量经网桥转发,如“default via 10.0.0.1 dev eth0 ……”
  • 主机内,目标为容器的流量经网桥转发,如“10.0.0.0/24 dev br0 ……”

MACvlan和IPvlan的父接口和子接口网络隔离,可以在父接口的网络空间下创建另一个子接口(如上图eth1),通过它来转发实现主机和容器互通(需要bridge模式),主要是从宿主机能到达容器,如上图蓝色线条。

  • 主机内,配置访问容器的路由,如“10.0.0.102 dev eth1 ……”

Pod访问Service

Service可以说是Pod虚拟的负载均衡,也是虚拟的反向代理,访问一个IP实际导向一组后端IP,常规做法是中间人代理模式(例如Nginx),在主机内示意如下图。


中间人模式将原本“客户端-服务器”的连接拆成两段,分别是“客户端-代理”和“代理-服务器”,“实体的中间人”有两个明显的问题,一是会占用端口,需要特别规划避免与业务冲突,二是数据会在用户态和内核态复制,容易导致性能瓶颈。

另外,Service的访问IP是虚拟IP(如ClusterIP),不与任何设备关联,无法监听,中间代理的方案要行得通需要将ServiceIP转成localhost,也就是DNAT(Destination Network Address Translation,目标网络地址转换),这是网络地址转换(NAT)的一种形式,相对的还有SNAT(Source Network Address Translation,源网络地址转换)。

不过,既然DNAT能够修改连接目标,也就没必要多一个代理节点,直接修改成可达的后端Pod地址,再加上负载均衡规则就实现主机访问Service的功能了,这是由内核提供的。

netfilter

netfilter是Linux内核中的一个网络包过滤和处理的框架,所有的流量都会经过当前网络栈的netfilter处理器,其中定义了五个处理节点(钩子,hook points),如下图。


iptables

iptables是netfilter的用户空间接口,用于配置和管理网络数据包,iptables有五个内置的规则表,通常主要使用以下四张表:

  • Filter 表:这是默认的表,用于控制数据包的访问控制,即决定哪些数据包可以进入、离开或穿过系统。它包含三条内置链:INPUTFORWARDOUTPUT
  • NAT 表:用于网络地址转换,它可以在数据包进入(PREROUTING链)、离开(POSTROUTING链)系统或在系统内部路由(OUTPUT链)时修改数据包的源或目的地址。
  • Mangle 表:用于修改数据包的内容,如调整 TTL 值、设置 QoS 标记等。它在数据包的处理流程中的多个点上都有作用,包括 PREROUTINGINPUTFORWARDOUTPUTPOSTROUTING链。
  • Raw 表:用于决定数据包是否被连接跟踪系统跟踪,这通常用于某些需要绕过连接跟踪的场景。它主要在PREROUTINGOUTPUT链上使用。

除了这四张常用的表,还有:

  • Security 表:这是一个较少使用的表,它与 SELinux 集成,用于强制访问控制策略。

对于前述中间人的例子,如果使用iptables来做,就是添加NAT表规则,在OUTPUT链中实现DNAT转换。

iptables的规则匹配是链表式的,时间复杂度为O(n),所以在大规模集群,也就是包含大量规则的情况下,性能可能会受影响。除此之外,集群规则需要推送到每个Node,规则变更的时间复杂度接近O(n2)。

IPVS

IPVS(IP Virtual Server)是一个构建在Linux内核中的高性能负载均衡器,它通过虚拟IP地址(VIP)将网络请求分发到多个后端服务器上,从而实现负载均衡。IPVS也是在netfilter上构建的,设计时面向水平扩展,采用类哈希表的数据结构,查找时间复杂度接近O(1),规则变更复杂度也比iptables相应降低一个量级,性能相对较好。

Service的虚拟IP一般情况下是ping不通的,不过IPVS会创建一个虚拟接口,能够处理ICMP指令,如果采用的是这个模式,Service的虚拟IP就可以ping通。

eBPF

eBPF(Extended Berkeley Packet Filter)是一种革命性的技术,起源于Linux内核,能够在操作系统内核中安全有效地运行沙盒程序。它允许开发者在不更改内核代码的前提下,实时获取和修改操作系统的行为,从而扩展内核的功能。eBPF程序经过内核的验证器校验,确保安全执行,并且可以利用即时编译器(JIT)实现接近直接运行机器码的速度。

eBPF的工作原理基于事件驱动,可以在内核或应用程序经过特定的钩子点时运行程序。这些钩子包括系统调用、函数入口/退出、内核跟踪点、网络事件等,也可以通过创建内核探针(kprobe)或用户探针(uprobe)来附加eBPF程序。

简单来说,eBPF能够通过可编程的方式在内核态植入自定义逻辑,除了扩展性和函数丰富程度外,还有两点明显的优势:

  • eBPF能够在连接级别(socket level)进行NAT,建连后不需要每个包都过滤,对比iptables和IPVS包级别(packet level)的重复拦截,显然性能更好。
  • iptables和IPVS一般配置在宿主机网络命名空间下,Pod访问Service的基本方式是想办法先转到宿主机网络命名空间,再通过netfilter进行地址转换,这种情况下,一方面会多转一次网络协议栈,另一方面对Pod流量不经过宿主机网络空间的连网方式不好支持。eBPF可以配置在任何网络命名空间中,包括宿主机和容器的网络命名空间,相对来说更加灵活。

跨主机Pod互通

网络包的投递方式有点像是邮局,对于民政部门正式确立的官方地址,如“XX市XX区XX街道XX号”,各地邮局能根据系统指引正常中转,邮递员也能准确地送上门,但是对于当地某些非正式的地址,如“XX村XX山北面王二家”,就得依靠熟识的老乡带路才行了。

主机内的容器互通是靠官方还是要靠老乡,对应Underlay和Overlay两种不同的网络方案。

  • Underlay网络:Underlay网络就是我们理解的传统网络,也是物理网络,通过物理或光纤电缆连接网络设备和服务器,包括交换机和路由器等设备,借助以太网协议、路由协议和VLAN协议等驱动。
  • Overlay网络:Overlay网络是建立在现有的Underlay网络之上的一种虚拟网络技术,通过在物理网络上封装数据包,能够创建一个分离的、逻辑上的网络层。

不难想象,Underlay方案性能更好,但对物理网络有侵入,Overlay方案则相反,主要对比如下。

方案

underlay

overlay

实现

  • MACvlan
  • IPvlan
  • VXLAN
  • IPIP

优点

  • 性能较好
  • 网络流量可精确管理、监控
  • 对物理网络无侵入
  • 网络管理相对简单

缺点

  • 对当前组网有侵入
  • 占用现网IP,需规划
  • 维护和管理较复杂
  • 容器网络较难监控
  • 容器对外需要通过Node SNAT,较难精确管理流量

其中,VXLAN(Virtual Extensible LAN,虚拟可扩展局域网)是一种网络虚拟化技术,它通过在现有的IP网络上创建虚拟网络,允许数据中心实现大规模的网络隔离和扩展。VXLAN使用MAC-in-UDP封装技术,将第二层的以太网帧封装在第三层的IP包中,实现跨越物理网络边界的虚拟网络通信。

VXLAN的核心组件包括VTEP(VXLAN Tunnel Endpoint,VXLAN隧道终端),它负责封装和解封VXLAN数据包,以及VXLAN隧道,即VTEP之间的逻辑通道用于传输VXLAN数据包。VXLAN数据包结构包括外层以太网头、外层IP头、外层UDP头、VXLAN头(包含VNI和其他控制信息)和内层以太网帧。

VXLAN的工作原理是,当主机发送数据包时,源VTEP将数据包封装在VXLAN头和外层IP、UDP头中,然后发送到目标VTEP。封装后的VXLAN数据包通过物理网络传输,目标VTEP接收到数据包后解封,恢复出原始的以太网帧并发送到目标主机。


常规的Overlay方案,如VXLAN,需要额外协议解封装,性能往往较差,如果宿主机之间本身二层互通,可以在宿主机配置路由规则,将宿主机当作容器互通的网关,通过直接转发的方式减少性能损失,如下图。


无论采用哪种模式,避免不了的一个问题是节点和容器是动态加入集群的,如何维护路由表是一项大的挑战,一种方式是利用控制面的etcd来存储和通知,通过在Node上部署的后台进程来更新本地路由,另一种方式是利用路由学习协议,例如BGP(边界网关协议,Border Gateway Protocol),进行路由表数据交换。

容器访问集群外

在这里,容器访问集群外特指访问公网,实际上是私有网络访问公共网络的问题,基本方法也是在当地讲当地话,IP需要在指定域内可路由,一般需要一台能通公网的NAT网关,如下图所示。


集群外访问容器

从前面的内容可以知道,集群外访问容器只要流量能到达宿主机,就有办法可以转到指定容器,这里主要介绍一下NodePort。

NodePort是K8s中的一种服务(Service)类型,它允许通过集群中每个节点的特定端口来访问服务,也就是说NodePort服务会在所有节点上打开一个指定的端口(或随机选择一个端口,如果未指定),任何发往该端口的流量都会被转发到服务后端的Pod。

基本原理如前“Pod访问Service”所述,通过netfilter或eBPF拦截转发,流量示意如上图。

文章来自个人专栏
学而时习
20 文章 | 1 订阅
0条评论
0 / 1000
请输入你的评论
2
2