互联网的本质就是一系列的网络协议,按照功能不同,分工不同,其常被分为七层、五层、四层网络结构。七层,五层、四层的概念,只是人为的划分而已,是为了区分出哪一层是干什么用的。
今天咱们主要讲“四层网络协议”,该协议族中最核心的两个协议分别为 TCP(传输控制协议)和 IP(网际协议),因此它也被称为 TCP/IP 协议族,它具有四层网络结构 :应用层、传输层、网络层、网络接口层。
![在这里插入图片描述](https://img-blog.csdnimg.cn/20190105164025264.png?x-oss-process=image/watermark,type_ZmFuZ3poZW5naGVpdGk,shadow_10,text_aHR0cHM6Ly9ibG9nLmNzZG4ubmV0L3FxXzQxOTIzNjIy,size_16,color_FFFFFF,t_70)
eBPF是一个能够在内核运行沙箱程序的技术,提供了一种在内核事件和用户程序事件发生时安全注入代码的机制,使得非内核开发人员也可以对内核进行控制。本片就将提供一种基于 eBPF 的网络监测实践。
工具
工具名称:DataKit
DataKit是 “观测云” 开源的、一体式的数据采集 Agent,提供全平台操作系统支持,拥有全面数据采集能力,涵盖基础设施、指标、日志、应用性能、用户访问以及安全巡检等各种场景。通过引入 eBPF 技术,DataKit 实现了网络传输层和应用层的部分协议的可观测。
开源地址:https://github.com/GuanceCloud/datakit
DataKit 采集器架构
- 采集管理:配置加载模块用于配置动态管理与采集插件的开启关闭;监视器模块用于查看采集器资源使用、采集插件开启、数据处理器脚本工作状况、采集器外部数据接入API 的响应与延迟信息等
- 数据采集:采集器不仅可以通过内置插件进行数据采集,还能接入外部数据源,如云原生计算基金会下的可观测项目 OTEL 的链路、指标数据等
- 数据清洗:在采集插件生成数据后和数据上传之间的数据清洗层,用户可以通过编程介入,如使用可编程数据处理器的语言编写脚本修改 Point ,使用内置函数分析提取网络数据中 IP 归属的城市、省份和国家到 Point 中;脚本支持动态加载和卸载
- 数据上传:采集器对各种数据进行分类上传,类别有日志、指标、链路、网络等,所有类别的数据均使用 Point 结构封装,每一个 Point 代表一条数据,大致由四个部分:名字、 标签字典、字段字典以及时间戳构成 (其名字可以是指标名 cpu, 日志来源 nginx ,网络的 httpflow等)
eBPF 技术应用
DataKit 采集器使用了三种类型的 eBPF 程序:socket filter、kprobe、uprobe,能够抓取以太网帧、跟踪与 socket 和 TCP/IP 协议栈相关的内核函数以及用户共享库函数,实现网络协议可观测。下图介绍 DataKit 采集器如何实现 eBPF 技术进行主机上的网络观测。
以上示意图自上而下被分为了用户空间和内核空间两部分。操作系统内核运行在内核空间;用户应用程序运行在用户空间,用户空间的程序通常无法直接访问内核空间的内存。
上图的左侧,以 OSI 七层网络模型为参考,传入的网络数据包从第二层的链路层到第三层的网络层,再到第四层的传输层,这一过程数据包通常由内核传递和处理。而应用层协议如 HTTP 等将交由用户空间应用处理。
上图中的 BSD Socket 联系用户空间和内核空间,用户空间应用可通过创建不同的套接字来获取从链路层、网络层、传输层的网络数据包。
DataKit 采集器通过创建套接字地址族为 AF_PACKET 的原始套接字来抓取链路层数据包即以太帧,以太帧包含源和目标的 MAC 地址、网络层的 IP 地址、传输层的端口号以及上层的数据。对于应用层 HTTP 和 DNS 协议,通过加载 socket filter 类型 eBPF 程序过滤出 HTTP 或 DNS 协议数据包。在这一过程中直接通过 eBPF 程序在内核中解析以太帧中的应用层 HTTP 协议数据中的 HTTP 头,以获取 HTTP 请求路径、HTTP 状态码等信息。而对于 DNS 协议,在 DataKit 采集器内解析获取到数据包,收集 DNS 请求响应信息和 DNS 状态码。
由于 HTTPS 协议使用 HTTP 协议进行通信,但是经过 SSL/TLS 加密,其数据包在抵达传输层之前就已经完成了对应用层的 HTTP 数据的加密;使用 uprobe 类型程序跟踪用户空间的某些用于 TLS 加解密的共享库中的函数,如 ssl_read 输入于返回来获取 HTTP 协议数据,这样可以在 HTTP 协议数据被加密前和解密后进行协议解析。
上图的右侧为 DataKit 采集器使用 kprobe 类型程序跟踪的 socket 、TCP/IP 协议栈等相关内核函数来观测传输层协议,通过 inet_bind 函数判断某个端口是否被应用所监听,并通过跟踪其他的内核函数来获取 tcp和 udp 协议的收发字节数和 tcp 协议的重传、时延等信息。
数据采集
DataKit 采集器的 eBPF 网络观测功能采集并生成了三个数据集,分别为 netflow, dnsflow 和 httpflow,其 tag 基本相同,以下是其 tag 名与描述。
Tag 名 | 描述 |
src_ip | 源 IP |
dst_ip | 目标 IP |
src_port | 源端口 |
dst_port | 目标端口 |
transport | tcp 或 udp |
family | IPv4 或 IPv6 |
direction | 传输方向(incoming/outgoing) |
src_ip_type | 源 IP 类型 (other/private/multicast) |
dst_ip_type | 目标 IP 类型 (other/private/multicast) |
host | 主机名 |
source | 数据源(netflow,httpflow,dnsflow) |
pid | 进程 id,仅 netflow |
dst_domain | 仅 netflow,来自 dnsflow 抓包记录 |
src_k8s_namespace | 源 service 归属的 namespace |
src_k8s_deployment_name | 源 serivce 归属的 deployment |
src_k8s_service_name | 源 service |
src_k8s_pod_name | 源 pod |
dst_k8s_namespace | 目标 service 归属的 namespace |
dst_k8s_deployment_name | 目标 serivce 归属的 deployment |
dst_k8s_service_name | 目标 service |
dst_k8s_pod_name | 目标 pod |
sub_source | 子来源,默认 N/A,如若为 Kubernetes 流量则为 K8s。 |
传输层网络观测
- 采集器使用 kprobe 类型 eBPF 程序获取部分内核函数的输入与返回值
- 通过 inet_bind(6) 函数判断 src_ip + src_port 是否为服务端
- 通过协议栈 tcp\udp 以及 ip 相关的内核函数,获取服务与客户端之间的流量大小以及 TCP 协议的连接的建立与关闭次数、重传和 RTT 信息
Field 名 | 描述 |
bytes_read | 接收字节数 |
bytes_written | 发送字节数 |
retransmits | 重传次数 |
rtt | rtt |
rtt_var | rtt_var |
tcp_closed | TCP 连接关闭次数 |
tcp_established | TCP 连接建立次数 |
应用层网络观测
- 采集器使用 AF_PACKET + BPF 在采集器上分析 DNS 请求,以支持 CentOS(RedHat)7.6 (其不支持 socket filter 类型 eBPF 程序),记录请求信息支持 netflow 进行域名反向解析;
- 对于 HTTP 请求使用 socket filter 和 uprobe 类型 eBPF 程序实现 HTTP(S) 请求分析。
下面的为采集 dns 协议生成的字段 和 http 协议生成字段。
Field 名(dns) | 描述 |
count | 一个采集周期内的请求总数 |
latency | DNS 平均请求响应时间间隔 |
latency_max | DNS 最大请求的响应时间间隔 |
rcode | DNS 响应码: 0 - NoError, 1 - FormErr, 2 - ServFail, 3 - NXDomain, 4 - NotImp, 5 - Refused, ... |
Field 名(http) | 描述 |
count | 一个采集周期内的请求总数 |
http_version | 1.1 / 1.0 ... |
latency | TTFB |
method | GET/POST... |
path | 请求路径 |
status_code | 状态码,如 200, 301, 404 ... |
truncated | 请求路径长度达到采集的(约 150)字节上限,存在截断可能 |
用户地理分布及 TCP 时延
通过内置数据处理器编写脚本,来解析 ip 并获取 ip 归属的省份、国家等信息作为标签追加到生成的 Point 上,在观测云创建仪表板,可通过下图的世界地图和中国地图展示 netflow 中客户端 ip 的地理分布和服务端之间的 tcp 时延。
主机间四层网络拓扑
下图为部署了 DataKit 采集器并开启了 eBPF 网络采集器的主机间的网络拓扑图,图上我们可以看到主机间的数据发送与接受的字节数和网络波动等信息。
K8S Pod 间网络拓扑
当 eBPF 采集插件获取到 K8S 的 ip 和端口信息后将自动追加到生成的数据上,通过观测云可构建不同的网络拓扑图,下图是构建的 Pod 网络拓扑关系图。
K8S Deployment 间网络拓扑
下图是构建的 Deployment 网络拓扑图,从图中可以看到 nginx deployment 上的 HTTP 协议的每秒请求数和请求错误率。