从零搭建一个单节点 K8S 可观测实验室(六):安装 Tempo + OpenTelemetry,构建链路追踪链路
2026/8/8 10:10:19 网站建设 项目流程

在前面的文章中,我们已经完成了 Kubernetes 可观测体系中的两个部分:

Metrics 指标 Prometheus Logs 日志 Loki

Prometheus 可以帮助我们发现:

  • Node CPU 是否过高

  • Memory 是否不足

  • Pod 是否频繁重启

  • 服务错误率是否突然升高

Loki 则可以帮助我们进一步查看:

  • 数据库连接是否失败

  • 配置文件是否缺失

  • 应用是否出现异常

  • 某个 Pod 在故障前输出了什么日志

但是,当系统由多个服务组成时,仅仅查看 Metrics 和 Logs 仍然不够。

假设一次用户请求需要经过下面几个服务:

用户请求 │ ▼ Frontend │ ▼ Backend │ ▼ Database

现在请求耗时突然从:

200 ms

上升到:

2 s

Prometheus 可以发现:

接口延迟上升

Loki 也可能找到一些相关日志。

但是我们仍然需要回答:

这 2 秒究竟消耗在哪个服务上?

是 Frontend 处理缓慢?

还是 Backend 调用了一个很慢的接口?

或者 Database 查询耗费了大量时间?

这正是分布式链路追踪需要解决的问题。

这一篇,我们继续搭建可观测体系的第三部分:

Tracing 链路追踪 Tempo

本篇将在单节点 Kubernetes 实验环境中部署:

  • Tempo:存储和查询 Trace

  • OpenTelemetry Collector:接收、处理和转发 Trace

  • Python Demo:生成最简单的测试 Trace

  • Grafana:查询和展示完整调用链

最终形成下面这条链路:

Demo Application │ │ OTLP/gRPC 4317 ▼ OpenTelemetry Collector │ │ OTLP/gRPC 4317 ▼ Tempo │ │ HTTP 3200 ▼ Grafana Explore

一、什么是 Trace?

一次请求进入系统后,可能会经过多个处理步骤。

例如:

HTTP Request │ ├── Validate Request │ ├── Query Database │ └── Build Response

在链路追踪系统中,一次完整请求通常称为:

Trace

Trace 内部的每个处理步骤称为:

Span

例如:

Trace: 用户请求 │ ├── Span: HTTP Request 320 ms │ ├── Span: Validate Request 10 ms │ ├── Span: Query Database 250 ms │ └── Span: Build Response 60 ms

通过这些 Span,我们可以直观看出:

Query Database

占用了大部分时间。

因此,Tracing 主要回答:

一次请求经过了哪些步骤?

以及:

时间究竟消耗在哪里?


二、OpenTelemetry 和 Tempo 分别负责什么?

在本实验中,OpenTelemetry 和 Tempo 承担不同的角色。

OpenTelemetry

OpenTelemetry 是一套开放的可观测标准和工具体系。

它可以处理:

Metrics Logs Traces

本篇主要使用其中两个部分:

OpenTelemetry SDK OpenTelemetry Collector

应用通过 OpenTelemetry SDK 创建 Trace 和 Span,然后将数据发送给 OpenTelemetry Collector。

Collector 主要负责:

  • 接收应用发送的遥测数据

  • 批量处理 Trace

  • 添加或修改属性

  • 将 Trace 转发给后端存储系统

  • 将应用和具体存储后端解耦

Tempo

Tempo 是 Grafana 生态中的分布式链路追踪后端。

它主要负责:

  • 接收 Trace

  • 存储 Trace

  • 根据 Trace ID 查询

  • 根据服务名、Span 名称和属性搜索 Trace

  • 将查询结果提供给 Grafana

Tempo 支持单体和微服务两种部署模式。

对于入门、开发和小规模环境,Grafana 官方建议使用单体模式;微服务模式更加复杂,适合需要独立扩展各组件的场景。

本实验室的目标仍然是:

单节点 + 低资源占用 + 便于学习

因此采用:

Tempo Monolithic

也就是单体部署模式。


三、整体架构

本篇完整架构如下:

Kubernetes Cluster Demo Trace Application │ │ OpenTelemetry SDK │ OTLP/gRPC :4317 ▼ OpenTelemetry Collector │ │ Batch Processor │ OTLP/gRPC :4317 ▼ Tempo │ │ Query API :3200 ▼ Grafana

这里为什么不让应用直接连接 Tempo?

理论上可以:

Application │ ▼ Tempo

但是在真实系统中,更常见的结构是:

Application │ ▼ OpenTelemetry Collector │ ▼ Tracing Backend

Collector 相当于应用和后端之间的统一中转站。

以后即使将 Tempo 替换成其他 Trace 后端,应用端也不一定需要修改。

Collector 还可以统一完成:

  • 数据批处理

  • 数据过滤

  • 属性补充

  • 采样

  • 多后端转发

  • 重试和队列缓冲

因此,本实验采用更加标准的结构:

Application ↓ Collector ↓ Tempo ↓ Grafana

四、安装 Tempo

前面的 Prometheus 和 Grafana 已经安装在:

monitoring

Namespace 中。

为了方便 Grafana 访问,这一篇也将 Tempo 安装在:

monitoring

Namespace 中。

1. 添加 Grafana Helm Repository

如果前面安装 Loki 时已经添加过,可以直接执行更新:

helm repo add grafana https://grafana.github.io/helm-charts helm repo update

查看 Tempo Chart:

helm search repo grafana/tempo

Grafana 提供了单体和分布式 Tempo Helm 部署方式;对于本实验,使用单体grafana/tempoChart 即可。

2. 准备 tempo-values.yaml

创建配置文件:

vim tempo-values.yaml

内容如下:

tempo: # 关闭匿名使用情况上报 reportingEnabled: false # 开启 OTLP 接收端口 receivers: otlp: protocols: grpc: endpoint: 0.0.0.0:4317 http: endpoint: 0.0.0.0:4318 # 单节点实验环境不使用持久化存储 persistence: enabled: false service: type: ClusterIP

这里开启了两个 OTLP 接收协议:

4317 OTLP/gRPC 4318 OTLP/HTTP

本篇主要使用:

4317 OTLP/gRPC

Tempo 的 OTLP Receiver 默认可能只监听本地地址,因此在 Kubernetes 中需要明确配置为:

0.0.0.0:4317 0.0.0.0:4318

这样其他 Pod 才能通过 Kubernetes Service 访问。Tempo 官方配置文档也说明,Receiver 默认可能监听 localhost,若需要接收外部容器发送的数据,应配置监听地址。

3. 关于临时存储

这里设置了:

persistence: enabled: false

这意味着 Tempo 数据只用于实验。

如果 Tempo Pod 被删除或重新创建,已经存储的 Trace 可能丢失。

因此,这套配置适用于:

  • 学习 Tempo

  • 验证 OTLP 链路

  • 测试 Grafana Trace 查询

  • 单节点可观测实验室

不适合生产环境。

生产环境通常应该使用:

  • PVC

  • Amazon S3

  • Google Cloud Storage

  • Azure Blob Storage

  • 其他对象存储

Tempo 官方也建议生产环境优先使用对象存储;本地文件系统更加适合单体测试和开发场景。

4. 安装 Tempo

执行:

helm install tempo grafana/tempo \ -n monitoring \ -f tempo-values.yaml

查看 Helm Release:

helm list -n monitoring

查看 Pod:

kubectl get pods -n monitoring

正常情况下应该看到类似结果:

tempo-0 1/1 Running

不同版本的 Helm Chart,Pod 名称和容器数量可能略有差异。

5. 查看 Tempo Service

执行:

kubectl get svc -n monitoring

应该可以看到:

tempo

进一步查看端口:

kubectl get svc tempo -n monitoring

结果中通常可以看到:

3200/TCP 4317/TCP 4318/TCP

它们分别对应:

