Skip to content

eBPF 全链路观测 部署文档(Beyla + Tempo on uat1)

目标集群:uat1(192.168.122.31:6443,RKE2 v1.35.6,6 节点,Rocky 9.8 内核 5.14 带 BTF,Calico CNI) 命名空间:observability;复用 cattle-monitoring-system 的 rancher-monitoring(Prometheus + Grafana + Alertmanager) 本地 kubectl:/tmp/bin/kubectl,kubeconfig ~/.kube/config-122.31

一、方案与选型

决策点选择理由
采集器Grafana Beyla v3.30.0零侵入 eBPF 自动埋点;弃 Pixie(依赖外部 Cloud)、DeepFlow(太重)
Trace 存储Tempo v2.10.7 monolithic轻量单实例;不选 3.0(2026-06 架构大改,UAT 求稳)
是否部署 OTel CollectorBeyla 直发 Tempo OTLP,减少一跳;后续需要采样/脱敏再插入
Tempo 存储后端local backend(NFS PVC)UAT 够用;生产必须换对象存储(S3/MinIO)
服务拓扑Tempo metrics-generatorspanmetrics + servicegraph 聚合后 remote_write 回 Prometheus,Node Graph 直接用
Grafana 数据源provisioning ConfigMap 注入rancher-monitoring 数据源是 provisioning 只读,API 改不动

数据流

进程 ──eBPF──► Beyla ──┬── :9090 Prometheus export ──► Prometheus(RED 指标)
                       └── OTLP/gRPC ──► Tempo:4317 ──► local blocks(NFS)
Tempo metrics-generator ──remote_write──► Prometheus(spanmetrics / servicegraph)
Grafana:Prometheus(exemplar→Tempo)+ Tempo 数据源 + RED 看板

二、前置条件

  1. 内核 ≥ 5.8 且带 BTF:ls /sys/kernel/btf/vmlinux(Rocky 9.8 内核 5.14 ✅)
  2. Harbor 192.168.122.156:30000 已建 observability 项目(须先在 Harbor API/UI 创建,skopeo push 不会自动建)
  3. skopeo 已登录 Harbor(凭据在 ~/.docker/config.json)
  4. rancher-monitoring 正常运行(Prometheus CR 名 rancher-monitoring-prometheus)

三、部署步骤

3.1 同步镜像(离线环境)

bash
cd worker/apps/midddleware/ebpf-observability
export HARBOR_PASSWORD='xxx'   # 或放 .secrets.env
./deploy.sh --sync

镜像清单(images.txt,共 2 个):

grafana/beyla:3.30.0     # 注意:DaoCloud 上 beyla 的 tag 无 v 前缀(带 v 会 401)
grafana/tempo:2.10.7

源站 docker.m.daocloud.io → Harbor observability 项目。attestation 层导致 --all 失败时脚本自动 fallback --override-os linux --override-arch amd64

3.2 一键部署

bash
./deploy.sh

deploy.sh 依次做 6 件事(全部幂等):

  1. 建 ns observability
  2. 部署 Tempo(Deployment + PVC 10Gi + ConfigMap + svc 4317/4318/3200)
  3. 部署 Beyla(SA + ClusterRole + ConfigMap + DaemonSet + metrics Service)
  4. apply monitoring.yaml(ServiceMonitor + PrometheusRule)
  5. 给 Prometheus CR patch --web.enable-remote-write-receiver(已存在则跳过)
  6. 覆盖 Grafana 数据源 ConfigMap(加 Tempo + exemplar 联动)并重启 Grafana pod

3.3 关键配置说明

Beyla(beyla.yaml 中 ConfigMap beyla-config):

yaml
discovery:
  instrument:
    - k8s_namespace: "*"        # ⚠️ v3 的 k8s_* 选择器是 glob,不是正则!
  exclude_instrument:
    - k8s_namespace: "kube-system"   # 逐个 glob 枚举,不能用 ^(...)$ 正则
    - k8s_namespace: "cattle-*"
    # ... 见 beyla.yaml
