入门OpenTelemetry——链路追踪数据收集与导出

链路追踪数据收集

链路数据收集方案

在 Kubernetes 中部署应用进行链路追踪数据收集,常见有两种方案:

  1. 基于 Instrumentation Operator 的自动注入(自动埋点)
    通过部署 OpenTelemetry Operator,并创建 Instrumentation 自定义资源(CRD),实现对应用容器的自动注入 SDK 或 Sidecar,从而无需修改应用代码即可采集追踪数据。适合需要快速接入、统一管理、降低改造成本的场景。
  2. 手动在应用中集成 OpenTelemetry SDK(手动埋点)
    在应用程序代码中直接引入 OpenTelemetry SDK,手动埋点关键业务逻辑,控制 trace span 的粒度和内容,并将数据通过 OTLP(OpenTelemetry Protocol)协议导出到后端(如 OpenTelemetry Collector、Jaeger、Tempo 等)。适合需要精准控制追踪数据质量或已有自定义采集需求的场景。

接下来以Instrumentation Operator自动注入方式演示如何收集并处理数据。

部署测试应用

接下来我们部署一个HotROD 演示程序,它内置了OpenTelemetry SDK,我们只需要配置 opentelemetry 接收地址既可,具体可参考文档:

https://github.com/jaegertracing/jaeger/tree/main/examples/hotrod

apiVersion: apps/v1
kind: Deployment
metadata:
  name: go-demo
spec:
  selector:
    matchLabels:
      app: go-demo
  template:
    metadata:
      labels:
        app: go-demo
    spec:
      containers:
      - name: go-demo
        image: jaegertracing/example-hotrod:latest
        imagePullPolicy: IfNotPresent
        resources:
          limits:
            memory: "500Mi"
            cpu: "200m"
        ports:
        - containerPort: 8080
        env:
          - name: OTEL_EXPORTER_OTLP_ENDPOINT # opentelemetry服务地址
            value: http://center-collector.opentelemetry.svc:4318
---
apiVersion: v1
kind: Service
metadata:
  name: go-demo
spec:
  selector:
    app: go-demo
  ports:
  - port: 8080
    targetPort: 8080
---
apiVersion: traefik.io/v1alpha1
kind: IngressRoute
metadata:
  name: go-demo
spec:
  entryPoints:
  - web
  routes:
  - match: Host(`go-demo.cuiliangblog.cn`)
    kind: Rule
    services:
      - name: go-demo
        port: 8080

接下来浏览器添加 hosts 解析后访问测试

Jaeger 方案

Jaeger 介绍

Jaeger 是Uber公司研发,后来贡献给CNCF的一个分布式链路追踪软件,主要用于微服务链路追踪。它优点是性能高(能处理大量追踪数据)、部署灵活(支持单节点和分布式部署)、集成方便(兼容 OpenTelemetry),并且可视化能力强,可以快速定位性能瓶颈和故障。

基于上述示意图,我们简要解析下 Jaeger 各个组件以及组件间的关系:

Client libraries(客户端库)

功能:将追踪信息(trace/span)插入到应用程序中。

说明

  • 支持多种语言,如 Go、Java、Python、Node.js 等。
  • 通常使用 OpenTelemetry SDK 或 Jaeger Tracer。
  • 将生成的追踪数据发送到 Agent 或 Collector。

Agent(代理)

功能:接收客户端发来的追踪数据,批量转发给 Collector。

说明:

  • 接收 UDP 数据包(更轻量)
  • 向 Collector 使用 gRPC 发送数据

Collector(收集器)

功能

  • 接收 Agent 或直接从 SDK 发送的追踪数据。
  • 处理(转码、校验等)后写入存储后端。

可横向扩展,提高吞吐能力。

Ingester(摄取器)(可选)

功能:在使用 Kafka 作为中间缓冲队列时,Ingester 从 Kafka 消费数据并写入存储。

用途:解耦收集与存储、提升稳定性。

Storage Backend(存储后端)

功能:保存追踪数据,供查询和分析使用。

支持

  • Elasticsearch
  • Cassandra
  • Kafka(用于异步摄取)
  • Badger(仅用于开发)
  • OpenSearch

