饮墨

子安饮墨馀三斗,留与卿儿作赋来

Grafana Beyla:eBPF 零侵入应用可观测性实战

痛点:传统应用监控的侵入性困境

运维团队在推进可观测性建设时,常遇到这样的尴尬:

  1. SDK 侵入成本高 — OpenTelemetry SDK 需要改代码,Java Agent 要加 JVM 参数,Go 应用更是得手动埋点。业务团队排期紧,根本不愿配合。
  2. 多语言栈覆盖难 — 一个集群里跑着 Go、Java、Python、Node.js、Rust 服务,为每种语言维护 instrumentation 方案是运维噩梦。
  3. Sidecar 方案有开销 — Istio/Envoy sidecar 虽然能采集 L7 指标,但每个 Pod 多一个容器,内存和 CPU 开销在大规模集群中不可忽视。

Grafana Beyla 用 eBPF 从内核层自动捕获 HTTP/gRPC 调用,无需修改应用代码、无需 sidecar、无需重启服务,真正实现零侵入的应用级可观测性。

方案:Beyla 是什么,怎么工作

Grafana Beyla 是 Grafana Labs 开源的 eBPF 自动化 instrumentation 工具,核心原理:

  • 通过 eBPF uprobe/kprobe 挂载到内核和用户态函数
  • 自动识别 HTTP(Go net/http、Java Servlet、Python WSGI/ASGI、Node.js http 模块)和 gRPC 调用
  • 生成符合 OpenTelemetry 语义约定的 Metrics 和 Traces
  • 直接推送到 Prometheus(OTLP)或 Grafana Cloud

关键优势对比:

方案 代码侵入 多语言支持 资源开销 部署复杂度
OTel SDK 高(需改代码) 逐个适配
Istio Sidecar 仅 L7 层 高(每 Pod +1 容器)
Beyla eBPF 自动识别 极低(~30MB 内存)

实操步骤

步骤 1:DaemonSet 部署 Beyla

生产环境推荐以 DaemonSet 方式部署,监控节点上所有应用进程:

# beyla-daemonset.yaml
apiVersion: apps/v1
kind: DaemonSet
metadata:
  name: beyla
  namespace: monitoring
spec:
  selector:
    matchLabels:
      app: beyla
  template:
    metadata:
      labels:
        app: beyla
    spec:
      hostPID: true  # 必须:需要访问宿主机进程
      serviceAccountName: beyla
      containers:
      - name: beyla
        image: grafana/beyla:1.8
        securityContext:
          privileged: true  # eBPF 需要特权模式
        env:
        - name: BEYLA_OPEN_PORT
          value: "80,443,8080,3000,5000,9090"
        - name: BEYLA_OTEL_METRICS_ENDPOINT
          value: "http://prometheus-server.monitoring:4318"
        - name: BEYLA_OTEL_TRACES_ENDPOINT
          value: "http://tempo.monitoring:4318"
        - name: BEYLA_SERVICE_NAMESPACE
          valueFrom:
            fieldRef:
              fieldPath: metadata.namespace
        resources:
          requests:
            memory: "32Mi"
            cpu: "50m"
          limits:
            memory: "128Mi"
            cpu: "200m"
        volumeMounts:
        - name: sys-kernel
          mountPath: /sys/kernel
          readOnly: true
      volumes:
      - name: sys-kernel
        hostPath:
          path: /sys/kernel
kubectl apply -f beyla-daemonset.yaml

步骤 2:配置精细化服务发现

通过 ConfigMap 定义更精准的匹配规则,避免监控不必要的进程:

# beyla-config.yaml
apiVersion: v1
kind: ConfigMap
metadata:
  name: beyla-config
  namespace: monitoring
data:
  beyla-config.yml: |
    # 按 Kubernetes metadata 匹配目标
    discovery:
      services:
        - k8s_namespace: "production|staging"
          k8s_deployment_name: ".*"
        - k8s_namespace: "default"
          k8s_pod_labels:
            app: "api-gateway"

    # 路由分组:将 /users/123 归类为 /users/{id}
    routes:
      patterns:
        - /api/v1/users/{id}
        - /api/v1/orders/{id}
        - /healthz
      ignored_patterns:
        - /metrics
        - /ready
        - /live

    # 采样策略:生产环境建议 tail-based sampling
    attributes:
      kubernetes:
        enable: true  # 自动添加 pod/node/namespace 标签

    otel_metrics_export:
      endpoint: http://prometheus-server.monitoring:4318
      interval: 15s

    otel_traces_export:
      endpoint: http://tempo.monitoring:4318
      sampler:
        name: parentbased_traceidratio
        arg: "0.1"  # 10% 采样率