attributes:
  kubernetes:
    enable: true                # 指标/trace 自动带 k8s_* 标签
prometheus_export:
  port: 9090                    # RED 指标出口
internal_metrics:
  prometheus:
    port: 9099                  # Beyla 自身内部指标(排障用)
otel_traces_export:             # ⚠️ YAML 键名必须是 otel_traces_export
  endpoint: http://tempo.observability:4317
  protocol: grpc

DaemonSet 安全上下文:非 privileged,仅加 BPF / PERFMON / NET_ADMIN / SYS_PTRACE 四个 caps + hostPID: true

Tempo(tempo.yaml 中 ConfigMap):

  • receivers:OTLP grpc:4317 / http:4318
  • storage:local backend,WAL + blocks 在 NFS PVC(/var/tempo),block_retention: 48h
  • metrics_generator:开 span-metrics + service-graphs processor,registry 暴露,remote_write → http://rancher-monitoring-prometheus.cattle-monitoring-system:9090/api/v1/write
  • overrides:metrics_generator processor 默认全租开启

3.4 Grafana 数据源(provisioning 方式)

rancher-monitoring 的 Grafana 数据源由 ConfigMap rancher-monitoring-grafana-datasource provisioning(API 修改会报 read-only),deploy.sh 第 6 步已渲染完整配置:

  • Tempo:http://tempo.observability:3200,开 Node Graph(数据源指向 Prometheus 的 servicegraph 指标)、traces→metrics 跳转(spanmetrics)
  • Prometheus:加 exemplarTraceIdDestinations(Beyla 指标 exemplar 的 trace_id 一键跳 Tempo)

⚠️ 该 ConfigMap 属 rancher-monitoring chart 管理,chart 升级会还原,升级后需重跑 deploy.sh 第 6 步。 ⚠️ provisioning sidecar 是 init 模式,改 ConfigMap 后必须删 Grafana pod 才生效(deploy.sh 已包含)。

3.5 导入看板

Grafana UI → Dashboards → Import → 上传 grafana/dashboard-ebpf-apm-red.json(uid ebpf-apm-red)。面板:请求速率 / 错误率 / P95 延迟(Beyla RED)+ Node Graph 服务拓扑 + 最近 Traces。

四、验证清单

bash
alias k='/tmp/bin/kubectl'; export KUBECONFIG=~/.kube/config-122.31

# 1. Pod 状态
k -n observability get pods -o wide          # tempo 1/1,beyla 6/6

# 2. Beyla 进程埋点(关键!len 必须 >0)
BPOD=$(k -n observability get pods -l app=beyla -o jsonpath='{.items[0].metadata.name}')
k -n observability logs $BPOD | grep -c 'instrumenting process'   # >0

# 3. Beyla trace 导出计数(内部指标 :9099)
k -n observability port-forward pod/$BPOD 19099:9099 &
curl -s localhost:19099/metrics | grep -E '^beyla_otel_trace_exports_total|^beyla_ebpf_tracer_flushes_count'
# 两个计数都应 >0 且持续增长;flushes=0 说明 span 事件根本没产出(见踩坑①)

# 4. 制造流量后查 Tempo
for i in $(seq 10); do curl -s -o /dev/null http://192.168.122.31/ -H 'Host: helloworld-go-default.knative.ai-ear.cn'; done
k -n observability port-forward svc/tempo 13200:3200 &
curl -s 'localhost:13200/api/search?limit=10'    # traces 非空

# 5. RED 指标进 Prometheus
k -n cattle-monitoring-system port-forward svc/rancher-monitoring-prometheus 19090:9090 &
curl -s 'localhost:19090/api/v1/query?query=sum(rate(http_server_request_duration_seconds_count[5m]))'

# 6. spanmetrics / servicegraph 回写
curl -s 'localhost:19090/api/v1/query?query=traces_spanmetrics_calls_total'        # series 100+
curl -s 'localhost:19090/api/v1/query?query=traces_service_graph_request_total'    # 边 10+

