使用 OpenSearch 安装 Alauda Distributed Tracing
安装 Alauda Distributed Tracing 平台包括以下步骤:
- 安装 Alauda Build of OpenTelemetry v2 Operator
- 部署 Alauda Build of Jaeger v2
- 部署 OpenTelemetry Collector,将 trace 转发到 Jaeger
安装 Alauda Build of OpenTelemetry v2 Operator
Alauda Build of OpenTelemetry v2 Operator 管理 Jaeger v2 和 OpenTelemetry Collector 实例的生命周期。在部署任何 tracing 组件之前,必须先安装此 Operator。
通过 Web 控制台安装
按照 Alauda Build of OpenTelemetry v2 文档中 通过 Web 控制台安装 部分中的说明进行操作。
通过 CLI 安装
按照 Alauda Build of OpenTelemetry v2 文档中 通过 CLI 安装 部分中的说明进行操作。
部署 Alauda Build of Jaeger v2
Jaeger v2 以由 Alauda Build of OpenTelemetry v2 Operator 管理的 OpenTelemetryCollector 自定义资源形式部署。它使用后端存储,并通过 OAuth2 Proxy sidecar 与 Alauda Container Platform 身份验证系统集成。
先决条件
- 已安装 Alauda Container Platform Application Observability(之前称为 Alauda Build of OpenTelemetry v2)Operator。
- 有可用的 OpenSearch 3.x 实例,并且拥有其 endpoint URL、用户名和密码。
- 由具有
cluster-admin 角色的集群管理员建立的活动 ACP CLI (kubectl) 会话。
- 已安装
jq 命令行工具。
操作步骤
-
设置用于连接 OpenSearch 的用户可配置环境变量:
export OPENSEARCH_ENDPOINT='<OpenSearch endpoint URL>'
export OPENSEARCH_USER='<OpenSearch username>'
export OPENSEARCH_PASS='<OpenSearch password>'
将占位值替换为实际的 OpenSearch 凭据。
-
从集群中获取平台配置和 Jaeger 相关容器镜像:
export PLATFORM_URL=$(kubectl -nkube-public get configmap global-info -o jsonpath='{.data.platformURL}')
export CLUSTER_NAME=$(kubectl -nkube-public get configmap global-info -o jsonpath='{.data.clusterName}')
export ALB_CLASS_NAME=$(kubectl -nkube-public get configmap global-info -o jsonpath='{.data.systemAlbIngressClassName}')
export OIDC_ISSUER=$(kubectl -nkube-public get configmap global-info -o jsonpath='{.data.oidcIssuer}')
OIDC_CLIENT_SECRET_REF=$(kubectl -nkube-public get configmap global-info -o jsonpath='{.data.oidcClientSecretRef}')
if [ -n "$OIDC_CLIENT_SECRET_REF" ]; then
SYSTEM_NAMESPACE=$(kubectl -nkube-public get configmap global-info -o jsonpath='{.data.systemNamespace}')
export OIDC_CLIENT_ID=$(kubectl -n"$SYSTEM_NAMESPACE" get secret "$OIDC_CLIENT_SECRET_REF" -o go-template='{{index .data "client-id"}}' | base64 -d)
export OIDC_CLIENT_SECRET=$(kubectl -n"$SYSTEM_NAMESPACE" get secret "$OIDC_CLIENT_SECRET_REF" -o go-template='{{index .data "client-secret"}}' | base64 -d)
else
export OIDC_CLIENT_ID=$(kubectl -nkube-public get configmap global-info -o jsonpath='{.data.oidcClientID}')
export OIDC_CLIENT_SECRET=$(kubectl -nkube-public get configmap global-info -o jsonpath='{.data.oidcClientSecret}')
fi
JAEGER_RELATED_IMAGES=$(kubectl get csv -n opentelemetry-operator2 \
-l 'operators.coreos.com/opentelemetry-operator2.opentelemetry-operator2=' \
-o jsonpath='{.items[0].spec.relatedImages}')
export JAEGER_IMAGE=$(echo "$JAEGER_RELATED_IMAGES" | jq -r '.[] | select(.name=="component.jaeger") | .image')
export JAEGER_ES_INDEX_CLEANER_IMAGE=$(echo "$JAEGER_RELATED_IMAGES" | jq -r '.[] | select(.name=="component.jaeger-es-index-cleaner") | .image')
export JOAUTH2_PROXY_IMAGE=$(echo "$JAEGER_RELATED_IMAGES" | jq -r '.[] | select(.name=="component.oauth2-proxy") | .image')
-
设置默认环境变量。可以根据部署要求调整这些值:
# Namespace for the Jaeger instance
export JAEGER_NS="jaeger-system"
# Name of the Jaeger instance
export JAEGER_INSTANCE_NAME="jaeger"
# Index prefix for Jaeger data
export JAEGER_ES_INDEX_PREFIX="acp-${CLUSTER_NAME}"
# Maximum age of spans the Jaeger query service will search. Keep aligned with the index-cleaner retention.
export JAEGER_MAX_SPAN_AGE="168h"
# Base path for the Jaeger UI
export JAEGER_BASEPATH="/clusters/${CLUSTER_NAME}/jaeger"
-
创建 Jaeger 命名空间和 OpenSearch 凭据 Secret:
kubectl get namespace ${JAEGER_NS} &> /dev/null || kubectl create namespace ${JAEGER_NS}
kubectl create secret generic opensearch-credentials \
--namespace=${JAEGER_NS} \
--from-literal=OPENSEARCH_USER=${OPENSEARCH_USER} \
--from-literal=OPENSEARCH_PASS=${OPENSEARCH_PASS} \
--dry-run=client -o yaml | kubectl apply -f -
验证 Secret 是否已创建:
kubectl get secret opensearch-credentials -n ${JAEGER_NS}
-
创建 OAuth2 Proxy 的 Secret,用于将 Jaeger UI 与 Alauda Container Platform 身份验证集成:
# Generate a cookie secret for the OAuth2 Proxy:
OAUTH2_PROXY_COOKIE_SECRET=$(dd if=/dev/urandom bs=32 count=1 2>/dev/null | base64 | tr -d -- '\n' | tr -- '+/' '-_')
# Create the Secret:
kubectl create secret generic ${JAEGER_INSTANCE_NAME}-oauth2-proxy \
--namespace=${JAEGER_NS} \
--from-literal=OAUTH2_PROXY_CLIENT_SECRET=${OIDC_CLIENT_SECRET} \
--from-literal=OAUTH2_PROXY_COOKIE_SECRET=${OAUTH2_PROXY_COOKIE_SECRET} \
--dry-run=client -o yaml | kubectl apply -f -
-
创建名为 jaeger.yaml 的文件,内容如下:
jaeger.yaml
apiVersion: opentelemetry.io/v1beta1
kind: OpenTelemetryCollector
metadata:
labels:
prometheus: kube-prometheus
name: ${JAEGER_INSTANCE_NAME}
namespace: ${JAEGER_NS}
spec:
image: "${JAEGER_IMAGE}"
mode: deployment
replicas: 1
resources:
requests:
cpu: 100m
memory: 256Mi
limits:
cpu: "2"
memory: 2Gi
ports:
- name: oauth2-proxy
port: 4180
- name: jaeger-grpc
port: 16685
observability:
metrics:
enableMetrics: true
volumes:
- name: opensearch-credentials
secret:
secretName: opensearch-credentials
items:
- key: OPENSEARCH_PASS
path: pass
- name: oauth2-proxy-secrets
secret:
secretName: ${JAEGER_INSTANCE_NAME}-oauth2-proxy
items:
- key: OAUTH2_PROXY_CLIENT_SECRET
path: client-secret
- key: OAUTH2_PROXY_COOKIE_SECRET
path: cookie-secret
volumeMounts:
- name: opensearch-credentials
mountPath: /etc/jaeger/opensearch-credentials
readOnly: true
config:
receivers:
otlp:
protocols:
grpc:
endpoint: "0.0.0.0:4317"
http:
endpoint: "0.0.0.0:4318"
processors:
batch: {}
memory_limiter:
check_interval: 1s
limit_percentage: 80
spike_limit_percentage: 20
exporters:
debug: {}
jaeger_storage_exporter:
trace_storage: opensearch_storage
extensions:
healthcheckv2:
use_v2: true
http:
endpoint: "0.0.0.0:13133"
jaeger_storage:
backends:
opensearch_storage:
opensearch:
server_urls:
- "${OPENSEARCH_ENDPOINT}"
auth:
basic:
username: "${OPENSEARCH_USER}"
password_file: /etc/jaeger/opensearch-credentials/pass
tls:
insecure_skip_verify: true
service_cache_ttl: 12h
max_span_age: "${JAEGER_MAX_SPAN_AGE}"
indices:
index_prefix: "${JAEGER_ES_INDEX_PREFIX}"
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
jaeger_query:
storage:
traces: opensearch_storage
ui:
config_file: ""
base_path: "${JAEGER_BASEPATH}"
http:
endpoint: 0.0.0.0:16686
service:
extensions: [healthcheckv2, jaeger_storage, jaeger_query]
pipelines:
traces:
receivers: [otlp]
processors: [memory_limiter, batch]
exporters: [debug, jaeger_storage_exporter]
telemetry:
resource:
service.name: jaeger
metrics:
level: detailed
readers:
- pull:
exporter:
prometheus:
host: "0.0.0.0"
port: 8888
without_scope_info: true
without_type_suffix: true
without_units: true
logs:
level: info
additionalContainers:
- name: oauth2-proxy
image: ${JOAUTH2_PROXY_IMAGE}
args:
- --http-address=0.0.0.0:4180
- --upstream=http://127.0.0.1:16686
- --proxy-prefix=${JAEGER_BASEPATH}/oauth2
- --redirect-url=${PLATFORM_URL}${JAEGER_BASEPATH}/oauth2/callback
- --provider=oidc
- --oidc-issuer-url=${OIDC_ISSUER}
- --scope=openid profile email groups ext
- --email-domain=*
- --code-challenge-method=S256
- --insecure-oidc-allow-unverified-email=true
- --cookie-secure=false
- --skip-provider-button=true
- --ssl-insecure-skip-verify=true
- --skip-jwt-bearer-tokens=true
- --client-id=${OIDC_CLIENT_ID}
- --client-secret-file=/etc/oauth2-proxy/client-secret
- --cookie-secret-file=/etc/oauth2-proxy/cookie-secret
resources:
requests:
cpu: 50m
memory: 64Mi
limits:
cpu: 500m
memory: 256Mi
volumeMounts:
- name: oauth2-proxy-secrets
mountPath: /etc/oauth2-proxy
readOnly: true
ports:
- containerPort: 4180
name: oauth2-proxy
protocol: TCP
prometheus: kube-prometheus 标签会被自动创建的 ServiceMonitor 资源继承,从而使 ACP Prometheus 能够抓取 Jaeger 指标。
- Jaeger v2 容器镜像。这不是默认的 OpenTelemetry Collector 镜像,而是基于 OpenTelemetry Collector framework 构建的自定义 Jaeger binary。
- Jaeger 容器的资源请求和限制。请根据预期的 trace 量进行调整;吞吐量较高的环境可能需要更多 CPU 和内存。
- 为 Jaeger 实例启用 Prometheus 指标 endpoint。
jaeger_storage 扩展配置用于存储 trace 数据的 OpenSearch backend。
opensearch driver 选择 OpenSearch 存储实现。Jaeger 对 OpenSearch 使用与 Elasticsearch 相同的实现。
service_cache_ttl 控制 service name cache 的保留时长。默认值为 12h。如果 index retention 较短,请减小此值,以确保 Jaeger UI 能够及时发现服务。
max_span_age 是 query service 将搜索的 span 最大年龄,此处设置为 JAEGER_MAX_SPAN_AGE。请将其与 jaeger-es-index-cleaner retention 保持一致,以免 UI 查询已经删除的 indices。
index_prefix 必须与 jaeger-es-index-cleaner CronJob 使用的 INDEX_PREFIX 匹配,否则 cleaner 无法找到要删除的 indices。有关 shards 和 replicas 调优的详细信息,请参阅 Shards and Replicas。
rollover_frequency: day 与 date_layout 一起生成每日 indices,例如 ${JAEGER_ES_INDEX_PREFIX}-jaeger-span-YYYY-MM-DD。这些不带 rollover alias 的普通每日 indices 会由 jaeger-es-index-cleaner 根据日期后缀进行匹配。
jaeger_query 扩展为 Jaeger Query API 和 Jaeger UI 提供服务。
additionalContainers 部分定义 OAuth2 Proxy sidecar,该 sidecar 通过与 Alauda Container Platform Dex identity provider 集成来处理 Jaeger UI 的身份验证。
- OAuth2 Proxy sidecar 的资源请求和限制。由于此容器仅代理身份验证请求,因此资源需求较低。
-
使用 envsubst 渲染 manifest 并应用配置:
envsubst < jaeger.yaml | kubectl apply -f -
-
等待 Jaeger Pod 就绪:
kubectl rollout status deployment/${JAEGER_INSTANCE_NAME}-collector \
-n ${JAEGER_NS} --timeout=180s
-
部署 jaeger-es-index-cleaner,定期删除过期的 indices。
为什么不使用
jaeger-es-rollover init?
jaeger-es-rollover 工具的 init 子命令会调用 Elasticsearch 的 _ilm/policy/... endpoint,以验证是否存在 ILM policy,但 OpenSearch 使用 _plugins/_ism/policies/...。两者不兼容,因此 init 在 OpenSearch 上会失败(请参阅 jaegertracing/jaeger#7121)。
本指南使用“每日 indices 加 jaeger-es-index-cleaner”,不依赖 rollover aliases,因此不需要 jaeger-es-rollover init。
工作原理
OpenSearch backend 会写入每日 indices,例如 acp-<cluster>-jaeger-span-2026-04-22。jaeger-es-index-cleaner 会匹配名称为 <prefix>-jaeger-(span|service|dependencies|sampling)-YYYY-MM-DD 的 indices,将日期后缀与“今天减去 N 天”进行比较,并删除早于 retention period 的 indices。
设置 index-cleaner 环境变量:
# Index retention in days: indices older than this are deleted
export JAEGER_INDEX_RETENTION_DAYS="7"
# Daily execution time (UTC). For example, "30 2 * * *" means 02:30 UTC.
export JAEGER_CLEANER_SCHEDULE="30 2 * * *"
INFO
retention 参数与 Jaeger 的关系
为避免 Jaeger UI 查询 cleaner 刚刚删除的 indices,请使 JAEGER_INDEX_RETENTION_DAYS(cleaner retention)与 Jaeger 的 max_span_age(JAEGER_MAX_SPAN_AGE)保持一致。例如,将两者都设置为 7 天(168h)。
-
创建 jaeger-index-cleaner.yaml,将 index-cleaner 部署为 CronJob:
jaeger-index-cleaner.yaml
apiVersion: batch/v1
kind: CronJob
metadata:
name: ${JAEGER_INSTANCE_NAME}-es-index-cleaner
namespace: ${JAEGER_NS}
spec:
schedule: "${JAEGER_CLEANER_SCHEDULE}"
concurrencyPolicy: Forbid
successfulJobsHistoryLimit: 3
failedJobsHistoryLimit: 3
jobTemplate:
spec:
backoffLimit: 3
template:
spec:
restartPolicy: Never
containers:
- name: jaeger-es-index-cleaner
image: "${JAEGER_ES_INDEX_CLEANER_IMAGE}"
args:
- "${JAEGER_INDEX_RETENTION_DAYS}"
- "${OPENSEARCH_ENDPOINT}"
env:
- name: INDEX_PREFIX
value: "${JAEGER_ES_INDEX_PREFIX}"
- name: INDEX_DATE_SEPARATOR
value: "-"
- name: ES_TLS_ENABLED
value: "true"
- name: ES_TLS_SKIP_HOST_VERIFY
value: "true"
- name: ES_USERNAME
valueFrom:
secretKeyRef:
name: opensearch-credentials
key: OPENSEARCH_USER
- name: ES_PASSWORD
valueFrom:
secretKeyRef:
name: opensearch-credentials
key: OPENSEARCH_PASS
resources:
requests:
cpu: 50m
memory: 64Mi
limits:
cpu: 500m
memory: 256Mi
schedule 使用标准 Cron 表达式(UTC)。请在非高峰时段安排;通常每天运行一次即可。
concurrencyPolicy: Forbid 确保上一次清理仍在运行时不会启动新的 Job,从而避免并发删除操作对 OpenSearch 造成短暂压力。
args 是 jaeger-es-index-cleaner 的位置参数:第一个参数是保留天数,第二个参数是 OpenSearch endpoint。ROLLOVER=true 有意不设置,因此使用默认的每日 index 匹配模式。
INDEX_PREFIX 必须与 Jaeger 的 indices.index_prefix 完全匹配(此处为 acp-<cluster>),否则 cleaner 无法找到对应的 indices。
ES_TLS_SKIP_HOST_VERIFY=true 对应 Jaeger 侧的 insecure_skip_verify: true TLS policy。如果改为使用自签名 CA 强化 TLS,请将 CA 挂载到容器中,并将 ES_TLS_CA_FILE 设置为其路径。
渲染并部署 CronJob:
envsubst < jaeger-index-cleaner.yaml | kubectl apply -f -
-
为命名空间添加标签,并创建 Ingress 以公开 Jaeger UI:
kubectl label namespace ${JAEGER_NS} cpaas.io/project=cpaas-system --overwrite
kubectl apply -n ${JAEGER_NS} -f - <<EOF
apiVersion: networking.k8s.io/v1
kind: Ingress
metadata:
name: ${JAEGER_INSTANCE_NAME}
annotations:
nginx.ingress.kubernetes.io/enable-cors: "true"
spec:
ingressClassName: ${ALB_CLASS_NAME}
rules:
- http:
paths:
- path: ${JAEGER_BASEPATH}
pathType: ImplementationSpecific
backend:
service:
name: ${JAEGER_INSTANCE_NAME}-collector
port:
number: 4180
EOF
等待 Ingress 就绪:
kubectl wait --for=jsonpath='{.status.loadBalancer.ingress}' ingress/${JAEGER_INSTANCE_NAME} \
-n ${JAEGER_NS} --timeout=180s
验证
访问 <platform-url>/clusters/<cluster-name>/jaeger 上的 Jaeger UI,其中 <platform-url> 是 Alauda Container Platform URL,<cluster-name> 是集群名称。
运行以下命令打印 Jaeger UI URL:
echo "Jaeger UI: ${PLATFORM_URL}${JAEGER_BASEPATH}"
部署 OpenTelemetry Collector
Jaeger v2 运行后,部署一个 OpenTelemetry Collector 实例,以接收经过插桩的应用程序发送的 trace 数据,并将其转发到 Jaeger。
-
创建名为 otel-collector.yaml 的文件,内容如下:
otel-collector.yaml
apiVersion: opentelemetry.io/v1beta1
kind: OpenTelemetryCollector
metadata:
labels:
prometheus: kube-prometheus
name: otel
namespace: ${JAEGER_NS}
spec:
mode: deployment
replicas: 1
resources:
requests:
cpu: 100m
memory: 256Mi
limits:
cpu: "2"
memory: 2Gi
observability:
metrics:
enableMetrics: true
config:
receivers:
otlp:
protocols:
grpc:
endpoint: 0.0.0.0:4317
http:
endpoint: 0.0.0.0:4318
zipkin: {}
processors:
batch: {}
memory_limiter:
check_interval: 1s
limit_percentage: 80
spike_limit_percentage: 20
exporters:
debug: {}
otlp/traces:
endpoint: "${JAEGER_INSTANCE_NAME}-collector.${JAEGER_NS}.svc.cluster.local:4317"
tls:
insecure: true
prometheus:
add_metric_suffixes: false
endpoint: "0.0.0.0:8889"
resource_to_telemetry_conversion:
enabled: true # by default resource attributes are dropped
service:
pipelines:
traces:
receivers: [otlp, zipkin]
processors: [memory_limiter, batch]
exporters: [debug, otlp/traces]
metrics:
receivers: [otlp]
processors: [memory_limiter, batch]
exporters: [debug, prometheus]
telemetry:
metrics:
readers:
- pull:
exporter:
prometheus:
host: 0.0.0.0
port: 8888
without_scope_info: true
without_type_suffix: true
without_units: true
prometheus: kube-prometheus 标签使 ACP Prometheus 能够通过自动创建的 ServiceMonitor 抓取 Collector 指标。
- Collector 容器的资源请求和限制。请根据预期的 trace 吞吐量进行调整。
- 使 Operator 能够自动为 Collector 的指标端点创建
ServiceMonitor 资源。
- OTLP receiver 通过 gRPC(端口
4317)和 HTTP(端口 4318)接收经过插桩的应用程序发送的 trace 数据。
otlp/traces exporter 将接收到的 trace 转发到 Jaeger collector 服务。端点根据 Jaeger 实例名称和命名空间派生。
- trace pipeline 通过 OTLP 和 Zipkin 接收数据,经由
memory_limiter 和 batch 处理后,同时导出到 debug exporter(用于日志记录)和 otlp/traces(用于转发到 Jaeger)。
-
使用 envsubst 渲染 manifest 并应用配置:
envsubst < otel-collector.yaml | kubectl apply -f -
-
等待 Collector pod 就绪:
kubectl rollout status deployment/otel-collector \
-n ${JAEGER_NS} --timeout=180s
验证
安装所有组件后,生成示例 trace 数据,以验证端到端 tracing pipeline。
-
部署 telemetrygen 作为测试客户端,以生成示例 trace:
kubectl apply -f - <<EOF
apiVersion: v1
kind: Pod
metadata:
name: telemetrygen
namespace: ${JAEGER_NS}
spec:
restartPolicy: Never
containers:
- name: telemetrygen
image: ghcr.io/open-telemetry/opentelemetry-collector-contrib/telemetrygen:latest
args:
- traces
- --otlp-endpoint=otel-collector.${JAEGER_NS}.svc.cluster.local:4317
- --otlp-insecure
- --duration=150s
- --interval=5s
- --child-spans=3
- --rate=2
- --service=telemetrygen
- --workers=1
EOF
# Wait for telemetrygen to complete, then clean up the test Pod
kubectl wait -n ${JAEGER_NS} --for=jsonpath='{.status.phase}'=Succeeded pod/telemetrygen --timeout=10m
kubectl delete pod -n ${JAEGER_NS} telemetrygen
NOTE
--otlp-endpoint 必须指向上一步部署的 OpenTelemetry Collector 服务。
-
在 <platform-url>/clusters/<cluster-name>/jaeger 打开 Jaeger UI。
从 Service 下拉菜单中选择 telemetrygen 服务,然后单击 Find Traces,以验证是否可以看到生成的 trace。
运行以下命令以打印 Jaeger UI URL:
echo "Jaeger UI: ${PLATFORM_URL}${JAEGER_BASEPATH}"
服务性能监控(SPM)在 Jaeger UI 中以 Monitor 选项卡的形式呈现,它会聚合 span 数据以生成 RED(请求、错误、持续时间)指标。这样无需预先了解服务名称或操作名称,即可识别性能问题。有关更多详细信息,请参阅服务性能监控(SPM)。
启用 SPM 需要在 Jaeger 内部运行 SpanMetrics Connector 以生成 RED 指标,并通过 loadbalancing exporter 将 span 从前端 OpenTelemetry Collector 路由到 Jaeger,从而确保即使两个组件都运行多个从节点,指标仍保持准确。Jaeger 会在 Prometheus endpoint 上公开这些指标,并通过兼容 PromQL 的后端将其提供给 Monitor 选项卡。
前提条件
- 已部署 Jaeger v2 和 OpenTelemetry Collector(已完成之前的所有步骤)。
- 集群中提供 ACP 监控。
操作步骤
-
从集群中获取监控 endpoint 和凭据:
export MONITORING_URL=$(kubectl get feature monitoring -o jsonpath='{.spec.accessInfo.database.address}')
MONITORING_SECRET_NAME=$(kubectl get feature monitoring -o jsonpath='{.spec.accessInfo.database.basicAuth.secretName}')
export MONITORING_USERNAME=$(kubectl -ncpaas-system get secret "$MONITORING_SECRET_NAME" -o jsonpath="{.data.username}" | base64 -d)
export MONITORING_PASSWORD=$(kubectl -ncpaas-system get secret "$MONITORING_SECRET_NAME" -o jsonpath="{.data.password}" | base64 -d)
-
创建用于存储监控凭据的 Secret:
kubectl create secret generic monitoring-credentials \
--namespace=${JAEGER_NS} \
--from-literal=username=${MONITORING_USERNAME} \
--from-literal=password=${MONITORING_PASSWORD} \
--dry-run=client -o yaml | kubectl apply -f -
-
修补 OpenTelemetry Collector,使其通过 loadbalancing exporter 将 span 转发到 Jaeger,而不是使用直接的 otlp/traces exporter。借助 routing_key: service,给定服务的所有 span 都会一致地发送到同一个 Jaeger 从节点,因此在 Jaeger 内部运行的 SpanMetrics Connector(下一步)会对每个服务仅聚合一次。这可以确保当 Collector 或 Jaeger 运行多个从节点时,指标仍然正确:
kubectl patch opentelemetrycollector otel -n ${JAEGER_NS} --type=merge -p "
spec:
config:
exporters:
loadbalancing:
routing_key: service
protocol:
otlp:
tls:
insecure: true
resolver:
dns:
hostname: ${JAEGER_INSTANCE_NAME}-collector-headless.${JAEGER_NS}.svc.cluster.local
port: '4317' # the dns resolver requires the port as a string
service:
pipelines:
traces:
exporters: [debug, loadbalancing]
"
dns resolver 会通过 OpenTelemetry Operator 自动配置的无头 Service(${JAEGER_INSTANCE_NAME}-collector-headless)发现每个 Jaeger collector Pod,因此无需额外的 Service 或 RBAC。
等待 Collector 重启:
kubectl rollout status deployment/otel-collector \
-n ${JAEGER_NS} --timeout=180s
-
创建名为 jaeger-spm-patch.yaml 的文件,内容如下。此修补程序会在 Jaeger 内部运行 SpanMetrics Connector,在 Prometheus endpoint 上公开生成的 RED 指标,并添加 PromQL 指标后端,以便 Jaeger 将这些指标提供给 Monitor 选项卡:
jaeger-spm-patch.yaml
spec:
volumes:
- name: opensearch-credentials
secret:
secretName: opensearch-credentials
items:
- key: OPENSEARCH_PASS
path: pass
- name: oauth2-proxy-secrets
secret:
secretName: ${JAEGER_INSTANCE_NAME}-oauth2-proxy
items:
- key: OAUTH2_PROXY_CLIENT_SECRET
path: client-secret
- key: OAUTH2_PROXY_COOKIE_SECRET
path: cookie-secret
- name: monitoring-credentials
secret:
secretName: monitoring-credentials
items:
- key: username
path: user
- key: password
path: pass
volumeMounts:
- name: opensearch-credentials
mountPath: /etc/jaeger/opensearch-credentials
readOnly: true
- name: monitoring-credentials
mountPath: /etc/jaeger/monitoring-credentials
readOnly: true
config:
connectors:
spanmetrics: {}
exporters:
prometheus:
add_metric_suffixes: false # Jaeger expects standard OTel metric names without _total suffixes
endpoint: "0.0.0.0:8889"
resource_to_telemetry_conversion:
enabled: true
extensions:
basicauth/monitoring:
client_auth:
username_file: /etc/jaeger/monitoring-credentials/user
password_file: /etc/jaeger/monitoring-credentials/pass
jaeger_storage:
metric_backends:
monitoring_metrics_storage:
prometheus:
endpoint: ${MONITORING_URL}
tls:
insecure_skip_verify: true
auth:
authenticator: basicauth/monitoring
jaeger_query:
storage:
metrics: monitoring_metrics_storage
service:
extensions: [basicauth/monitoring, healthcheckv2, jaeger_storage, jaeger_query]
pipelines:
traces:
exporters: [debug, jaeger_storage_exporter, spanmetrics]
metrics/spanmetrics:
receivers: [spanmetrics]
exporters: [prometheus]
monitoring-credentials 卷会将监控 basic-auth 凭据挂载到 Jaeger 容器中。
monitoring-credentials volumeMount 会使凭据在 /etc/jaeger/monitoring-credentials/ 处可用。
spanmetrics connector 会根据 Jaeger 接收的 span 生成 RED 指标。由于 Collector 会将每个服务路由到单个 Jaeger 从节点,因此每个从节点都会正确聚合互不重叠的服务集合。
prometheus exporter 会在端口 8889 上公开生成的指标。Jaeger 实例已带有 prometheus: kube-prometheus 标签和 observability.metrics.enableMetrics: true(在 jaeger.yaml 中设置),因此 Operator 会自动创建 ServiceMonitor,使 ACP Prometheus 能够抓取此 endpoint。
basicauth/monitoring extension 为监控指标 endpoint 提供 basic authentication。
metric_backends 部分配置 Jaeger 用于查询 SPM 数据的兼容 PromQL 指标存储。
- 在
jaeger_query extension 中引用指标存储。
- 必须将
basicauth/monitoring extension 添加到 service.extensions 列表中,才能使其生效。
traces pipeline 现在还会导出到 spanmetrics(存储和指标生成),而专用的 metrics/spanmetrics pipeline 会将生成的指标转发到 prometheus exporter。
WARNING
volumes、volumeMounts、service.extensions 和 pipeline exporters 字段都是数组。合并修补程序会完全替换数组,而不是向其中追加内容。上面的修补文件包含所有现有条目以及新增条目,以防止数据丢失。
-
应用修补程序:
kubectl patch opentelemetrycollector ${JAEGER_INSTANCE_NAME} -n ${JAEGER_NS} \
--type=merge -p "$(envsubst < jaeger-spm-patch.yaml)"
等待 Jaeger 重启:
kubectl rollout status deployment/${JAEGER_INSTANCE_NAME}-collector \
-n ${JAEGER_NS} --timeout=180s
扩展到多个从节点
要在高可用模式下运行 SPM,请增加 spec.replicas 在 otel 和 ${JAEGER_INSTANCE_NAME} collector 中的值;无需进行其他更改。无状态 Collector 层可以自由扩展,并且由于 span 由 service 进行负载均衡,每个 Jaeger 从节点都拥有互不重叠的服务集合,并且能够无冲突地聚合这些服务。请注意以下事项:
验证
启用 SPM 后,可以按照上方验证部分中的说明,部署 telemetrygen 测试客户端来进行验证。
生成 trace 后,在 Jaeger UI 中转到 Monitor 选项卡,查看 telemetrygen 服务聚合后的 RED 指标。
卸载
要从集群中移除 Alauda Distributed Tracing 组件,请按照卸载 Alauda Distributed Tracing中的说明操作。