3200 Tempo HTTP 查询接口 4317 OTLP/gRPC 4318 OTLP/HTTP

Tempo 的完整 Kubernetes Service DNS 为:

tempo.monitoring.svc.cluster.local

后续 OpenTelemetry Collector 将数据发送到:

tempo.monitoring.svc.cluster.local:4317

6. 查看 Tempo 日志

执行:

kubectl logs -n monitoring statefulset/tempo --tail=100

如果当前 Chart 创建的不是 StatefulSet,也可以先查看资源:

kubectl get deployment,statefulset -n monitoring

然后根据实际资源名称查看日志。

如果 Tempo 正常启动,日志中不应该持续出现:

address already in use

或者:

connection refused

等错误。


五、安装 OpenTelemetry Collector

Tempo 已经能够接收 Trace,接下来部署 OpenTelemetry Collector。

Collector 官方 Helm Chart 要求显式设置运行模式,可选值包括:

daemonset deployment statefulset

本篇只需要一个集中接收 Trace 的 Collector,因此使用:

deployment

官方当前安装示例推荐使用:

otel/opentelemetry-collector-k8s

镜像。

1. 添加 OpenTelemetry Helm Repository

执行:

helm repo add open-telemetry \ https://open-telemetry.github.io/opentelemetry-helm-charts helm repo update

查看 Chart:

helm search repo open-telemetry/opentelemetry-collector

2. 创建 observability Namespace

创建专门用于 Collector 和测试应用的 Namespace:

kubectl create namespace observability

如果 Namespace 已经存在,会提示:

AlreadyExists

也可以使用更加幂等的写法:

kubectl create namespace observability \ --dry-run=client -o yaml | kubectl apply -f -

检查:

kubectl get namespace

应该可以看到:

observability

六、准备 Collector 配置

创建配置文件:

vim otel-collector-values.yaml

内容如下:

mode: deployment image: repository: otel/opentelemetry-collector-k8s alternateConfig: extensions: health_check: endpoint: ${env:MY_POD_IP}:13133 receivers: otlp: protocols: grpc: endpoint: ${env:MY_POD_IP}:4317 http: endpoint: ${env:MY_POD_IP}:4318 processors: memory_limiter: check_interval: 5s limit_percentage: 80 spike_limit_percentage: 25 batch: {} exporters: otlp/tempo: endpoint: tempo.monitoring.svc.cluster.local:4317 tls: insecure: true service: extensions: - health_check pipelines: traces: receivers: - otlp processors: - memory_limiter - batch exporters: - otlp/tempo ports: otlp: enabled: true otlp-http: enabled: true jaeger-compact: enabled: false jaeger-thrift: enabled: false jaeger-grpc: enabled: false zipkin: enabled: false service: type: ClusterIP resources: limits: memory: 256Mi requests: cpu: 50m memory: 128Mi

这里使用了:

alternateConfig:

而不是直接使用:

config:

原因是 OpenTelemetry Collector Chart 自带默认配置,其中包括:

  • Logs Pipeline

  • Metrics Pipeline

  • Debug Exporter

  • Jaeger Receiver

  • Zipkin Receiver

如果直接覆盖部分config,Helm 会将自定义内容与默认内容合并。

对于本篇只处理 Trace 的最小环境来说,可能会引入不必要的配置。

alternateConfig不与默认配置合并,可以提供一份完全独立的 Collector 配置。但使用这种方式时,必须保留健康检查扩展,否则 Chart 的 Readiness 和 Liveness Probe 可能失败。

1. Receiver

下面的配置表示 Collector 接收 OTLP 数据:

receivers: otlp: protocols: grpc: endpoint: ${env:MY_POD_IP}:4317 http: endpoint: ${env:MY_POD_IP}:4318

支持两种协议:

OTLP/gRPC 4317 OTLP/HTTP 4318

2. Processor

这里配置了两个 Processor:

memory_limiter: batch:

memory_limiter用于限制 Collector 内存占用。

batch会将多个 Span 组成批次后再发送,从而减少网络请求次数。

因此,处理过程大致是:

接收 Span │ ▼ 检查内存限制 │ ▼ 批量处理 │ ▼ 发送给 Tempo

3. Exporter

下面的配置表示将 Trace 发送到 Tempo:

exporters: otlp/tempo: endpoint: tempo.monitoring.svc.cluster.local:4317 tls: insecure: true

由于 Collector 和 Tempo 都运行在同一个 Kubernetes Cluster 内部,因此可以使用 Kubernetes Service DNS:

tempo.monitoring.svc.cluster.local

本实验没有配置 TLS,所以设置:

insecure: true

4. Pipeline

Trace Pipeline 如下:

pipelines: traces: receivers: - otlp processors: - memory_limiter - batch exporters: - otlp/tempo

完整的数据流为:

OTLP Receiver │ ▼ Memory Limiter │ ▼ Batch Processor │ ▼ OTLP Tempo Exporter

七、安装 OpenTelemetry Collector

执行:

helm install otel-collector \ open-telemetry/opentelemetry-collector \ -n observability \ -f otel-collector-values.yaml

查看 Helm Release:

helm list -n observability

1. 查看 Pod

执行:

kubectl get pods -n observability

正常情况下可以看到类似结果:

otel-collector-opentelemetry-collector-xxxxxxxxxx-xxxxx 1/1 Running

2. 查看 Deployment

执行:

kubectl get deployment -n observability

应该可以看到:

otel-collector-opentelemetry-collector

3. 查看 Service

执行:

kubectl get svc -n observability

应该可以看到:

otel-collector-opentelemetry-collector

查看具体端口:

kubectl get svc \ otel-collector-opentelemetry-collector \ -n observability

应该包含:

4317/TCP 4318/TCP

完整 Service DNS 为:

otel-collector-opentelemetry-collector.observability.svc.cluster.local

4. 查看 Collector 日志

执行:

kubectl logs \ -n observability \ deployment/otel-collector-opentelemetry-collector \ --tail=100

不同版本的 Collector 日志格式可能略有差异。

正常情况下应该能够看到 OTLP Receiver 和健康检查扩展启动,并且不应该持续出现:

connection refused

或者:

failed to export

等错误。

此时链路的基础设施部分已经完成:

OpenTelemetry Collector │ ▼ Tempo │ ▼ Grafana

但是目前还没有应用产生 Trace。

接下来部署一个最小 Python 应用。


八、创建最小 Trace Demo

为了避免一次部署复杂的 OpenTelemetry Demo 系统,本篇只创建一个最简单的 HTTP 应用。

每次访问:

/

应用会生成一个 Trace,其中包含三个 Span:

http-request │ ├── step-1 └── step-2

两个子步骤分别模拟:

step-1 100 ms step-2 200 ms

通过这个简单例子,可以直观看到:

  • Trace

  • Root Span

  • Child Span

  • Span Duration

  • Span Attribute

  • Service Name

1. 创建 demo-config.yaml

创建文件:

vim demo-config.yaml

内容如下:

apiVersion: v1 kind: ConfigMap metadata: name: demo-trace-app namespace: observability data: app.py: | import os import time from flask import Flask from opentelemetry import trace from opentelemetry.sdk.resources import Resource from opentelemetry.sdk.trace import TracerProvider from opentelemetry.sdk.trace.export import BatchSpanProcessor from opentelemetry.exporter.otlp.proto.grpc.trace_exporter import ( OTLPSpanExporter, ) app = Flask(__name__) service_name = os.getenv( "OTEL_SERVICE_NAME", "demo-trace" ) otlp_endpoint = os.getenv( "OTEL_EXPORTER_OTLP_ENDPOINT", "otel-collector-opentelemetry-collector." "observability.svc.cluster.local:4317" ) resource = Resource.create({ "service.name": service_name, "deployment.environment": "k8s-lab", "service.version": "1.0.0" }) provider = TracerProvider( resource=resource ) exporter = OTLPSpanExporter( endpoint=otlp_endpoint, insecure=True ) processor = BatchSpanProcessor( exporter ) provider.add_span_processor( processor ) trace.set_tracer_provider( provider ) tracer = trace.get_tracer( "demo-trace" ) @app.route("/") def hello(): with tracer.start_as_current_span( "http-request" ) as span: span.set_attribute( "demo.tag", "v1" ) span.set_attribute( "http.route", "/" ) with tracer.start_as_current_span( "step-1" ): time.sleep(0.1) with tracer.start_as_current_span( "step-2" ): time.sleep(0.2) return "hello otel trace\n" @app.route("/slow") def slow(): with tracer.start_as_current_span( "slow-request" ) as span: span.set_attribute( "demo.slow", True ) with tracer.start_as_current_span( "slow-operation" ): time.sleep(1) return "slow trace generated\n" if __name__ == "__main__": app.run( host="0.0.0.0", port=8080 )