# 7. 告警规则加载
curl -s 'localhost:19090/api/v1/rules?type=alert' | grep -o 'AppHighErrorRate\|AppHighLatencyP99\|BeylaDown\|TempoDown'

五、踩坑记录(实测)

#现象正确做法
Beyla v3 的 k8s_namespace 等选择器是 glob 不是正则k8s_namespace: .+ / ^(a|b)$ 静默匹配 0 个进程,debug 日志 processes matching selection criteria len=0metadata does not match attr=k8s_namespace value=elasticsearch;RED 指标仍在(见④),极易误判为"工作正常"glob 写法:k8s_namespace: "*"、排除逐个枚举 cattle-*
YAML 键名 otel_traces_export误写 otlp_traces_export 被静默忽略,无任何报错,trace 不导出键名 otel_traces_export;调 log_level: debug 看启动日志应有 component=otelcfg.TracesConfig ... endpoint=...
ConfigMap 变更不触发 DS 重启改了 beyla-config 没生效每次改后 kubectl -n observability rollout restart ds beyla
Beyla v3 指标走内核聚合,trace 走 ring buffer,是两条路RED 指标正常 ≠ trace 管线正常;beyla_ebpf_tracer_flushes_count=0 才是 trace 侧的真实信号排障先看内部指标 :9099 的 flushes 与 beyla_otel_trace_exports_total
Prometheus 新版 remote-write 开关改名--enable-feature=remote-write-receiverUnknown option--web.enable-remote-write-receiver,patch Prometheus CR 的 additionalArgs;空 POST 返 400 = 端点存在
Tempo 镜像 distrolesskubectl exec 无 sh/wget,无法容器内自测docker.m.daocloud.io/curlimages/curl 起临时 pod 打 OTLP/HTTP JSON 到 :4318/v1/traces 验证接收器
DaoCloud beyla tag 无 v 前缀grafana/beyla:v3.30.0 拉取 401grafana/beyla:3.30.0
Grafana 数据源 provisioning 只读API PUT/POST 报 Cannot update read-only data source;匿名访问是 Viewer 无权 create改 ConfigMap rancher-monitoring-grafana-datasource + 删 pod 重启;chart 升级会还原
Grafana admin 密码 DB 与 secret 漂移basic auth 401、/api/user Unauthorized(匿名 Viewer 下 GET /api/org 仍 200,迷惑性强)pod 重启时 Grafana 从 GF_SECURITY_ADMIN_PASSWORD env(来自 secret)重新同步,重启后用 /login 拿 cookie
Knative 缩容到零干扰 trace 验证打几个 curl 后 70s pod 消失,span 停发,怀疑链路坏了验证时持续打流量保持 pod 存活;或用常驻服务(redis/kibana)验证

六、生产注意事项

  1. Tempo 换对象存储:local backend 仅适合 UAT;生产用 S3/MinIO + 多副本(distributed 模式)
  2. 跨进程 trace 串链:加 CAP_SYS_ADMIN 开启 Go context propagation(需评估内核 lockdown 与 bpf_probe_write_user 安全面)
  3. 采样:otel_traces_export.sampler 默认全采;上量后改 traceidratio 按比例采样
  4. 高基数控制:attributes.select 裁剪指标标签;routes.patterns 收敛 HTTP route
  5. resource 限额:Beyla DS 默认无 limit,生产建议 requests/limits(内存 ~120Mi/实例起步)
  6. chart 升级还原点:Grafana 数据源 CM、Prometheus additionalArgs 都可能被 rancher-monitoring 升级还原,升级后重跑 deploy.sh

七、卸载

bash
kubectl delete -f monitoring.yaml -f beyla.yaml -f tempo.yaml
kubectl delete ns observability
# 回滚 Prometheus remote-write(可选)
kubectl -n cattle-monitoring-system get prometheus rancher-monitoring-prometheus -o json \
  | jq '.spec.additionalArgs'   # 手动移除 web.enable-remote-write-receiver 后 apply
# 回滚 Grafana 数据源:从 ConfigMap 删 Tempo 段落与 exemplarTraceIdDestinations,删 grafana pod