Query(查询服务)

功能:从存储中查询追踪数据,提供给前端 UI 使用。

提供 API 接口:供 UI 或其他系统(如 Grafana Tempo)调用。

UI(前端界面)

功能

  • 可视化展示 Trace、Span、服务依赖图。
  • 支持搜索条件(服务名、时间范围、trace ID 等)。

常用用途

  • 查看慢请求
  • 分析请求调用链
  • 排查错误或瓶颈

在本示例中,指标数据采集与收集由 OpenTelemetry 实现,仅需要使用 jaeger-collector 组件接收输入,存入 elasticsearch,使用 jaeger-query 组件查询展示数据既可。

部署 Jaeger(all in one)

资源清单

apiVersion: apps/v1
kind: Deployment
metadata:
  name: jaeger
  namespace: opentelemetry
  labels:
    app: jaeger
spec:
  replicas: 1
  selector:
    matchLabels:
      app: jaeger
  template:
    metadata:
      labels:
        app: jaeger
    spec:
      containers:
        - name: jaeger
          image: jaegertracing/all-in-one:latest
          args:
            - "--collector.otlp.enabled=true"  # 启用 OTLP gRPC
            - "--collector.otlp.grpc.host-port=0.0.0.0:4317"
          resources:
            limits:
              memory: "2Gi"
              cpu: "1"
          ports:
            - containerPort: 6831
              protocol: UDP
            - containerPort: 16686
              protocol: TCP
            - containerPort: 4317
              protocol: TCP
---
apiVersion: v1
kind: Service
metadata:
  name: jaeger
  namespace: opentelemetry
  labels:
    app: jaeger
spec:
  selector:
    app: jaeger
  ports:
    - name: jaeger-udp
      port: 6831
      targetPort: 6831
      protocol: UDP
    - name: jaeger-ui
      port: 16686
      targetPort: 16686
      protocol: TCP
    - name: otlp-grpc
      port: 4317
      targetPort: 4317
      protocol: TCP
---
apiVersion: traefik.io/v1alpha1
kind: IngressRoute
metadata:
  name: jaeger
  namespace: opentelemetry
spec:
  entryPoints:
  - web
  routes:
  - match: Host(`jaeger.cuiliangblog.cn`)
    kind: Rule
    services:
      - name: jaeger
        port: 16686

接下来配置 hosts 解析后浏览器访问既可。

部署 Jaeger(分布式)

all in one 数据存放在内存中不具备高可用性,生产环境中建议使用Elasticsearch 或 OpenSearch 作为 Cassandra 的存储后端,以 ElasticSearch 为例,部署操作具体可参考文档:https://www.cuiliangblog.cn/detail/section/162609409

导出 ca 证书

# kubectl -n elk get secret elasticsearch-es-http-certs-public -o go-template='{{index .data "ca.crt" | base64decode }}' > ca.crt
# kubectl create secret -n opentelemetry generic es-tls-secret --from-file=ca.crt=./ca.crt
secret/es-tls-secret created

此处使用 helm 方式部署 jaeger,具体可参考文档:https://github.com/jaegertracing/helm-charts/tree/v2

获取 chart 包

# helm repo add jaegertracing https://jaegertracing.github.io/helm-charts
"jaegertracing" has been added to your repositories
# helm search repo jaegertracing
NAME                            CHART VERSION   APP VERSION     DESCRIPTION                              
jaegertracing/jaeger            3.4.1           1.53.0          A Jaeger Helm chart for Kubernetes       
jaegertracing/jaeger-operator   2.57.0          1.61.0          jaeger-operator Helm chart for Kubernetes
# helm pull jaegertracing/jaeger --untar
# cd jaeger
# ls
Chart.lock  charts  Chart.yaml  README.md  templates  values.yaml

修改安装参数

provisionDataStore: # 不安装后端存储
  cassandra: false
  elasticsearch: false
agent:
  enabled: false # 不需要安装agent
spark:
  enabled: true # 安装spark,用于从追踪信息中提取服务调用关系图
collector: 
  service:
    otlp: # 接收otlp数据
      grpc:
        name: otlp-grpc
        port: 4317
        # nodePort:
      http:
        name: otlp-http
        port: 4318