这个程序显式设置了几个 Resource Attribute:

service.name deployment.environment service.version

其中最重要的是:

service.name = demo-trace

后续 Grafana 将根据这个属性查询服务。

应用 ConfigMap:

kubectl apply -f demo-config.yaml

检查:

kubectl get configmap -n observability

应该可以看到:

demo-trace-app

九、部署 Demo Application

创建:

vim demo-app.yaml

内容如下:

apiVersion: apps/v1 kind: Deployment metadata: name: demo-trace namespace: observability spec: replicas: 1 selector: matchLabels: app: demo-trace template: metadata: labels: app: demo-trace spec: containers: - name: demo-trace image: python:3.11-slim command: - sh - -c args: - | pip install --no-cache-dir \ flask \ opentelemetry-api \ opentelemetry-sdk \ opentelemetry-exporter-otlp && echo "Starting demo trace application" && python /app/app.py env: - name: OTEL_SERVICE_NAME value: demo-trace - name: OTEL_EXPORTER_OTLP_ENDPOINT value: >- otel-collector-opentelemetry-collector.observability.svc.cluster.local:4317 ports: - name: http containerPort: 8080 readinessProbe: httpGet: path: / port: 8080 initialDelaySeconds: 3 periodSeconds: 5 resources: requests: cpu: 50m memory: 64Mi limits: memory: 256Mi volumeMounts: - name: app mountPath: /app volumes: - name: app configMap: name: demo-trace-app

应用:

kubectl apply -f demo-app.yaml

查看 Deployment:

kubectl get deployment -n observability

查看 Pod:

kubectl get pods -n observability

刚开始可能会看到:

ContainerCreating

随后进入:

Running

由于容器启动时需要执行:

pip install

第一次启动可能需要等待一段时间。

查看应用日志:

kubectl logs \ -n observability \ deployment/demo-trace \ -f

正常情况下应该可以看到:

Starting demo trace application Running on http://0.0.0.0:8080


十、访问 Demo 并生成 Trace

为了从 Kubernetes Node 访问 Demo,先安装socat,执行:

sudo apt update sudo apt install -y socat

验证:

command -v socat

应该输出:

/usr/bin/socat

然后使用:

kubectl port-forward \ -n observability \ deployment/demo-trace \ 8080:8080

这里直接使用:

deployment/demo-trace

而不是填写具体 Pod 名称。

因为 Pod 名称包含随机字符串,例如:

demo-trace-5ffd95c654-hs448

Pod 重新创建后名称会发生变化,而 Deployment 名称保持稳定。

端口转发成功后,会看到类似输出:

Forwarding from 127.0.0.1:8080 -> 8080 Forwarding from [::1]:8080 -> 8080

保持这个终端不关闭。

重新打开另一个终端,多访问几次:

curl http://localhost:8080 curl http://localhost:8080 curl http://localhost:8080

输出:

hello otel trace

再访问慢请求:

curl http://localhost:8080/slow

输出:

slow trace generated

每执行一次请求,应用都会生成一条新的 Trace。

此时完整链路为:

curl │ ▼ Demo Application │ │ OpenTelemetry SDK ▼ OpenTelemetry Collector │ │ OTLP/gRPC ▼ Tempo

