使用eBPF技术监控ACS容器状态

本文介绍利用eBPF技术无侵入地获得容器性能数据、内核Trace数据或网络指标数据等,从而快速发现目标容器和关联的Pod存在的性能问题。

背景信息

eBPF(Extended Berkeley Packet Filter)是一项运行沙箱程序的技术,允许开发者在操作系统内核内安全运行自定义代码,并即时获得执行结果,而无需修改内核源代码或加载内核模块,从而避免复杂的运维操作。

Kubernetes生态中,eBPF的主要应用场景有:

  • 网络管理:Cilium网络插件,可以灵活更新网络策略并实施流量转发。

  • 故障定位与事件追踪:使用Falco等工具实时监控Kubernetes集群中容器的系统调用和访问行为,帮助运维人员及时发现安全风险。

  • 安全监控:在入侵检测中,如端口扫描,一旦检测到异常行为,eBPF程序能够阻止数据包传输并隔离受攻击的容器,最大限度减少安全风险。

  • 性能监控:Sysdig等工具提供性能和故障诊断,监控集群或单机的性能数据。

eBPF的运行分为用户态(User Space)和内核态(Kernel Space):

  • 用户态:通常是用于编写和加载eBPF程序的应用程序。您可以使用如C语言等编写eBPF程序,并通过工具(如bpftool,libbpf等)将其加载到内核中。

  • 内核态:eBPF程序被加载并实际执行的环境。eBPF程序在内核态中运行,可以直接访问内核数据结构和接口,进行特定的监控与处理工作。

image

对此,ACS提供了基于eBPF的可观测能力,您可以在Pod/sys/kernel/debug目录下配置监控项和指标,实现对细粒度数据的监控,帮助您优化性能和排查故障。

前置条件

已为ACS Pod开启特权模式。

说明

ACS默认不提供开启特权模式的入口, 请提交工单申请。

应用示例

以下演示eBPF程序在实际ACS容器算力环境下的使用。本示例的镜像中使用了社区开源的Go语言框架eBPF工具软件ebpf-go,ebpf-go包含了多个示例应用。关于此示例基础镜像的详细信息,请参见相关信息