storage:
  type: elasticsearch # 使用elasticsearch存储
  elasticsearch:
    scheme: https
    host: elasticsearch-es-http.elk.svc
    port: 9200
    anonymous: false
    user: admin
    usePassword: true
    password: 123.com
    nodesWanOnly: false
    extraEnv: []
    cmdlineParams:
      {}
    tls:
      enabled: true
      secretName: es-tls-secret
      mountPath: /es-tls/ca.crt
      subPath: ca.crt
      ca: /es-tls/ca.crt

安装 jaeger

# helm install jaeger -n opentelemetry . -f values.yaml 
NAME: jaeger
LAST DEPLOYED: Tue Apr 29 14:11:35 2025
NAMESPACE: opentelemetry
STATUS: deployed
REVISION: 1
TEST SUITE: None
NOTES:
###################################################################
### IMPORTANT: Ensure that storage is explicitly configured     ###
### Default storage options are subject to change.              ###
###                                                             ###
### IMPORTANT: The use of <component>.env: {...} is deprecated. ###
### Please use <component>.extraEnv: [] instead.                ###
###################################################################

You can log into the Jaeger Query UI here:

  export POD_NAME=$(kubectl get pods --namespace opentelemetry -l "app.kubernetes.io/instance=jaeger,app.kubernetes.io/component=query" -o jsonpath="{.items[0].metadata.name}")
  echo http://127.0.0.1:8080/
  kubectl port-forward --namespace opentelemetry $POD_NAME 8080:16686
# kubectl get pod -n opentelemetry                                  
NAME                                READY   STATUS    RESTARTS        AGE
center-collector-79978d9c9b-rrpgl   1/1     Running   1 (3h57m ago)   4h36m
jaeger-collector-5f5948c494-vzbxn   1/1     Running   0               4m39s
jaeger-query-75cb86f44d-np6b7       2/2     Running   0               4m39s
# kubectl get svc -n opentelemetry | grep jaeger
jaeger-collector               ClusterIP   10.105.82.204   <none>        14250/TCP,14268/TCP,4317/TCP,4318/TCP,14269/TCP   40s
jaeger-query                   ClusterIP   10.108.108.99   <none>        80/TCP,16685/TCP,16687/TCP                        40s

创建 ingress 资源

cat jaeger.yaml           
apiVersion: traefik.io/v1alpha1
kind: IngressRoute
metadata:
  name: jaeger
  namespace: opentelemetry
spec:
  entryPoints:
  - web
  routes:
  - match: Host(`jaeger.cuiliangblog.cn`)
    kind: Rule
    services:
      - name: jaeger
        port: 16686#                                                                                               
# kubectl apply -f jaeger.yaml    
ingressroute.traefik.io/jaeger created

接下来配置 hosts 解析后浏览器访问既可。

配置 Collector

apiVersion: opentelemetry.io/v1beta1
kind: OpenTelemetryCollector
# 元数据定义部分
metadata:
  name: center        # Collector 的名称为 center
  namespace: opentelemetry
# 具体的配置内容
spec:
  replicas: 1           # 设置副本数量为1
  config:               # 定义 Collector 配置
    receivers:          # 接收器,用于接收遥测数据(如 trace、metrics、logs)
      otlp:             # 配置 OTLP(OpenTelemetry Protocol)接收器
        protocols:      # 启用哪些协议来接收数据
          grpc: 
            endpoint: 0.0.0.0:4317      # 启用 gRPC 协议
          http: 
            endpoint: 0.0.0.0:4318      # 启用 HTTP 协议

    processors:         # 处理器,用于处理收集到的数据
      batch: {}         # 批处理器,用于将数据分批发送,提高效率

    exporters:          # 导出器,用于将处理后的数据发送到后端系统
      # debug: {}         # 使用 debug 导出器,将数据打印到终端(通常用于测试或调试)
      otlp:               # 数据发送到jaeger的grpc端口
        endpoint: "jaeger-collector:4317"
        tls: # 跳过证书验证
          insecure: true

    service:            # 服务配置部分
      pipelines:        # 定义处理管道
        traces:         # 定义 trace 类型的管道
          receivers: [otlp]                      # 接收器为 OTLP
          processors: [batch]                    # 使用批处理器
          exporters: [otlp]                      # 将数据发送到otlp

