jaeger部署
前言:
jaeger有两个大版本,一个是1.x,另一个是2.x。对于部署镜像来说,1.x拆分成了collector、query等多个镜像;而2.x版本则是打包成了一个镜像,部署时可以通过配置文件指定其是collector还是query。
以下部署方案是2.x的
1.jaeger部署,all-in-one模式,使用opensearch作为存储后端
配置文件参考https://github.com/jaegertracing/jaeger/tree/v2.3.0/cmd/jaeger目录下的
auth.basic和tls的配置都是网上找的,官方示例并没有
apiVersion: v1 data:
config-ui.json: |-
{
"monitor": {
"menuEnabled": true ##开启monitor的页面
}
} config.yaml: | service: extensions: [jaeger_storage, jaeger_query, healthcheckv2] ##可以通过这个配置指定是query还是collector,两个pod(可调副本)都是用一个镜像,可以配不同svc。collector把jaeger_query去掉即可,但query需要保留所有。otel-agent往collector吐数据就行 pipelines: traces: receivers: [otlp] processors: [batch] exporters: [jaeger_storage_exporter] telemetry: resource: service.name: jaeger metrics: level: detailed readers: - pull: exporter: prometheus: host: 0.0.0.0 port: 8888 logs: level: debug # TODO Initialize telemetry tracer once OTEL released new feature. # https://github.com/open-telemetry/opentelemetry-collector/issues/10663 extensions: healthcheckv2: use_v2: true http: jaeger_query: storage: traces: some_storage traces_archive: another_storage
metrics: some_storage #monitor的tag页面指标 ui: config_file: /etc/config/config-ui.json jaeger_storage: backends: some_storage: &opensearch_config opensearch: server_urls: - https://100.10.10.10:9200 auth: basic: username: "admin" password: "admin" tls: insecure_skip_verify: true ###跳过opensearch的tls认证 indices: index_prefix: "jaeger-main" spans: date_layout: "2006-01-02" rollover_frequency: "day" shards: 5 ###如果数据量很大,可以增加这个分片数 replicas: 1 services: date_layout: "2006-01-02" rollover_frequency: "day" shards: 5 replicas: 1 dependencies: date_layout: "2006-01-02" rollover_frequency: "day" shards: 5 replicas: 1 sampling: date_layout: "2006-01-02" rollover_frequency: "day" shards: 5 replicas: 1 another_storage: opensearch: server_urls: - https://100.10.10.10:9200 auth: basic: username: "admin" password: "admin" tls: insecure_skip_verify: true ###跳过opensearch的tls认证 indices: index_prefix: "jaeger-archive"
metric_backends some_storage: *opensearch_config ###指标也配置使用opensearch存储 receivers: otlp: protocols: grpc: endpoint: 0.0.0.0:4317 http: endpoint: 0.0.0.0:4318 jaeger: protocols: grpc: endpoint: 0.0.0.0:14250 thrift_compact: endpoint: 0.0.0.0:6831 thrift_binary: endpoint: 0.0.0.0:6832 processors: batch: exporters: jaeger_storage_exporter: trace_storage: some_storage kind: ConfigMap metadata: name: xdd-jaeger-cm namespace: pero --- apiVersion: apps/v1 kind: Deployment metadata: name: xdd-jaeger-deployment namespace: pero spec: replicas: 2 selector: matchLabels: name: xdd-jaeger strategy: type: RollingUpdate rollingUpdate: maxSurge: 25% maxUnavailable: 25% template: metadata: labels: name: xdd-jaeger spec: affinity: podAntiAffinity: preferredDuringSchedulingIgnoredDuringExecution: - weight: 100 podAffinityTerm: labelSelector: matchExpressions: - key: name operator: In values: - xdd-jaeger topologyKey: "kubernetes.io/hostname" containers: - args: - --config=/etc/config/config.yaml image: jaegertracing/jaeger:v2.3.0 imagePullPolicy: Always name: xdd-jaeger-container ports: - containerPort: 16685 name: port-1 protocol: TCP - containerPort: 16686 name: port-2 protocol: TCP - containerPort: 5778 name: port-3 protocol: TCP - containerPort: 5779 name: port-4 protocol: TCP - containerPort: 27777 name: port-5 protocol: TCP - containerPort: 27778 name: port-6 protocol: TCP - containerPort: 4317 name: port-7 protocol: TCP - containerPort: 4318 name: port-8 protocol: TCP - containerPort: 6831 name: port-9 protocol: TCP - containerPort: 6832 name: port-10 protocol: TCP - containerPort: 14268 name: port-11 protocol: TCP - containerPort: 14250 name: port-12 protocol: TCP volumeMounts: - mountPath: /etc/config name: xdd-jaeger-cm dnsPolicy: ClusterFirst volumes: - configMap: defaultMode: 420 name: xdd-jaeger-cm name: xdd-jaeger-cm --- apiVersion: v1 kind: Service metadata: name: xdd-jaeger-svc namespace: pero spec: ipFamilies: - IPv4 - IPv6 ipFamilyPolicy: RequireDualStack ports: - name: port-1 port: 16685 protocol: TCP targetPort: 16685 - name: port-2 port: 16686 protocol: TCP targetPort: 16686 - name: port-3 port: 5778 protocol: TCP targetPort: 5778 - name: port-4 port: 5779 protocol: TCP targetPort: 5779 - name: port-5 port: 27777 protocol: TCP targetPort: 27777 - name: port-6 port: 27778 protocol: TCP targetPort: 27778 - name: port-7 port: 4317 protocol: TCP targetPort: 4317 - name: port-8 port: 4318 protocol: TCP targetPort: 4318 - name: port-9 port: 6831 protocol: TCP targetPort: 6831 - name: port-10 port: 6832 protocol: TCP targetPort: 6832 - name: port-11 port: 14268 protocol: TCP targetPort: 14268 - name: port-12 port: 14250 protocol: TCP targetPort: 14250 selector: name: xdd-jaeger sessionAffinity: None type: ClusterIP
2.部署完成后,可以访问opensearch查看索引,可以看到有jaeger开头的索引
curl https://100.10.10.10:9200/_cat/indices --insecure -u'admin:admin'
3.访问jaeger页面
100.10.10.10:16686
4.通过curl命令手动发送traces数据给jaeger
#!/bin/bash # Jaeger Collector 服务地址 JAEGER_SERVICE="xdd-jaeger-svc.pero" JAEGER_PORT="9411" URL="http://${JAEGER_SERVICE}:${JAEGER_PORT}/api/v2/spans" # 生成随机 Trace ID 和 Span ID generate_id() { cat /dev/urandom | tr -dc 'a-f0-9' | fold -w 16 | head -n 1 } TRACE_ID=$(generate_id) SPAN_ID=$(generate_id) TIMESTAMP=$(date +%s)000000 # 转换为微秒 echo "正在向 Jaeger 发送追踪数据..." echo "Jaeger 地址: ${URL}" echo "Trace ID: ${TRACE_ID}" # 构建 JSON 数据 JSON_DATA=$(cat << EOF [ { "traceId": "${TRACE_ID}", "id": "${SPAN_ID}", "name": "manual-test-span", "timestamp": ${TIMESTAMP}, "duration": 45000, "kind": "SERVER", "localEndpoint": { "serviceName": "manual-test-service", "ipv4": "10.0.0.1" }, "tags": { "http.method": "GET", "http.path": "/test-endpoint", "http.status_code": "200", "environment": "testing", "test_type": "curl_script" } } ] EOF ) # 发送请求 response=$(curl -s -w "%{http_code}" -X POST "${URL}" \ -H "Content-Type: application/json" \ -d "${JSON_DATA}") http_code=${response: -3} if [ "$http_code" -eq 202 ] || [ "$http_code" -eq 200 ]; then echo "追踪数据发送成功! HTTP 状态码: ${http_code}" echo "请在 Jaeger UI 中搜索 Trace ID: ${TRACE_ID}" else echo "发送失败! HTTP 状态码: ${http_code}" echo "响应内容: ${response%???}" fi
5.otel发送数据到jaeger
receivers:
otlp:
protocols:
grpc:
endpoint: 0.0.0.0:4317
http:
endpoint: 0.0.0.0:4318
exporters:
otlp/jaeger:
endpoint: 100.10.10.10:4317 ###配置jaeger的4317端口,通过grpc协议发送otel格式的数据
tls:
insecure: true
processors:
#batch:
k8sattributes:
resource:
attributes:
- key: app.host.ip
from_attribute: k8s.pod.ip
action: insert
#extensions:
# zpages: {}
# memory_ballast:
# # Memory Ballast size should be max 1/3 to 1/2 of memory.
# size_mib: 165
service:
#extensions: [zpages, memory_ballast]
pipelines:
traces:
receivers: [otlp]
processors: [k8sattributes, resource]
exporters: [otlp/jaeger] ###配置jaeger生效
手动发送数据到otel
#!/bin/bash # 生成当前时间戳(纳秒) current_time=$(date +%s000000000) start_time=$((current_time - 150000000)) # 150ms前 end_time=$current_time # 创建临时JSON文件 cat > /tmp/trace_payload.json << EOF { "resourceSpans": [ { "resource": { "attributes": [ { "key": "service.name", "value": { "stringValue": "xdd-service" } } ] }, "scopeSpans": [ { "scope": { "name": "manual-instrumentation" }, "spans": [ { "traceId": "$(openssl rand -hex 16)", "spanId": "$(openssl rand -hex 8)", "name": "GET /api/v1/users/{id}", "kind": 2, "startTimeUnixNano": "$start_time", "endTimeUnixNano": "$end_time", "attributes": [ { "key": "http.method", "value": { "stringValue": "GET" } }, { "key": "http.route", "value": { "stringValue": "/api/v1/users/:id" } }, { "key": "http.status_code", "value": { "intValue": 200 } } ], "status": { "code": 0 } } ] } ] } ] } EOF # 发送到OpenTelemetry Collector curl -X POST http://197.166.76.242:4318/v1/traces \ -H "Content-Type: application/json" \ -d @/tmp/trace_payload.json echo "Trace sent with duration: 150ms"
查看索引里面的数据
curl -XGET --insecure -u 'admin:admin' \ 'https://100.10.10.10:9200/jaeger-main-jaeger-service-2025-11-07/_search' \ -H 'Content-Type: application/json' \ -d '{ "query": { "term": { "process.serviceName": "xdd-service" } }, "size": 5 }'
6.定时删除opensearch的数据和索引
apiVersion: batch/v1
kind: CronJob
metadata:
name: jaeger-index-cleaner
namespace: pero
spec:
schedule: "0 2 * * *"
successfulJobsHistoryLimit: 1
failedJobsHistoryLimit: 1
jobTemplate:
spec:
template:
spec:
containers:
- name: jaeger-index-cleaner
image: jaeger:2.3.0
imagePullPolicy: Always
command:
- /bin/sh
- -c
- sh /apps/jaeger-index-cleaner.sh
volumeMounts:
- mountPath: /apps/
name: jaeger-index-cleaner-config
volumes:
- configMap:
defaultMode: 420
name: jaeger-index-cleaner-config
name: jaeger-index-cleaner-config
restartPolicy: OnFailure
---
apiVersion: v1
data:
jaeger-index-cleaner.sh: |-
#!/bin/bash
# 配置变量
OPENSEARCH_URL="https://192.168.211.11:9200"
USERNAME="admin"
PASSWORD="admin"
# 数据保留3天
RETENTION_DAYS_DATA=3
# 删除RETENTION_DAYS_INDEX + 1天之前的索引
RETENTION_DAYS_INDEX=2
current_time=$(date "+%Y-%m-%d %H:%M:%S")
echo "----------------------$current_time------------------------"
LAST_DATE=$(date -d "-${RETENTION_DAYS_INDEX} days" "+%Y-%m-%d")
echo "删除${LAST_DATE}之前的索引"
# 获取索引并筛选,注意过滤索引的关键字,不要误删其他索引
curl -s $OPENSEARCH_URL/_cat/indices?v --insecure -u "${USERNAME}:${PASSWORD}" \
| grep jaeger | awk '{print $3}' | while read idx; do
# 提取日期
d=$(echo $idx | grep -oE '[0-9]{4}-[0-9]{2}-[0-9]{2}')
[ -z "$d" ] && continue
# 时间戳对比,删除LAST_DATE之前的索引
if [ $(date -d $d +%s) -lt $(date -d $LAST_DATE +%s) ]; then
echo $idx
echo "curl -s -XDELETE --insecure -u '${USERNAME}:${PASSWORD}' '${OPENSEARCH_URL}/${idx}'" | bash -x
echo -e '\n'
fi
done
# 删除索引中的数据
curl -s -XPOST --insecure -u "${USERNAME}:${PASSWORD}" "${OPENSEARCH_URL}/jaeger-main*/_delete_by_query?pretty" -H 'Content-Type: application/json' -d'{
"query": {
"range": {
"startTimeMillis": {
"lt": "now-'"${RETENTION_DAYS_DATA}"'d"
}
}
}
}'
kind: ConfigMap
metadata:
name: jaeger-index-cleaner-config
namespace: pero

浙公网安备 33010602011771号