挂载 ConfigMap 到 DaemonSet:

kubectl create configmap beyla-config --from-file=beyla-config.yml -n monitoring
# 在 DaemonSet 中添加 volume 和 env:
# BEYLA_CONFIG_PATH=/config/beyla-config.yml

步骤 3:Grafana Dashboard 可视化

Beyla 输出的指标遵循 OpenTelemetry 语义约定,核心指标:

# RED 三指标 — Rate
sum(rate(http_server_request_duration_seconds_count{service_namespace="production"}[5m])) by (service_name)

# RED 三指标 — Errors
sum(rate(http_server_request_duration_seconds_count{http_response_status_code=~"5.."}[5m])) by (service_name)
/ sum(rate(http_server_request_duration_seconds_count[5m])) by (service_name)

# RED 三指标 — Duration (P99)
histogram_quantile(0.99, 
  sum(rate(http_server_request_duration_seconds_bucket{service_namespace="production"}[5m])) by (le, service_name)
)

Grafana Labs 提供了开箱即用的 Dashboard(ID: 19077),直接导入即可:

# 或通过 Grafana API 导入
curl -X POST http://grafana:3000/api/dashboards/import \
  -H "Content-Type: application/json" \
  -d '{"dashboard": {"id": 19077}, "overwrite": true, "inputs": [{"name": "DS_PROMETHEUS", "value": "Prometheus"}]}'

步骤 4:验证与排查

# 检查 Beyla Pod 是否正常运行
kubectl get pods -n monitoring -l app=beyla

# 查看 Beyla 日志,确认服务发现
kubectl logs -n monitoring -l app=beyla | grep "instrumenting"

# 预期输出类似:
# level=info msg="instrumenting process" pid=12345 service=api-gateway

# 验证指标是否到达 Prometheus
kubectl exec -n monitoring deploy/prometheus-server -- \
  wget -qO- 'http://localhost:9090/api/v1/query?query=http_server_request_duration_seconds_count' | python3 -m json.tool | head -20

避坑指南

坑 1:内核版本过低导致 eBPF 功能不可用

Beyla 依赖 eBPF CO-RE(Compile Once, Run Everywhere),最低要求 Linux 5.8+。AWS EKS 使用 Amazon Linux 2023 AMI(内核 6.1+)没问题,但如果还在用老旧的 Amazon Linux 2(内核 5.10)需要确认 BTF 支持:

# 检查节点是否支持 BTF
ls /sys/kernel/btf/vmlinux
# 存在即支持

坑 2:特权容器与安全策略冲突

Beyla 需要 privileged: truehostPID: true,在启用了 Pod Security Admission 的集群中会被拦截。解决方案:

# 为 monitoring namespace 设置 privileged 级别
apiVersion: v1
kind: Namespace
metadata:
  name: monitoring
  labels:
    pod-security.kubernetes.io/enforce: privileged
    pod-security.kubernetes.io/warn: privileged

坑 3:高基数(High Cardinality)指标爆炸

如果不配置路由分组,/users/123/users/456 会生成独立的指标标签,导致 Prometheus 内存暴涨。务必配置 routes.patterns 将动态路径参数化,并用 ignored_patterns 排除健康检查等高频低价值路径。

总结

Grafana Beyla 解决了可观测性落地的"最后一公里"问题 — 不用求着开发改代码,不用忍受 sidecar 的资源开销,一个 DaemonSet 部署完毕,全集群 HTTP/gRPC 服务的 RED 指标和分布式 Trace 就自动到位。

适用场景: - 多语言微服务集群快速接入可观测性 - 已有 Grafana Stack(Prometheus + Tempo + Grafana)的团队 - 对应用零侵入有硬性要求的合规环境

不适用场景: - 需要业务自定义 Span/指标(如订单金额、用户 ID 维度)— 仍需 SDK - 非 HTTP/gRPC 协议(如自定义 TCP 二进制协议)— Beyla 暂不支持

生产建议: Beyla 作为基线覆盖 + 核心服务追加 OTel SDK 精细埋点,两者互补而非替代。

您还没有登录,请登录后发表评论。