正常使用kubectl port-forward时,一般不需要额外安装socat

只有在特定旧环境或特殊转发工具明确报告缺少socat时,才需要单独处理。


十一、在 Grafana 中配置 Tempo

进入 Grafana。

依次打开:

Connections ↓ Add new connection ↓ Tempo ↓ Add new data source

填写 URL:

http://tempo.monitoring.svc.cluster.local:3200

这里使用的是:

Tempo HTTP Query API

而不是 OTLP 数据接收端口。

两者的作用不同:

4317 Collector 向 Tempo 写入 Trace 3200 Grafana 从 Tempo 查询 Trace

本实验中的 Grafana 和 Tempo 都运行在 Kubernetes Cluster 内部,因此 Grafana 可以通过 Kubernetes Service DNS 访问 Tempo。

点击:

Save & Test

如果看到类似提示:

Data source is working

说明 Grafana 已经能够查询 Tempo。


十二、在 Grafana 中查询 Trace

进入:

Explore

选择数据源:

Tempo

1. 使用 Search 页面查询

可以在查询界面中选择:

Service Name

然后选择:

demo-trace

点击:

Run query

应该可以看到刚才生成的 Trace。

注意:这里的Limit默认是20,查询的Trace可能较少,可以自行改大。

2. 使用 TraceQL 查询

也可以切换到 TraceQL 模式,输入:

{ resource.service.name = "demo-trace" }

这里需要注意,TraceQL 的完整查询需要使用花括号。

不是:

service.name = "demo-trace"

而是:

{ resource.service.name = "demo-trace" }

3. 查询普通请求

查询 Root Span:

{ name = "http-request" }

4. 查询慢请求

查询:

{ name = "slow-request" }

或者根据自定义属性查询:

{ span.demo.slow = true }

5. 根据环境查询

查询:

{ resource.deployment.environment = "k8s-lab" }

6. 根据版本查询

查询:

{ resource.service.version = "1.0.0" }

十三、查看完整 Trace

点击其中一条 Trace,可以看到类似结构:

demo-trace: http-request │ ├── http-request 300 ms │ ├── step-1 100 ms │ └── step-2 200 ms

其中:

http-request

是 Root Span。

下面两个是 Child Span:

step-1 step-2

可以看到:

step-1 大约 100 ms step-2 大约 200 ms

对于慢请求,则可以看到:

slow-request └── slow-operation 大约 1 s

这就是链路追踪最核心的能力:

将一次请求拆分成多个步骤,并显示每个步骤的耗时。

如果真实系统中出现延迟,就可以判断时间主要消耗在:

  • HTTP 请求处理

  • 数据库查询

  • 外部接口调用

  • 消息队列

  • 缓存访问

  • 业务计算


十四、Trace、Span 和上下文传播

在本篇 Demo 中,我们创建了一个父 Span:

with tracer.start_as_current_span( "http-request" ):

然后在父 Span 内创建两个子 Span:

with tracer.start_as_current_span( "step-1" ):

以及:

with tracer.start_as_current_span( "step-2" ):

OpenTelemetry 会自动识别当前上下文,因此形成:

http-request │ ├── step-1 └── step-2

这就是 Span 上下文传播。

如果没有正确传播上下文,可能会变成三条互不相关的 Trace:

Trace A http-request Trace B step-1 Trace C step-2

而不是一条完整调用链。

在真正的分布式系统中,上下文还需要通过 HTTP Header 在服务之间传播。

常见 Header 为:

traceparent

例如:

Frontend │ │ traceparent ▼ Backend │ │ traceparent ▼ Database Service

这样不同服务产生的 Span 才能被组合成同一条 Trace。

本篇 Demo 只在一个进程内部创建父子 Span,因此 OpenTelemetry SDK 可以自动处理上下文。


十五、为什么使用 Collector,而不是直接写入 Tempo?

现在的链路是:

Application │ ▼ Collector │ ▼ Tempo

看起来比直接连接 Tempo 多了一层。

但是 Collector 带来了几个重要好处。