以其中的fentry eBPF程序为例,将fentry eBPF程序加载到容器的tcp_connect上。当容器向目标发送TCP SYN数据包时,eBPF会打印出对应的命令/IP/端口信息。

  1. 使用以下YAML内容,创建名为acs-test-ebpf-demo的工作负载。具体操作,请参见创建无状态工作负载Deployment

    apiVersion: apps/v1
    kind: Deployment
    metadata:
      labels:
        app: acs-test-ebpf-demo
      name: acs-test-ebpf-demo
      namespace: default
    spec:
      progressDeadlineSeconds: 600
      replicas: 1
      selector:
        matchLabels:
          app: acs-test-ebpf-demo
      strategy:
        rollingUpdate:
          maxSurge: 25%
          maxUnavailable: 25%
        type: RollingUpdate
      template:
        metadata:
          labels:
            alibabacloud.com/compute-class: general-purpose
            alibabacloud.com/compute-qos: default
            app: acs-test-ebpf-demo
        spec:
          containers:
          - command:
            - /bin/sh
            - -c
            - sleep 36000
            image: registry-cn-hangzhou.ack.aliyuncs.com/acs/ebpf-example:v1-alpha
            imagePullPolicy: Always
            name: test-ebpf
            resources:
              requests:
                cpu: "2"
                memory: 4Gi
            securityContext:
              capabilities:
                add:
                - SYS_ADMIN
                - NET_ADMIN
                - NET_RAW
                - SYS_RESOURCE
                - SYS_PTRACE
                - IPC_LOCK
                - SYSLOG
            volumeMounts:
            - mountPath: /sys/kernel/debug
              name: volume-debugfs
              readOnly: true
          restartPolicy: Always
          volumes:
          - emptyDir: {}
            name: emptydir-volume
          - hostPath:
              path: /sys/kernel/debug
              type: ""
            name: volume-debugfs

    部分配置项说明如下:

    配置项

    说明

    .spec.template.volume.hostPath

    指定需要挂载的路径。

    .spec.template.container.volumeMounts

    设置挂载的路径在容器内的目标路径。

    .spec.template.container.securityContext.capabilities.add

    设置挂载的eBPF对所依赖路径需要具备的权限。

    SYS_ADMIN:允许执行许多系统管理操作,是非常高风险的能力。

    NET_ADMIN:允许进行网络管理操作,例如更改网络接口的状态、修改路由表等。

    NET_RAW:允许容器直接使用原始套接字(raw socket)。

    SYS_RESOURCE:允许进程修改系统资源限制。

    SYS_PTRACE:允许监控其他进程。

    IPC_LOCK:允许进程锁定内存页。

    SYSLOG:允许对系统日志写入。

    重要

    上述示例中展示了多个可用的高风险权限,仅供测试使用。在生产环境,建议您遵循最小权限原则,只添加必要的能力。错误的配置可能会增加安全风险。

  2. 执行以下命令,进入容器。

    kubectl exec -it deploy/acs-test-ebpf-demo -- bash

    查看挂载的目录。

    cd /sys/kernel/debug && ls -al

    预期输出:

    drwx------ 37 root root 0 Dec 17 08:30 .
    drwxr-xr-x 15 root root 0 Dec 17 08:30 ..
    drwxr-xr-x  2 root root 0 Dec 17 08:30 acpi
    drwxr-xr-x  4 root root 0 Dec 17 08:30 bdi
    drwxr-xr-x  4 root root 0 Dec 17 08:30 block
    ...
    drwxr-xr-x  3 root root 0 Dec 17 08:30 zram
    drwxr-xr-x  2 root root 0 Dec 17 08:30 zsmalloc
    drwxr-xr-x  2 root root 0 Dec 17 08:30 zswap

    可以看到挂载正常。

  3. 进入示例应用目录。

    cd /app/ebpf && ls

    预期输出:

    CODEOWNERS          attachtype_string.go  docs                               fuzz_test.go     linker.go                  perf              types.go
    CODE_OF_CONDUCT.md  btf                   elf_reader.go                      go.mod           linker_test.go             prog.go           types_string.go
    CONTRIBUTING.md     cmd                   elf_reader_test.go                 go.sum           map.go                     prog_test.go      variable.go
    LICENSE             collection.go         elf_sections.go                    helpers_test.go  map_test.go                ringbuf           variable_test.go
    MAINTAINERS.md      collection_test.go    example_sock_elf_test.go           info.go          marshaler_example_test.go  rlimit
    Makefile            cpu.go                example_sock_extract_dist_test.go  info_test.go     marshalers.go              syscalls.go
    README.md           cpu_test.go           examples                           internal         marshalers_test.go         syscalls_test.go
    asm                 doc.go                features                           link             netlify.toml               testdata
  4. 执行以下命令,运行示例程序。

    cd /app/ebpf/examples/fentry/ && go run .

    预期输出:

    2024/12/17 08:40:49 Comm     Src addr        Port   -> Dest addr        Port  
    2024/12/17 08:40:49 ilogtail 172.20.87.70    34742  -> 100.xxx.xxx.208  80    
    2024/12/17 08:40:53 ilogtail 172.20.87.70    37232  -> 100.xxx.xxx.112  80    
    2024/12/17 08:40:53 ilogtail 172.20.87.70    48676  -> 100.xxx.xxx.200  80    
    2024/12/17 08:40:54 ilogtail 172.20.87.70    59592  -> 100.xxx.xxx.7    80    
    2024/12/17 08:40:54 ilogtail 172.20.87.70    50048  -> 100.xxx.xxx.132  80    
    2024/12/17 08:40:54 ilogtail 172.20.87.70    51096  -> 100.xxx.xxx.210  80    
    2024/12/17 08:40:54 ilogtail 172.20.87.70    37808  -> 100.xxx.xxx.134  80    
    2024/12/17 08:40:57 ilogtail 172.20.87.70    58272  -> 100.xxx.xxx.113  80    
    2024/12/17 08:40:57 ilogtail 172.20.87.70    58278  -> 100.xxx.xxx.113  80    
    2024/12/17 08:40:57 ilogtail 172.20.87.70    58294  -> 100.xxx.xxx.113  80    
    2024/12/17 08:40:58 ilogtail 172.20.87.70    56356  -> 100.xxx.xxx.208  80    
    2024/12/17 08:41:00 ilogtail 172.20.87.70    48692  -> 100.xxx.xxx.200  80    

    此示例展示了最简单的eBPF程序运行的过程,您可以根据业务需要开发更复杂并贴近业务实际情况的eBPF程序。

相关信息

以下是eBPF示例中镜像的Dockerfile文件,供您参考和修改。

FROM alibaba-cloud-linux-3-registry.cn-hangzhou.cr.aliyuncs.com/alinux3/alinux3:latest

# 1、更新包列表并安装必要的工具
RUN yum update -y && \
    yum install -y wget tar gzip git util-linux net-tools

# 2、安装 Go 语言环境
ENV GO_VERSION=1.22.3
RUN wget https://golang.org/dl/go$GO_VERSION.linux-amd64.tar.gz && \
    tar -C /usr/local -xzf go$GO_VERSION.linux-amd64.tar.gz && \
    rm go$GO_VERSION.linux-amd64.tar.gz

# 3、设置Go环境变量
ENV PATH=$PATH:/usr/local/go/bin
ENV GOPATH=/go
ENV PATH=$PATH:$GOPATH/bin

# 4、下载ebpf库示例代码
RUN git clone https://github.com/cilium/ebpf.git /app/ebpf/

# 5、创建工作目录
WORKDIR /app

ENTRYPOINT ["tail", "-f", "/dev/null"]