访问验证

接下来我们随机访问 demo 应用,并在 jaeger 查看链路追踪数据。

Jaeger 系统找到了一些 trace 并显示了一些关于该 trace 的元数据,包括参与该 trace 的不同服务的名称以及每个服务发送到 Jaeger 的 span 记录数。

jaeger 使用具体可参考文章https://medium.com/jaegertracing/take-jaeger-for-a-hotrod-ride-233cf43e46c2

Tempo 方案

Tempo 介绍

Grafana Tempo是一个开源、易于使用的大规模分布式跟踪后端。Tempo具有成本效益,仅需要对象存储即可运行,并且与Grafana,Prometheus和Loki深度集成,Tempo可以与任何开源跟踪协议一起使用,包括Jaeger、Zipkin和OpenTelemetry。它仅支持键/值查找,并且旨在与用于发现的日志和度量标准(示例性)协同工作。

Distributors(分发器)

功能:接收客户端发送的追踪数据并进行初步验证

说明

  • 对 Trace 进行分片、标签处理。
  • 将数据转发给合适的 Ingesters。

Ingesters(摄取器)

功能:处理和持久化 Trace 数据

说明

  • 接收来自 Distributor 的数据。
  • 在内存中缓存直到追踪完成(完整的 Trace)。
  • 再写入后端对象存储。

Storage(对象存储)

功能:持久化存储 Trace 数据

说明

  • 支持多种对象存储(S3、GCS、MinIO、Azure Blob 等)。
  • Tempo 存储的是压缩的完整 Trace 文件,使用 trace ID 进行索引。

Compactor(数据压缩)

**功能:**合并 trace 数据,压缩多个小 block 成一个大 block。

说明:

  • 可以单独运行 compactor 容器或进程。
  • 通常以 后台任务 的方式运行,不参与实时 ingest 或 query。

Tempo Query(查询前端)

功能:处理来自用户或 Grafana 的查询请求

说明

  • 接收查询请求。
  • 提供缓存、合并和调度功能,优化查询性能。
  • 将请求转发给 Querier。

Querier(查询器)

功能:从存储中检索 Trace 数据

说明

  • 根据 trace ID 从对象存储中检索完整 trace。
  • 解压和返回结构化的 Span 数据。
  • 返回结果供 Grafana 或其他前端展示。

部署 Tempo

推荐用Helm 安装,官方提供了tempo-distributed Helm chart 和 tempo Helm chart 两种部署模式,一般来说本地测试使用 tempo Helm chart,而生产环境可以使用 Tempo 的微服务部署方式 tempo-distributed。接下来以整体模式为例,具体可参考文档https://github.com/grafana/helm-charts/tree/main/charts/tempo

创建 s3 的 bucket、ak、sk 资源,并配置权限。具体可参考文档:https://www.cuiliangblog.cn/detail/section/121560332

获取 chart 包

# helm repo add grafana https://grafana.github.io/helm-charts
# helm pull grafana/tempo --untar
# cd tempo 
# ls
Chart.yaml  README.md  README.md.gotmpl  templates  values.yaml

修改配置,prometheus 默认未启用远程写入,可参考文章开启远程写入https://www.cuiliangblog.cn/detail/section/15189202

# vim values.yaml
tempo:
  storage:
    trace: # 默认使用本地文件存储,改为使用s3对象存储
      backend: s3
      s3:
        bucket: tempo                      # store traces in this bucket
        endpoint: minio-service.minio.svc:9000  # api endpoint
        access_key: zbsIQQnsp871ZnZ2AuKr                                 # optional. access key when using static credentials.
        secret_key: zxL5EeXwU781M8inSBPcgY49mEbBVoR1lvFCX4JU             # optional. secret key when using static credentials.
        insecure: true                                 # 跳过证书验证

创建 tempo

