You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

如何用eBPF代码从cgroup v1中获取容器ID?(task_struct尝试失败)

在eBPF中通过task_struct获取cgroup v1容器ID的解决方法

先排查task_struct->cgroups为0的问题

  • 内核结构定义不匹配:你用的task_struct定义可能和目标内核版本的实际结构不一致,导致cgroups字段的偏移错误,读出来的值为0。解决方法:用bpftool btf dump file /sys/kernel/btf/vmlinux format c | grep -A 30 'struct task_struct'获取内核真实的task_struct结构,确保代码中cgroups字段的位置正确;或者使用bpf_core_read系列函数安全读取字段,避免硬编码偏移(推荐)。
  • 内核配置问题:确认内核开启了CONFIG_CGROUPS选项,cgroup v1依赖该配置,关闭的话task_struct->cgroups会始终为0。

正确的容器ID获取流程(cgroup v1)

容器ID通常嵌入在cgroup的路径中(比如Docker的/docker/<container-id>),需要从task关联的cgroup中解析路径:

核心eBPF代码示例(适配5.x内核,需根据实际内核调整结构体)

#include <linux/bpf.h>
#include <bpf/bpf_helpers.h>
#include <linux/sched.h>

// 仅定义需要的结构体字段,避免全量定义导致偏移错误
struct task_struct {
    struct cgroup __rcu *cgroups;
};

struct cgroup {
    struct cgroup_subsys_state *dfl_cgrp;
    struct dentry *dentry;
};

struct cgroup_subsys_state {
    struct cgroup *cgrp;
};

struct dentry {
    struct qstr d_name;
    struct dentry *d_parent;
};

struct qstr {
    const unsigned char *name;
    unsigned int len;
};

SEC("tracepoint/sched/sched_process_exec")
int trace_exec(struct trace_event_raw_sched_process_exec *ctx) {
    struct task_struct *task = (struct task_struct *)bpf_get_current_task();
    struct cgroup *cgrp;
    struct dentry *dentry;
    char path[256] = {0};
    int pos = sizeof(path) - 1;

    // 安全读取cgroups字段
    struct cgroup *cgroups;
    bpf_core_read(&cgroups, sizeof(cgroups), &task->cgroups);
    if (!cgroups)
        return 0;

    // 获取默认cgroup的css
    struct cgroup_subsys_state *css;
    bpf_core_read(&css, sizeof(css), &cgroups->dfl_cgrp);
    if (!css)
        return 0;

    // 获取cgroup结构体
    bpf_core_read(&cgrp, sizeof(cgrp), &css->cgrp);
    if (!cgrp)
        return 0;

    // 获取cgroup对应的dentry
    bpf_core_read(&dentry, sizeof(dentry), &cgrp->dentry);
    if (!dentry)
        return 0;

    // 遍历dentry拼接路径
    struct dentry *curr = dentry;
    while (curr && curr->d_parent != curr) {
        struct qstr name;
        bpf_core_read(&name, sizeof(name), &curr->d_name);
        if (pos - name.len - 1 < 0)
            break;

        pos -= name.len;
        bpf_core_read(path + pos, name.len, name.name);
        pos -= 1;
        path[pos] = '/';

        bpf_core_read(&curr, sizeof(curr), &curr->d_parent);
    }

    // 解析Docker容器ID(根据实际运行时调整路径匹配规则)
    char *docker_prefix = __builtin_strstr(path, "/docker/");
    if (docker_prefix) {
        char *container_id = docker_prefix + 8; // 跳过"/docker/"
        bpf_printk("Container ID: %s", container_id);
    }

    return 0;
}

char _license[] SEC("license") = "GPL";

关键注意事项

  • 内核兼容性:不同内核版本的cgroup结构体字段名/偏移可能变化,必须用bpf_core_read(依赖BTF)或者动态获取偏移,避免硬编码。
  • 容器运行时适配:不同容器运行时的cgroup路径不同,比如containerd的路径是/containerd/io.containerd.runtime.v1.linux/moby/<id>,需要调整路径匹配逻辑。
  • 权限与内核参数:运行eBPF程序需要CAP_PERFMON/CAP_BPF权限,非特权用户需确保kernel.unprivileged_bpf_disabled=0。

内容的提问来源于stack exchange,提问作者谭瑞星

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.07.11 16:33:28