1. 应用与存储后端解耦

应用只需要知道:

OTLP Endpoint

不需要了解 Tempo 的具体实现。

以后后端变更时,可以只修改 Collector。

2. 批量发送

Collector 使用:

batch processor

将多个 Span 合并后发送,减少网络请求次数。

3. 数据处理

Collector 可以在发送前:

  • 删除敏感字段

  • 添加 Kubernetes Metadata

  • 修改属性

  • 丢弃无用数据

  • 对 Trace 进行采样

4. 多后端输出

同一份 Trace 可以同时发送到多个系统:

Application │ ▼ Collector │ │ ▼ ▼ Tempo Another Backend

5. 统一入口

多个应用可以统一发送到 Collector:

Frontend ──┐ Backend ──┼──► Collector ──► Tempo Worker ──┘

应用不需要分别维护后端连接。


十六、清理测试资源

本篇创建的:

demo-trace ConfigMap demo-trace Deployment

主要用于生成测试 Trace。

确认已经能够在 Grafana 中查询 Trace 后,可以删除:

kubectl delete -f demo-app.yaml kubectl delete -f demo-config.yaml

检查:

kubectl get pods -n observability

此时应该只保留 OpenTelemetry Collector。

Collector 和 Tempo 可以继续保留,因为后续还可以用于:

  • 接入真实应用

  • 演示跨服务 Trace

  • 将 Trace 与 Logs 关联

  • 将 Trace 与 Metrics 关联

  • 进行故障注入实验

如果希望删除整个 Collector 和 Demo 环境,可以执行:

helm uninstall otel-collector \ -n observability kubectl delete namespace observability

如果还需要删除 Tempo:

helm uninstall tempo \ -n monitoring

不过本系列后续还会继续使用 Tempo,因此暂时建议保留:

Tempo OpenTelemetry Collector Grafana

本系列采用的资源管理原则仍然是:

基础设施组件:继续保留 临时测试业务:验证完成后删除

这样既能保持实验连续性,也可以避免无用 Pod 不断堆积。


十七、小结:Metrics、Logs 和 Tracing

到这里,单节点 Kubernetes 可观测实验室已经完成了三项核心能力。

Metrics

Kubernetes Metrics │ ▼ Prometheus │ ▼ Grafana

Metrics 主要回答:

系统发生了什么?

例如:

  • CPU 是否过高

  • Memory 是否不足

  • Pod 是否频繁重启

  • 请求延迟是否上升

Logs

Pod stdout / stderr │ ▼ Fluent Bit │ ▼ Loki │ ▼ Grafana

Logs 主要回答:

为什么会出现问题?

例如:

  • 数据库连接失败

  • 配置文件缺失

  • 权限错误

  • 应用异常退出

Tracing

Application │ ▼ OpenTelemetry Collector │ ▼ Tempo │ ▼ Grafana

Tracing 主要回答:

问题发生在哪个调用步骤?

例如:

  • 哪个服务最慢

  • 哪次数据库查询耗时过长

  • 请求经过了哪些服务

  • 某个步骤花费了多长时间

将三者放在一起:

Metrics + Logs + Tracing

就形成了一个相对完整的可观测体系。

可以简单理解为:

Metrics 发现问题 Logs 解释问题 Tracing 定位问题

现在,我们的单节点 Kubernetes 实验室已经具备:

Prometheus Grafana Loki Fluent Bit Tempo OpenTelemetry Collector

完整链路为:

Metrics ──► Prometheus ──┐ │ Logs ─────► Loki ────────┼──► Grafana │ Traces ───► Tempo ───────┘

当然,目前三种数据仍然相对独立。

真正更有价值的可观测体验,是将它们关联起来:

从 Metrics 发现延迟升高 │ ▼ 进入对应 Trace │ ▼ 定位最慢 Span │ ▼ 查看相关 Pod 日志

这也是后续可以继续完善的方向。

需要专业的网站建设服务?

联系我们获取免费的网站建设咨询和方案报价,让我们帮助您实现业务目标

立即咨询