# helm install tempo -n opentelemetry . -f values.yaml
NAME: tempo
LAST DEPLOYED: Tue May  6 10:26:08 2025
NAMESPACE: opentelemetry
STATUS: deployed
REVISION: 1
TEST SUITE: None
# kubectl get pod -n opentelemetry        
NAME                                READY   STATUS    RESTARTS   AGE
center-collector-7fb65bcb44-pnx6s   1/1     Running   0          6d19h
tempo-0                             1/1     Running   0          2m24s
# kubectl get svc -n opentelemetry | grep tempo 
tempo                          ClusterIP   10.111.81.228   <none>        6831/UDP,6832/UDP,3100/TCP,14268/TCP,14250/TCP,9411/TCP,55680/TCP,55681/TCP,4317/TCP,4318/TCP,55678/TCP   24s

配置 Collector

tempo 服务的otlp 数据接收端口分别为4317(grpc)和4318(http),修改OpenTelemetryCollector 配置,将数据发送到 tempo 的 otlp 接收端口。

apiVersion: opentelemetry.io/v1beta1
kind: OpenTelemetryCollector
# 元数据定义部分
metadata:
  name: center        # Collector 的名称为 center
  namespace: opentelemetry
# 具体的配置内容
spec:
  replicas: 1           # 设置副本数量为1
  config:               # 定义 Collector 配置
    receivers:          # 接收器,用于接收遥测数据(如 trace、metrics、logs)
      otlp:             # 配置 OTLP(OpenTelemetry Protocol)接收器
        protocols:      # 启用哪些协议来接收数据
          grpc: 
            endpoint: 0.0.0.0:4317      # 启用 gRPC 协议
          http: 
            endpoint: 0.0.0.0:4318      # 启用 HTTP 协议

    processors:         # 处理器,用于处理收集到的数据
      batch: {}         # 批处理器,用于将数据分批发送,提高效率

    exporters:          # 导出器,用于将处理后的数据发送到后端系统
      # debug: {}         # 使用 debug 导出器,将数据打印到终端(通常用于测试或调试)
      otlp:               # 数据发送到tempo的grpc端口
        endpoint: "tempo:4317"
        tls: # 跳过证书验证
          insecure: true

    service:            # 服务配置部分
      pipelines:        # 定义处理管道
        traces:         # 定义 trace 类型的管道
          receivers: [otlp]                      # 接收器为 OTLP
          processors: [batch]                    # 使用批处理器
          exporters: [otlp]                     # 将数据打印到OTLP

访问验证

访问 grafana,添加 tempo 数据源。

查看 traces 数据

服务拓扑图配置

Tempo Metrics Generator 是 Grafana Tempo 提供的一个 可选组件,用于将 Trace(链路追踪数据)转换为 Metrics(指标数据),从而实现 Trace-to-Metrics(T2M) 的能力,默认情况下 tempo 并未启用该功能。

  1. prometheus 开启remote-write-receiver 功能,关键配置如下:
# vim prometheus-prometheus.yaml
spec:
  # enableFeatures: 
  enableFeatures: # 开启远程写入
  - remote-write-receiver
  externalLabels:
    web.enable-remote-write-receiver: "true"
# kubectl apply -f prometheus-prometheus.yaml

具体可参考文档:https://m.cuiliangblog.cn/detail/section/15189202

  1. tempo 开启metricsGenerator 功能,关键配置如下:
# vim values.yaml
global:
  per_tenant_override_config: /runtime-config/overrides.yaml
  metrics_generator_processors:
  - 'service-graphs'
  - 'span-metrics'
tempo:
  metricsGenerator:
    enabled: true # 从 Trace 中自动生成 metrics(指标),用于服务调用关系图
    remoteWriteUrl: "http://prometheus-k8s.monitoring.svc:9090/api/v1/write" # prometheus地址
  overrides: # 多租户默认配置启用metrics
    defaults: 
      metrics_generator:
        processors:
          - service-graphs
          - span-metrics

此时查询 prometheus 图表,可以获取traces 相关指标

  1. grafana 数据源启用节点图与服务图,配置如下

  1. 查看服务图数据

查看更多

崔亮的博客-专注devops自动化运维,传播优秀it运维技术文章。更多原创运维开发相关文章,欢迎访问https://www.cuiliangblog.cn
或关注公众号《崔亮的博客》

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值