作者:张晓辉 2023-03-27 00:13:26
云计算
云原生 统计一下在三个场景中,经过内核网络协议栈的处理次数都是两次(包括 netfilter 的处理。),即使是同 pod 或者同节点内。而这两种情况实际都发生在同一个内核空间中。
成都创新互联公司是专业的铜鼓网站建设公司,铜鼓接单;提供网站设计制作、网站制作,网页设计,网站设计,建网站,PHP网站建设等专业做网站服务;采用PHP框架,可快速的进行铜鼓网站开发网页制作和功能扩展;专业做搜索引擎喜爱的网站,专业的做网站团队,希望更多企业前来合作!
网络和操作系统内核,对我来说是既陌生又满是吸引,希望能够拨开层层迷雾找到背后的真相。
在 上一篇文章 中我深入探讨了 Kubernetes 网络模型,这次我想更深入一点:了解数据包在 Kubernetes 中的传输,为学习 Kubernetes 的 eBPF 网络加速做准备,加深对网络和操作系统内核的理解。 文中可能有疏漏之处,还望大家赐教。
在开始之前,我可以用一句话来总结我的学习成果:数据包的流转其实就是一个网络套接字描述符(Socket File Descriptor,中文有点冗长,以下简称 socket fd)的寻址过程。 它不是简单的指 socket fd 的内存地址,还包括它的网络地址。
在 Unix 和类 Unix 系统中,一切皆文件,也可以通过文件描述符来操作 socket。
既然要讨论数据包的流转,先看看什么是数据包。
网络数据包(network packet),也称为网络数据报(network datagram)或网络帧(Network frame),是通过计算机网络传输的数据单位。拿最常见的 TCP 数据包来看包含如下几个部分:
这里没有介绍的 checksum 和 FCS 通常是用来检查数据包在传输过程中是否被篡改或者发生了错误。
应用程序使用 socket 向网络发送数据的过程可以简单理解为使用头信息封装数据的过程:TCP 数据包、IP 数据包、Ethernet 数据包;反过来,从网络接收以太网数据包到应用程序可以处理的数据,就是解包的过程。封包和解包的过程是由内核网络协议栈来完成的。
下面分别说一下 socket 和内核网络协议栈的处理。
Socket 是一种在计算机网络中使用的编程接口,位于用户空间(用户应用程序运行的空间)和内核网络协议栈(内核中对数据进行封包和解包的组件)之间。
作为编程接口,socket 提供了如下操作(只列出部分):
通过下面的图,可以直观感受各个操作的作用:
开始讲解内核网络协议栈之前,先说下数据包在内存中的数据结构:sk_buff[1]。
sk_buff 是 Linux 内核中用于管理网络数据包的数据结构,它包含了接收和发送的网络数据包的各种信息和属性,如数据包的协议、数据长度、源和目标地址等。sk_buff 是一种可以在网络层和数据链路层之间传递的数据结构,可以被用于所有类型的网络协议栈,例如 TCP/IP、UDP、ICMP 等。
sk_buff 在 Linux 内核中广泛应用于网络协议栈的各个层级,如数据链路层、网络层、传输层等。sk_buff 数据结构的字段很多,有 4 个重要的字段且都是指针类型。sk_buff 在不同层的使用,就是通过修改这些指针来完成的:加 header (封包)和移除 header(解包)。
这个过程操作做的是指针,数据是零拷贝的,可以极大地提升效率。
应用程序使用 socket 的 sendmsg 操作发送数据(这里不深入讲解 netfilter、traffic control、queue discipline):
NIC 收到网络发来的数据包(这里不深入讲解 direct memory access、netfilter、traffic control):
另一部分的基础知识就是 Kubernetes 的网络模型了,可以参考之前的那篇 深入探索 Kubernetes 网络模型和网络通信。
这里继续讨论之前文章中的三种通信场景,pod 间的通信使用 pod IP 地址。如果要讨论通过 Service 来访问,则要加入 netfilter 的讨论篇幅会增加不少。
pod 内两个容器间的方式通常使用回环地址 127.0.0.1,在封包的 #4 路由过程中确定了使用回环网卡 lo进行传输。
curl 发出的请求在封包 #4 过程中确定使用 eth0 接口。然后通过与 eth0 相连的隧道 veth1 到达节点的根网络空间。
veth1 通过网桥 cni0 与其他 pod 相连虚拟以太接口 vethX 相连。在封包 #10 L2 寻址中,ARP 请求通过网桥发送给所有相连的接口是否拥有原始请求中的目的 IP 地址(这里是 10.42.1.9)
拿到了 veth0 的 MAC 地址后,在封包 #11 中设置数据包的链路层信息。数据包发出后,经过 veth0 隧道进入 pod httpbin 的 eth0 接口中,然后开始解包的过程。
解包的过程没啥特别,确定了 httpbin 使用的 socket。
这里稍微不同,就是在通过 cni0 发送 ARP 请求没有收到应答,使用根命名空间也就是主机的路由表,确定了目标主机 IP 地址后,然后通过主机的 eth0 放 ARP 请求并收到目标主机的响应。将其 MAC 地址在封包 #11 中写入。
数据包发送到目标主机后,开始解包的过程,最终进入目标 pod。
在集群层面有一张路由表,里面存储着每个节点的 Pod IP 网段(节点加入到集群时会分配一个 Pod 网段(Pod CIDR),比如在 k3s 中默认的 Pod CIDR 是 10.42.0.0/16,节点获取到的网段是 10.42.0.0/24、10.42.1.0/24、10.42.2.0/24,依次类推)。通过节点的 Pod IP 网段可以判断出请求 IP 的节点,然后请求被发送到该节点。
统计一下在三个场景中,经过内核网络协议栈的处理次数都是两次(包括 netfilter 的处理。),即使是同 pod 或者同节点内。而这两种情况实际都发生在同一个内核空间中。
假如同一个内核空间中的两个 socket 可以直接传输数据,是不是就可以省掉内核网络协议栈处理带来的延迟?
下篇继续。
[1] sk_buff: https://elixir.bootlin.com/linux/latest/source/include/linux/skbuff.h#L843
本文标题:追踪Kubernetes中的数据包
URL网址:http://www.shufengxianlan.com/qtweb/news28/78.html
网站建设、网络推广公司-创新互联,是专注品牌与效果的网站制作,网络营销seo公司;服务项目有等
声明:本网站发布的内容(图片、视频和文字)以用户投稿、用户转载内容为主,如果涉及侵权请尽快告知,我们将会在第一时间删除。文章观点不代表本网站立场,如需处理请联系客服。电话:028-86922220;邮箱:631063699@qq.com。内容未经允许不得转载,或转载时需注明来源: 创新互联