WEBKT

巧用 eBPF 追踪 Docker 容器网络流量,带宽监控不再难

24 0 0 0

前言

什么是 eBPF?

为什么选择 eBPF 追踪 Docker 容器网络?

实战:使用 eBPF 追踪 Docker 容器网络流量

1. 准备工作

2. 编写 eBPF 程序

3. 运行 eBPF 程序

4. 结果分析

进阶:更复杂的 eBPF 程序

总结

扩展阅读

前言

在云原生时代,Docker 容器已经成为应用部署的标配。然而,容器内部的网络流量监控一直是个难题。传统的监控方法,要么侵入性强,需要修改容器内部配置;要么效率低下,难以实时追踪。有没有一种方法,既能精确追踪容器的网络流量,又能避免侵入式修改呢?答案是肯定的,那就是 eBPF (Extended Berkeley Packet Filter)。

什么是 eBPF?

eBPF 最初是 Linux 内核中的一个包过滤工具,后来被扩展成一个通用的内核虚拟机。它允许用户在内核中安全地运行自定义代码,而无需修改内核源码或加载内核模块。eBPF 程序可以被附加到内核的各种事件点上,例如网络接口、系统调用、函数入口等,从而实现对系统行为的监控和分析。

简单来说,你可以把 eBPF 看作一个内核中的“探针”,它可以实时地收集和分析系统数据,而不会对系统性能产生明显的影响。

为什么选择 eBPF 追踪 Docker 容器网络?

  • 高性能: eBPF 程序运行在内核态,可以直接访问内核数据,避免了用户态和内核态之间的数据拷贝,性能非常高。
  • 安全性: eBPF 程序在加载到内核之前,会经过严格的验证,确保不会对系统造成危害。
  • 灵活性: eBPF 程序可以使用多种编程语言编写,例如 C、Go 等,可以根据需要定制监控逻辑。
  • 非侵入性: eBPF 程序不需要修改容器内部配置,即可实现对容器网络流量的监控。

实战:使用 eBPF 追踪 Docker 容器网络流量

接下来,我们通过一个简单的例子,演示如何使用 eBPF 追踪 Docker 容器的网络流量。

1. 准备工作

  • 安装 BCC: BCC (BPF Compiler Collection) 是一个用于编写和调试 eBPF 程序的工具集。你可以从 BCC 的官方网站 (https://github.com/iovisor/bcc) 下载并安装。

  • 安装 Docker: 确保你的系统上已经安装了 Docker。

  • 运行一个 Docker 容器: 运行一个你需要监控的 Docker 容器。例如,我们可以运行一个 Nginx 容器:

    docker run -d -p 8080:80 nginx
    

2. 编写 eBPF 程序

下面是一个简单的 eBPF 程序,用于统计指定 Docker 容器的网络流量:

# /usr/share/bcc/examples/networking/container_netflow.py
from bcc import BPF
import sys
import argparse
# 定义命令行参数
parser = argparse.ArgumentParser(
description="Trace network flow of a specific Docker container"
)
parser.add_argument("-p", "--pid", type=int, help="PID of the container")
args = parser.parse_args()
if not args.pid:
print("Please specify the PID of the container using -p or --pid")
sys.exit(1)
container_pid = args.pid
# 定义 eBPF 程序
program = '''
#include <uapi/linux/ptrace.h>
#include <net/sock.h>
#include <net/inet_sock.h>
#include <linux/bpf.h>
BPF_HASH(flow_bytes, u32, u64);
int kprobe__tcp_sendmsg(struct pt_regs *ctx, struct sock *sk, struct msghdr *msg, size_t size)
{
u32 pid = bpf_get_current_pid_tgid() >> 32;
// 过滤指定 PID 的容器
if (pid == CONTAINER_PID) {
u64 bytes = size;
u64 zero = 0;
u64 *value = flow_bytes.lookup_or_init(&pid, &zero);
*value += bytes;
}
return 0;
}
int kprobe__tcp_cleanup_rbuf(struct pt_regs *ctx, struct sock *sk, int copied)
{
u32 pid = bpf_get_current_pid_tgid() >> 32;
// 过滤指定 PID 的容器
if (pid == CONTAINER_PID) {
u64 bytes = copied;
u64 zero = 0;
u64 *value = flow_bytes.lookup_or_init(&pid, &zero);
*value += bytes;
}
return 0;
}
'''
# 替换 CONTAINER_PID
program = program.replace('CONTAINER_PID', str(container_pid))
# 加载 eBPF 程序
bpf = BPF(text=program)
# 打印表头
print("Tracing network flow for container PID: %d" % container_pid)
print("%-10s %-10s" % ("PID", "BYTES"))
# 循环打印数据
try:
while True:
for k, v in bpf["flow_bytes"].items():
print("%-10d %-10d" % (k.value, v.value))
bpf["flow_bytes"].clear()
sleep(1)
except KeyboardInterrupt:
exit()

代码解释:

  • BPF_HASH(flow_bytes, u32, u64):定义一个哈希表,用于存储每个 PID 对应的网络流量。
  • kprobe__tcp_sendmsg:这是一个 kprobe,它会在 tcp_sendmsg 函数被调用时触发。tcp_sendmsg 函数用于发送 TCP 数据。
  • kprobe__tcp_cleanup_rbuf:这是一个 kprobe,它会在 tcp_cleanup_rbuf 函数被调用时触发。tcp_cleanup_rbuf 函数用于接收 TCP 数据。
  • bpf_get_current_pid_tgid() >> 32:获取当前进程的 PID。
  • flow_bytes.lookup_or_init(&pid, &zero):在哈希表中查找 PID 对应的网络流量,如果不存在则初始化为 0。
  • *value += bytes:累加网络流量。

3. 运行 eBPF 程序

首先,你需要找到 Docker 容器的 PID。可以使用 docker inspect 命令来获取:

docker inspect <container_id> | grep Pid

然后,运行 eBPF 程序,并将容器的 PID 作为参数传递给它:

sudo python /usr/share/bcc/examples/networking/container_netflow.py -p <container_pid>

程序会实时打印出容器的网络流量,包括发送和接收的字节数。

4. 结果分析

通过 eBPF 程序,我们可以实时地监控 Docker 容器的网络流量。我们可以将这些数据用于以下用途:

  • 性能分析: 了解容器的网络瓶颈,优化网络配置。
  • 安全监控: 检测异常的网络流量,例如 DDoS 攻击。
  • 资源管理: 限制容器的网络带宽,避免资源滥用。

进阶:更复杂的 eBPF 程序

上面的例子只是一个简单的演示。实际上,eBPF 可以用于实现更复杂的网络监控功能,例如:

  • 追踪特定端口的流量: 只监控容器与特定端口之间的流量。
  • 分析网络协议: 解析网络数据包,获取协议类型、源 IP 地址、目标 IP 地址等信息。
  • 统计网络延迟: 测量容器与外部服务之间的网络延迟。

这些更复杂的功能需要编写更复杂的 eBPF 程序,并使用更高级的 eBPF 特性,例如 tail call、map-in-map 等。

总结

eBPF 是一种强大的网络监控工具,它可以帮助我们深入了解 Docker 容器的网络行为。通过编写 eBPF 程序,我们可以实现各种定制化的网络监控功能,而无需修改容器内部配置。希望本文能够帮助你入门 eBPF,并在实际工作中应用它来解决网络监控问题。

扩展阅读

容器观测者 eBPFDocker网络监控

评论点评

打赏赞助
sponsor

感谢您的支持让我们更好的前行

分享

QRcode

https://www.webkt.com/article/10156