Jaeger All-in-One 部署
Step 1:创建命名空间
kubectl create namespace observability
Step 2:部署 Jaeger All-in-One
创建文件 jaeger-all-in-one.yaml:
[root@k3s-server jaeger]# cat jaeger-all-in-one.yaml
apiVersion: apps/v1
kind: Deployment
metadata:
name: jaeger
namespace: observability
labels:
app: jaeger
spec:
replicas: 1
selector:
matchLabels:
app: jaeger
template:
metadata:
labels:
app: jaeger
spec:
containers:
- name: jaeger
image: jaegertracing/all-in-one:1.62.0
ports:
# Jaeger UI 网页
- containerPort: 16686
name: ui
# Collector gRPC 老jaeger‑sdk
- containerPort: 14250
name: grpc
# Collector HTTP thrift 老http上报
- containerPort: 14268
name: http
# Agent compact thrift UDP
- containerPort: 6831
protocol: UDP
name: agent-compact
# --------新增OTLP端口声明(备注)--------
- containerPort: 4317
name: otlp-grpc
- containerPort: 4318
name: otlp-http
env:
- name: COLLECTOR_OTLP_ENABLED
value: "true"
resources:
limits:
memory: "512Mi"
cpu: "500m"
---
apiVersion: v1
kind: Service
metadata:
name: jaeger
namespace: observability
spec:
selector:
app: jaeger
ports:
- name: ui
port: 16686
targetPort: ui
- name: grpc
port: 14250
targetPort: grpc
- name: http
port: 14268
targetPort: http
- name: agent-compact
port: 6831
protocol: UDP
targetPort: agent-compact
# --------新增OTLP Service转发端口--------
- name: otlp-grpc
port: 4317
targetPort: otlp-grpc
- name: otlp-http
port: 4318
targetPort: otlp-http
type: ClusterIP
Step 3:应用部署
kubectl apply -f jaeger-all-in-one.yaml
Step 4:验证 Pod 运行状态
kubectl get pods -n observability
Step 5:访问 Jaeger UI
# 端口转发到本地
kubectl port-forward svc/jaeger 16686:16686 -n observability --address 0.0.0.0
然后浏览器打开:http://localhost:16686
你应该能看到 Jaeger 的 Web 界面 🎉
Step6:部署一个示例应用
[root@k3s-server jaeger]# cat otel-demo.yaml
apiVersion: apps/v1
kind: Deployment
metadata:
name: otel-demo
namespace: observability
labels:
app: otel-demo
spec:
replicas: 1
selector:
matchLabels:
app: otel-demo
template:
metadata:
labels:
app: otel-demo
spec:
containers:
- name: otel-demo
image: ghcr.io/open-telemetry/opentelemetry-collector-contrib/telemetrygen:latest
args:
- "traces"
- "--otlp-endpoint=jaeger:4317"
- "--otlp-insecure"
- "--service=otel-demo-service"
- "--duration=60s"
- "--rate=1"
resources:
limits:
memory: "128Mi"
cpu: "200m"
kubectl apply -f otel-demo.yaml
Pod 是否运行
kubectl get pods -n observability
Step7:查看日志,确认数据真的发出去了
kubectl logs -n observability deployment/otel-demo
Step8:去 Jaeger UI 查看
打开 Jaeger UI:
kubectl port-forward svc/jaeger 16686:16686 -n observability --address 0.0.0.0
浏览器打开:
http://ip:16686
然后:
-
左侧 Service 下拉框里找:
otel-demo-service -
点击 Find Traces
-
点任意一条 Trace
Trace
└── otel-demo-service
└── 一个 Span
这就说明:
应用已经成功把追踪数据发给 Jaeger 了。
Step9:这节课最重要的理解
不要急着写代码,先记住这句话:
应用要产生追踪数据,必须集成 OpenTelemetry SDK。
SDK 会帮应用做三件事:
| SDK 做的事 | 通俗理解 |
|---|---|
| 生成 TraceID | 给整条请求一个编号 |
| 生成 Span | 记录"这一步做了什么、花了多久" |
| 发送数据 | 把记录发给 Jaeger |
配置采样率yaml
apiVersion: apps/v1
kind: Deployment
metadata:
name: otel-demo
namespace: observability
spec:
replicas: 1
selector:
matchLabels:
app: otel-demo
template:
metadata:
labels:
app: otel-demo
spec:
containers:
- name: otel-demo
image: ghcr.io/open-telemetry/opentelemetry-collector-contrib/telemetrygen:latest
args:
- "traces"
- "--otlp-endpoint=jaeger:4317"
- "--otlp-insecure"
- "--service=otel-demo-sampling"
- "--duration=120s"
- "--rate=10"
env:
- name: OTEL_TRACES_SAMPLER
value: "parentbased_traceidratio"
- name: OTEL_TRACES_SAMPLER_ARG
value: "0.1"
resources:
limits:
memory: "128Mi"
cpu: "200m"
======================================
Jaeger 生产架构部署
小步骤 1:先理解生产架构长什么样
之前 All-in-One 是这样的:
应用 → Jaeger All-in-One → 内存存储 → UI
生产级架构会变成这样:
应用
↓
Jaeger Collector
↓
Elasticsearch
↓
Jaeger Query / UI
| 组件 | 作用 |
|---|---|
| Collector | 接收应用上报的追踪数据 |
| Elasticsearch | 持久化存储追踪数据 |
| Query / UI | 提供查询接口和可视化界面 |
小步骤 2:部署 Elasticsearch
kubectl create namespace observability
创建文件:
[root@k3s-server jaeger]# cat elasticsearch.yaml
apiVersion: apps/v1
kind: Deployment
metadata:
name: elasticsearch
namespace: observability
spec:
replicas: 1
selector:
matchLabels:
app: elasticsearch
template:
metadata:
labels:
app: elasticsearch
spec:
containers:
- name: elasticsearch
image: docker.elastic.co/elasticsearch/elasticsearch:8.15.0
ports:
- containerPort: 9200
env:
- name: discovery.type
value: "single-node"
- name: xpack.security.enabled
value: "false"
- name: ES_JAVA_OPTS
value: "-Xms512m -Xmx512m"
resources:
limits:
memory: "1Gi"
cpu: "500m"
---
apiVersion: v1
kind: Service
metadata:
name: elasticsearch
namespace: observability
spec:
selector:
app: elasticsearch
ports:
- port: 9200
targetPort: 9200
部署
kubectl apply -f elasticsearch.yaml
小步骤 3:确认 Elasticsearch 能访问
kubectl logs -n observability deployment/elasticsearch --tail=30
小步骤 4:部署 Jaeger Collector
[root@k3s-server jaeger]# cat jaeger-collector.yaml
apiVersion: apps/v1
kind: Deployment
metadata:
name: jaeger-collector
namespace: observability
spec:
replicas: 1
selector:
matchLabels:
app: jaeger-collector
template:
metadata:
labels:
app: jaeger-collector
spec:
containers:
- name: jaeger-collector
image: jaegertracing/jaeger-collector:1.62.0
env:
# ✅新版环境变量,去掉SPANS_前缀!
- name: SPAN_STORAGE_TYPE
value: "elasticsearch"
- name: ES_SERVER_URLS
value: "http://elasticsearch:9200"
ports:
- containerPort: 14250
- containerPort: 14268
- containerPort: 4317
- containerPort: 4318
resources:
limits:
memory: "512Mi"
cpu: "500m"
---
apiVersion: v1
kind: Service
metadata:
name: jaeger-collector
namespace: observability
spec:
selector:
app: jaeger-collector
ports:
- name: grpc
port: 14250
targetPort: 14250
- name: http
port: 14268
targetPort: 14268
- name: otlp-grpc
port: 4317
targetPort: 4317
- name: otlp-http
port: 4318
targetPort: 4318
部署:
kubectl apply -f jaeger-collector.yaml
检查:
kubectl get pods -n observability
小步骤 5:部署 Jaeger Query / UI
[root@k3s-server jaeger]# cat jaeger-query.yaml
apiVersion: apps/v1
kind: Deployment
metadata:
name: jaeger-query
namespace: observability
spec:
replicas: 1
selector:
matchLabels:
app: jaeger-query
template:
metadata:
labels:
app: jaeger-query
spec:
containers:
- name: jaeger-query
image: jaegertracing/jaeger-query:1.62.0
env:
- name: SPAN_STORAGE_TYPE
value: "elasticsearch"
- name: ES_SERVER_URLS
value: "http://elasticsearch:9200"
ports:
- containerPort: 16686
resources:
limits:
memory: "512Mi"
cpu: "500m"
---
apiVersion: v1
kind: Service
metadata:
name: jaeger-query
namespace: observability
spec:
selector:
app: jaeger-query
ports:
- port: 16686
targetPort: 16686
type: NodePort
部署:
kubectl apply -f jaeger-query.yaml
检查:
kubectl get pods -n observability
你应该看到三个核心 Pod:
elasticsearch
jaeger-collector
jaeger-query
小步骤 6:打开 Jaeger UI
执行:
kubectl port-forward svc/jaeger-query 16686:16686 -n observability --address 0.0.0.0
然后浏览器打开:
http://IP:16686
这时候界面应该能打开。
但现在还没有数据,因为还没有应用往 jaeger-collector 发追踪数据。
小步骤 7:部署一个测试应用,把数据发给 Collector
[root@k3s-server jaeger]# cat otel-demo-prod.yaml
apiVersion: apps/v1
kind: Deployment
metadata:
name: otel-demo
namespace: observability
spec:
replicas: 1
selector:
matchLabels:
app: otel-demo
template:
metadata:
labels:
app: otel-demo
spec:
containers:
- name: otel-demo
image: ghcr.io/open-telemetry/opentelemetry-collector-contrib/telemetrygen:latest
args:
- "traces"
- "--otlp-endpoint=jaeger-collector:4317"
- "--otlp-insecure"
- "--service=prod-demo-service"
- "--duration=120s"
- "--rate=2"
resources:
limits:
memory: "128Mi"
cpu: "200m"
部署:
kubectl apply -f otel-demo-prod.yaml
查看日志:
kubectl logs -n observability deployment/otel-demo --tail=20
如果看到它在生成或导出 traces,说明数据正在发往 Collector。
小步骤 8:去 Jaeger UI 验证
回到 Jaeger UI:
http://ip:16686
操作步骤:
- 左侧 Service 选择
prod-demo-service - 点击 Find Traces
- 点开一条 Trace
你应该能看到追踪数据已经存到 Elasticsearch,并通过 Query/UI 查出来了。
=============================================
Jaeger 知识点总结
一、基础概念
1. 是什么
Jaeger 是 Uber 开源的分布式追踪系统(Distributed Tracing) ,基于 OpenTracing 规范;现在社区主推 OpenTelemetry(OTel),Jaeger 可以直接接收 OTel 的追踪数据。
作用:微服务架构下,追踪一次请求跨多个服务的完整调用链路,定位慢请求、调用报错、性能瓶颈。
2. 核心术语(OpenTracing)
- Trace(追踪) :一次完整请求的全部链路,全局唯一
traceID,一条 Trace 由多个 Span 组成。 - Span(跨度) :链路里的一次操作 / 调用;有自己唯一
spanID;包含开始时间、结束时间、耗时;存在父子关系。 - Parent‑Span:父 Span,上游调用;子 Span 由父 Span 产生。
- Tag(标签):Span 的键值对结构化元数据,用于过滤(http.status_code、error=true)
- Log(日志事件):Span 内时间点事件,记录异常堆栈等
- Baggage(行李) :跨进程透传的自定义上下文,会随 trace 全链路传递,慎用,不要放大量数据。
上下文传播:TraceId、SpanId 需要跨服务传递,通过 HTTP Header /gRPC metadata 传递(trace propagation 传播)。
二、Jaeger 架构组件
整体架构分:采集 → 存储 → 查询 UI
-
Jaeger‑Agent(代理)
- 部署在每台主机 / Pod 上,Sidecar 方式;业务应用上报 span 数据发给本地 agent(UDP/HTTP)
- Agent 做聚合、转发,减轻业务应用压力;应用不需要直连 Collector。
也可以绕过 agent,业务直接上报给 Collector(开发环境常用)
-
Collector(收集器)
- 接收 Agent / 应用发来的 trace 数据;做校验、处理;写入后端存储。
- 支持接收:Jaeger 协议、OpenTelemetry (OTLP) 协议 ✅(新版本重点)
-
Query(查询服务)
- 查询后端存储里面的 trace 数据;提供 API;前端 UI 后端。
-
UI(Web 前端)
- Web 可视化页面;查询 TraceID;查看调用链路时序图、DAG 依赖图。
-
Storage(存储后端)
存储 适用场景 Memory 仅测试,重启丢失数据 Cassandra 官方原生,生产旧方案,运维重 Elasticsearch 最常用生产存储 Badger 本地磁盘存储,单节点小规模部署
💡新版本 Jaeger all‑in‑one:开发环境一键集成 agent+collector+query+ui+memory 存储,本地测试首选。
三、数据传播的两种模式
1. 注入 & 提取 Inject / Extract
- Inject:把 trace 上下文 写入传输载体(http header、grpc metadata),上游服务
- Extract:下游从载体读出 trace 上下文,继续创建子 span
2. 传播格式(Propagator)
jaeger:旧 Jaeger 原生头uber‑trace‑idw3c tracecontext:W3C 标准 traceparent/tracestate,OpenTelemetry 默认,优先用这个!
重点:全链路所有服务必须使用同一种传播器,否则链路断链!看不到完整 trace
四、部署模式
-
All‑in‑One(开发测试) 所有组件打包一个进程;内存存储;本地快速调试。
docker 快速启动
docker run -d --name jaeger
-p 16686:16686 \ # UI端口
-p 4317:4317 \ # OTLP grpc
-p 4318:4318 \ # OTLP http
jaegertracing/all-in-one:latest
端口记忆:
- 16686:Web UI
- 4317:OTLP‑gRPC(otel 推荐)
- 4318:OTLP‑HTTP
- 6831 UDP:旧 jaeger agent thrift
- 分布式生产部署 Agent (Sidecar DaemonSet) + Collector 集群 + Elasticsearch 存储 + Query + UI;K8s 环境 DaemonSet 部署 Jaeger‑Agent 每个节点一个。
五、Jaeger vs OpenTelemetry(高频面试)
历史演进: 旧方案:业务埋码使用 OpenTracing SDK →上报 Jaeger Agent →Jaeger Collector 存储 现状:OpenTracing 已经归档废弃,不再维护! ✅ 现在标准方案:业务使用 OpenTelemetry SDK 埋点生成 Trace,输出 OTLP 协议,直接发给 Jaeger Collector;Jaeger 作为后端存储 + 可视化,不再负责 SDK 埋点。
简单一句话:
- OpenTelemetry (OTel):负责埋点生成链路数据(SDK)
- Jaeger:负责接收、存储、查询可视化链路数据(后端服务)
六、核心使用场景 & 排查问题思路
排查步骤
- 在 UI 搜索 TraceID,拿到整条请求链路
- 看每个 span 耗时,定位慢的服务 / 接口(找出瓶颈)
- 查看 tag
error=true的 span 定位异常服务;查看 log 里异常堆栈 - 查看服务依赖 DAG 图,看服务之间调用拓扑
常见问题
- 链路断了,前后服务 Span 不在同一个 TraceID? 👉 传播器不一致;http header 被反向代理 (Nginx/Istio) 丢弃 traceparent 头。
- 没有上报数据,UI 查不到 trace 👉 确认 OTLP 地址;检查网络;确认采样策略。
- 数据量太大存储压力高 → 采样 (Sampling)
七、采样 Sampling(非常重要面试点)
微服务流量很大,不能 100% 全部采集所有请求 trace,会压垮存储;需要采样策略。
4 种采样策略
- Constant 常量采样
0全部丢弃;1全部采集;测试环境用 1,生产禁止 1。 - Probabilistic 概率采样 按 traceID 概率采集,比如 0.1 采集 10% 的链路;整条 Trace 要么全部保留,要么全部丢弃(基于 traceID,同一个 trace 所有 span 统一决策,不会出现半截链路)
- Rate‑Limiting 限速采样 限制每秒最多采集 N 条 trace;适合流量突增场景,控制采集 QPS 上限。
- Remote 远程采样(生产推荐) 采样策略配置放在 Jaeger Collector;SDK 远程拉取采样策略;改策略不用重启业务服务。
✅采样是基于 TraceID 决策,不是 Span!保证一条 trace 完整或者丢弃,不会出现残缺链路。
八、K8s + Istio + Jaeger
Istio 本身可以生成访问链路;Istio 可以把 trace 数据输出 OTLP 到 Jaeger;此时业务代码不需要手动埋点 SDK,Sidecar 代理层面自动采集链路。 缺点:只能采集网络层面;业务内部方法调用看不到 span;想要方法级链路,业务还是要 OTel SDK 埋点。
九、面试高频简答题整理
- Jaeger 作用?
分布式追踪,可视化微服务跨服务调用链路,定位慢查询、调用异常性能瓶颈。
- Trace、Span 关系?
Trace 是一次完整请求;Trace 由若干 Span 组成;Span 存在父子调用关系;每个 trace 拥有全局 traceId。
- Agent 的作用?
部署主机 / 节点本地;业务本地上报,转发给 Collector;解耦业务和 collector;缓冲数据。
- 什么是采样,为什么需要采样?
高流量微服务,全部上报 trace 存储压力大;采样选择性采集部分链路;采样决策基于 TraceID 保证链路完整性。
- OpenTelemetry 和 Jaeger 关系?
OTel 是新一代埋点 SDK 标准,生成 OTLP 追踪数据;Jaeger 作为后端接收存储展示 trace;OpenTracing 已经废弃。
- 链路断链一般排查什么?
W3C 传播器是否统一;网关是否丢弃 traceparent 请求头;网络是否连通;采样策略是否全部丢弃。
十、补充区分三件套
- Metrics (指标):Prometheus:统计计数器、耗时百分位,聚合指标
- Logs (日志):ELK/Loki:离散事件日志
- Tracing (链路追踪):Jaeger/Zipkin:单次完整调用链路
可观测性三大支柱:指标、日志、追踪。