使用 OpenSearch 安装 Alauda Distributed Tracing
安装 Alauda Distributed Tracing 平台涉及以下步骤:
- 安装 Alauda Build of Jaeger v2 集群插件
- 安装 Alauda Build of OpenTelemetry v2 Operator
- 部署 Alauda Build of Jaeger v2
- 部署 OpenTelemetry Collector 以将 trace 转发到 Jaeger
安装 Alauda Build of Jaeger v2 集群插件
Alauda Build of Jaeger v2 集群插件包含 tracing 组件所需的容器镜像:Jaeger(jaeger、jaeger-es-rollover、jaeger-es-index-cleaner)和 OAuth2 Proxy。安装该插件会将这些镜像同步到平台的内置 registry,并在目标集群的 cpaas-system 命名空间中创建一个名为 jaeger-cluster-plugin-manifest 的 ConfigMap。后续步骤会从该 ConfigMap 中读取镜像地址。
通过 Web 控制台安装
- 在平台管理视图中,导航到 Administrator > Marketplace > Cluster Plugins。
- 选择要部署 tracing 组件的集群。
- 找到 Alauda Build of Jaeger v2 并点击 Install。该插件不需要安装参数。
NOTE
如果插件未列出,请从 Customer Portal 下载插件包,并使用 violet 工具将其发布到平台,或者联系技术支持。
通过 CLI 安装
集群插件通过创建 ModuleInfo 资源来安装,且无论插件目标集群是哪一个,都需要在 global 集群 中创建。
-
在 global 集群中运行以下命令,检查已发布的插件版本:
kubectl get moduleconfigs -l cpaas.io/module-name=jaeger-cluster-plugin \
-o custom-columns=NAME:.metadata.name,VERSION:.spec.version
-
在 global 集群中创建一个 ModuleInfo 资源以安装插件。将 <target-cluster> 替换为要部署 tracing 组件的集群名称,并将 <plugin-version> 替换为上一步中的某个版本:
kubectl apply -f - <<EOF
apiVersion: cluster.alauda.io/v1alpha1
kind: ModuleInfo
metadata:
labels:
cpaas.io/cluster-name: <target-cluster>
cpaas.io/module-name: jaeger-cluster-plugin
cpaas.io/module-type: plugin
name: <target-cluster>-jaeger-cluster-plugin
spec:
config: {}
version: <plugin-version>
EOF
-
在 global 集群中验证安装:
kubectl get moduleinfo -l cpaas.io/module-name=jaeger-cluster-plugin
当 STATUS 列显示 Running 时,表示插件已成功安装。
-
验证 ConfigMap 是否已在目标集群中创建(在目标集群上执行):
kubectl get configmap jaeger-cluster-plugin-manifest -n cpaas-system
安装 Alauda Build of OpenTelemetry v2 Operator
Alauda Build of OpenTelemetry v2 Operator 管理 Jaeger v2 和 OpenTelemetry Collector 实例的生命周期。你必须先安装该 Operator,然后才能部署任何 tracing 组件。
通过 Web 控制台安装
请参阅 Alauda Build of OpenTelemetry v2 文档中的 Installing via the web console 章节。
通过 CLI 安装
请参阅 Alauda Build of OpenTelemetry v2 文档中的 Installing via the CLI 章节。
部署 Alauda Build of Jaeger v2
Jaeger v2 作为由 Alauda Build of OpenTelemetry v2 Operator 管理的 OpenTelemetryCollector 自定义资源进行部署。它使用 backend storage,并通过 OAuth2 Proxy sidecar 与 Alauda Container Platform 认证系统集成。
前提条件
- 已安装 Alauda Build of Jaeger v2 集群插件。
- 已安装 Alauda Build of OpenTelemetry v2 Operator。
- 已有可用的 OpenSearch 3.x 实例,并且你拥有其 endpoint URL、用户名和密码。
- 由具有
cluster-admin 角色的集群管理员建立的有效 ACP CLI (kubectl) 会话。
操作步骤
-
为连接 OpenSearch 设置用户可配置的环境变量:
export OPENSEARCH_ENDPOINT='<OpenSearch endpoint URL>'
export OPENSEARCH_USER='<OpenSearch username>'
export OPENSEARCH_PASS='<OpenSearch password>'
将占位符值替换为实际的 OpenSearch 凭据。
-
从集群中获取平台配置,以及从 Alauda Build of Jaeger v2 集群插件创建的 ConfigMap 中获取与 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
export JAEGER_IMAGE=$(kubectl -ncpaas-system get configmap jaeger-cluster-plugin-manifest -o jsonpath='{.data.jaeger-image}')
export JAEGER_ES_ROLLOVER_IMAGE=$(kubectl -ncpaas-system get configmap jaeger-cluster-plugin-manifest -o jsonpath='{.data.jaeger-es-rollover-image}')
export JOAUTH2_PROXY_IMAGE=$(kubectl -ncpaas-system get configmap jaeger-cluster-plugin-manifest -o jsonpath='{.data.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 expected duration of a single trace. Controls how far beyond the search window spans are looked up.
export JAEGER_MAX_TRACE_DURATION="1h"
# 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}
-
在 OpenSearch 中创建一个 ISM (Index State Management) policy。Jaeger 使用 ISM 来管理索引 rollover 和保留:
curl -k -u "${OPENSEARCH_USER}:${OPENSEARCH_PASS}" -X PUT \
"${OPENSEARCH_ENDPOINT}/_plugins/_ism/policies/jaeger-ism-policy" \
-H 'Content-Type: application/json' \
--data-binary @- << EOF
{
"policy": {
"description": "Jaeger index rollover and retention",
"default_state": "hot",
"states": [
{
"name": "hot",
"actions": [
{
"rollover": {
"min_primary_shard_size": "50gb",
"min_index_age": "1d"
}
}
],
"transitions": [
{
"state_name": "delete",
"conditions": {
"min_index_age": "7d"
}
}
]
},
{
"name": "delete",
"actions": [
{
"delete": {}
}
],
"transitions": []
}
],
"ism_template": [
{ "index_patterns": ["${JAEGER_ES_INDEX_PREFIX}-jaeger-span-0*"], "priority": 100 },
{ "index_patterns": ["${JAEGER_ES_INDEX_PREFIX}-jaeger-service-0*"], "priority": 100 },
{ "index_patterns": ["${JAEGER_ES_INDEX_PREFIX}-jaeger-dependencies-0*"], "priority": 100 },
{ "index_patterns": ["${JAEGER_ES_INDEX_PREFIX}-jaeger-sampling-0*"], "priority": 100 }
]
}
}
EOF
关键字段:
rollover.min_primary_shard_size,位于 hot 状态:单个 primary shard 的最大大小。当 shard 超过该大小时,会触发 rollover 以创建新索引。默认值:50gb。
rollover.min_index_age,位于 hot 状态:触发 rollover 前索引允许存在的最大时长。默认值:1d(1 天)。
transitions[0].conditions.min_index_age,位于 hot 状态:从索引创建开始计算,到索引转入 delete 状态的时长。默认值:7d(7 天)。
ism_template:将该 policy 绑定到所有名称匹配任一模式的新建索引。OpenSearch 没有 Elasticsearch index.lifecycle.name 模板设置的等价项,因此这是唯一的绑定机制,所以该 policy 必须在下一步创建索引之前就存在。
WARNING
请保留 ism_template 模式中的 -0* 后缀。它只匹配带编号的 rollover 索引,例如 -000001 和 -000002。像 -* 这样更宽泛的模式也会匹配后续创建的日期后缀索引,而 ISM 无法对这些索引执行 rollover。
验证 ISM policy:
curl -k -sS -u "${OPENSEARCH_USER}:${OPENSEARCH_PASS}" \
"${OPENSEARCH_ENDPOINT}/_plugins/_ism/policies/jaeger-ism-policy?pretty"
输出应显示 policy 详情,包括 hot 和 delete 状态。
NOTE
如果对已存在的 policy 执行 PUT,OpenSearch 会返回 version_conflict_engine_exception。有关如何更改运行中部署的保留策略,请参阅 Updating an ISM Policy。
-
使用 jaeger-es-rollover 工具 初始化 索引别名和模板。这将为 OpenSearch 的 Jaeger 数据存储做好准备:
kubectl apply -n ${JAEGER_NS} -f - <<EOF
apiVersion: batch/v1
kind: Job
metadata:
name: jaeger-es-rollover-init
spec:
template:
spec:
containers:
- name: es-rollover-init
image: "${JAEGER_ES_ROLLOVER_IMAGE}"
args:
- init
- "${OPENSEARCH_ENDPOINT}"
env:
- name: INDEX_PREFIX
value: "${JAEGER_ES_INDEX_PREFIX}"
- name: ES_USE_ILM
value: "true"
- name: ES_ILM_POLICY_NAME
value: "jaeger-ism-policy"
- name: ADAPTIVE_SAMPLING
value: "true"
- 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
restartPolicy: Never
backoffLimit: 3
EOF
NOTE
该工具在 OpenSearch 上保留其以 ES_ 为前缀的变量名。ES_USE_ILM=true 选择生命周期管理的 rollover,工具会将其解析为 OpenSearch ISM API,而 ES_ILM_POLICY_NAME 指定其会验证存在性的 ISM policy 名称。ADAPTIVE_SAMPLING=true 还会创建 sampling 别名,而下面的 Jaeger 配置会使用这些别名。
等待 Job 完成,然后验证索引模板和别名是否已创建:
kubectl wait --for=condition=complete job/jaeger-es-rollover-init \
-n ${JAEGER_NS} --timeout=120s
# Verify index templates
curl -k -sS -u "${OPENSEARCH_USER}:${OPENSEARCH_PASS}" \
"${OPENSEARCH_ENDPOINT}/_cat/templates/${JAEGER_ES_INDEX_PREFIX}-jaeger-*?v"
# Verify index aliases
curl -k -sS -u "${OPENSEARCH_USER}:${OPENSEARCH_PASS}" \
"${OPENSEARCH_ENDPOINT}/_cat/aliases/${JAEGER_ES_INDEX_PREFIX}-jaeger-*?v"
预期结果如下:
- Job 状态为
Complete。
- OpenSearch 中存在名为
${JAEGER_ES_INDEX_PREFIX}-jaeger-(span|service|dependencies|sampling) 的索引模板。
${JAEGER_ES_INDEX_PREFIX}-jaeger-*-read 和 ${JAEGER_ES_INDEX_PREFIX}-jaeger-*-write 别名指向初始的 -000001 索引,并且每个 write 别名上的 is_write_index 都为 true。
确认 ISM 已接管新索引:
curl -k -sS -u "${OPENSEARCH_USER}:${OPENSEARCH_PASS}" \
"${OPENSEARCH_ENDPOINT}/_plugins/_ism/explain/${JAEGER_ES_INDEX_PREFIX}-jaeger-span-000001?pretty"
index.plugins.index_state_management.policy_id 字段应显示为 jaeger-ism-policy。
NOTE
ISM 通过后台扫描发现新索引,因此 policy_id 可能在几分钟内仍为 null。如果之后仍然是 null,则说明该 policy 的 ism_template 模式与已创建的索引名称不匹配。请修正 policy,并使用 POST _plugins/_ism/add/<index> 手动附加它。
-
初始化 Job 完成后进行清理:
kubectl delete job jaeger-es-rollover-init -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_trace_duration: "${JAEGER_MAX_TRACE_DURATION}"
create_mappings: false
indices:
index_prefix: "${JAEGER_ES_INDEX_PREFIX}"
spans:
shards: 5
replicas: 1
rotation:
auto_rollover: {}
services:
shards: 5
replicas: 1
rotation:
auto_rollover: {}
dependencies:
shards: 5
replicas: 1
rotation:
auto_rollover: {}
sampling:
shards: 5
replicas: 1
rotation:
auto_rollover: {}
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:
metrics:
level: detailed
readers:
- pull:
exporter:
prometheus:
host: "0.0.0.0"
port: 8888
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 容器的资源 requests 和 limits。请根据预期的 trace 量进行调整;吞吐量更高的环境可能需要更多 CPU 和内存。
- 为 Jaeger 实例启用 Prometheus metrics endpoint。
jaeger_storage extension 配置用于存储 trace 数据的 OpenSearch backend。
opensearch driver 选择 OpenSearch 存储实现。Jaeger 对 OpenSearch 使用与 Elasticsearch 相同的实现。
service_cache_ttl 控制 service name cache 的保留时间。默认值为 12h。如果 ISM rollover-to-delete 间隔较短,请减小该值,以确保 Jaeger UI 能够及时发现 services。
max_trace_duration 是单条 trace 的最大预期持续时间,此处取自 JAEGER_MAX_TRACE_DURATION。query service 会在时间范围过滤条件的两侧按该值扩展,因此即使 span 超出搜索窗口也仍然可以被找到。默认值为 24h;如果你的 traces 生命周期较短,可将其调低。参见 Query Time Range。
- 在使用
auto_rollover 轮转策略时,create_mappings 必须设置为 false,因为索引模板和 mappings 由第 6 步中的 rollover 初始化进行管理。若保持默认值,会悄然移除模板中的 read alias 和 ISM rollover alias。
index_prefix 必须与第 6 步中 jaeger-es-rollover 初始化时使用的 INDEX_PREFIX 一致。有关 shards 和 replicas 调优的更多信息,请参阅 Shards and Replicas。
rotation.auto_rollover 策略使用 read/write aliases,并依赖第 5 步创建的 ISM policy 自动触发索引 rollover 和删除。默认 alias 名称与 rollover 初始化创建的名称一致。由于 read alias 始终会解析为其关联的所有索引,因此在该策略下 max_span_age 不起作用,并且刻意留空;保留策略完全由 ISM policy 控制。
jaeger_query extension 提供 Jaeger Query API 和 Jaeger UI。
additionalContainers 部分定义了 OAuth2 Proxy sidecar,它通过与 Alauda Container Platform Dex identity provider 集成来处理 Jaeger UI 的认证。
- OAuth2 Proxy sidecar 的资源 requests 和 limits。由于该容器只代理认证请求,因此资源需求很低。
-
使用 envsubst 渲染 manifest 并应用配置:
envsubst < jaeger.yaml | kubectl apply -f -
-
等待 Jaeger Pod 就绪:
kubectl rollout status deployment/${JAEGER_INSTANCE_NAME}-collector \
-n ${JAEGER_NS} --timeout=180s
-
为命名空间添加标签并创建 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_grpc/traces:
endpoint: "${JAEGER_INSTANCE_NAME}-collector.${JAEGER_NS}.svc.cluster.local:4317"
tls:
insecure: true
prometheus:
translation_strategy: UnderscoreEscapingWithoutSuffixes # keep OTel metric names without _total suffixes (add_metric_suffixes is deprecated and ignored since collector-contrib v0.154.0)
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_grpc/traces]
metrics:
receivers: [otlp]
processors: [memory_limiter, batch]
exporters: [debug, prometheus]
telemetry:
metrics:
readers:
- pull:
exporter:
prometheus:
host: 0.0.0.0
port: 8888
prometheus: kube-prometheus 标签使 ACP Prometheus 能够通过自动创建的 ServiceMonitor 抓取 Collector metrics。
- Collector 容器的资源 requests 和 limits。请根据预期的 trace 吞吐量进行调整。
- 使 Operator 能够自动为 Collector 的 metrics endpoint 创建
ServiceMonitor 资源。
- OTLP receiver 接受来自已埋点应用的 gRPC(端口
4317)和 HTTP(端口 4318)trace 数据。
otlp_grpc/traces exporter 将接收到的 traces 转发到 Jaeger collector service。endpoint 会根据 Jaeger 实例名称和命名空间推导得出。
- trace pipeline 通过 OTLP 和 Zipkin 接收数据,经由
memory_limiter 和 batch 处理,并同时导出到 debug exporter(用于日志)和 otlp_grpc/traces(用于转发到 Jaeger)。
The OTLP gRPC exporter is named
otlp_grpc
exporter 的类型名称是 otlp_grpc,而不是 otlp。前者名称作为已弃用别名仍然可用,但 Collector 会在启动时针对每个受影响的组件实例输出弃用警告,并且上游计划在未来版本中移除该别名。
-
使用 envsubst 渲染 manifest 并应用配置:
envsubst < otel-collector.yaml | kubectl apply -f -
-
等待 Collector Pod 就绪:
kubectl rollout status deployment/otel-collector \
-n ${JAEGER_NS} --timeout=180s
验证
安装完所有组件后,通过生成示例 trace 数据来验证端到端 tracing 流水线。
-
将 telemetrygen 作为测试客户端部署以生成示例 traces:
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 service。
-
打开 <platform-url>/clusters/<cluster-name>/jaeger 上的 Jaeger UI。
从 Service 下拉列表中选择 telemetrygen service,然后点击 Find Traces,以验证生成的 traces 是否可见。
运行以下命令以打印 Jaeger UI URL:
echo "Jaeger UI: ${PLATFORM_URL}${JAEGER_BASEPATH}"
Service Performance Monitoring(SPM)会在 Jaeger UI 中显示为 Monitor 标签页,并通过聚合 span 数据生成 RED(Request、Error、Duration)指标。这样你无需预先了解 service 或 operation 名称,就能识别性能问题。更多详情请参阅 Service Performance Monitoring (SPM)。
启用 SPM 需要在 Jaeger 内部 运行 SpanMetrics Connector 来生成 RED 指标,并通过 load_balancing exporter 将前端 OpenTelemetry Collector 的 spans 路由到 Jaeger,这样即使两个组件都运行多个副本,指标也能保持准确。Jaeger 会在 Prometheus endpoint 上暴露这些指标,并通过兼容 PromQL 的 backend 将其提供给 Monitor 标签页。
前提条件
- 已部署 Jaeger v2 和 OpenTelemetry Collector(已完成前述所有步骤)。
- 集群中可用 ACP monitoring。
操作步骤
-
从集群中获取 monitoring 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)
-
为 monitoring 凭据创建一个 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,使其通过 load_balancing exporter 将 spans 转发到 Jaeger,替换直接使用的 otlp_grpc/traces exporter。通过设置 routing_key: service,同一 service 的所有 spans 会稳定地发送到同一个 Jaeger replica,因此在 Jaeger 内部运行的 SpanMetrics Connector(下一步)会对每个 service 只聚合一次。这可以确保当 Collector 或 Jaeger 运行多个副本时指标仍然正确:
kubectl patch opentelemetrycollector otel -n ${JAEGER_NS} --type=merge -p "
spec:
config:
exporters:
otlp_grpc/traces: null # remove the direct exporter, replaced by load_balancing
load_balancing:
routing_key: service
protocol:
otlp: # a configuration field of the load_balancing exporter, not a component type name
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, load_balancing]
"
dns resolver 会通过 OpenTelemetry Operator 自动配置的 headless 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 的文件,内容如下。该 patch 会在 Jaeger 内部运行 SpanMetrics Connector,在 Prometheus endpoint 上暴露生成的 RED 指标,并添加一个兼容 PromQL 的 metrics backend,以便 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:
span_metrics: {}
exporters:
prometheus:
translation_strategy: UnderscoreEscapingWithoutSuffixes # keep OTel metric names without _total suffixes (add_metric_suffixes is deprecated and ignored since Jaeger v2.20.0 / collector-contrib v0.154.0)
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, span_metrics]
metrics/spanmetrics:
receivers: [span_metrics]
exporters: [prometheus]
monitoring-credentials volume 会将 monitoring basic-auth 凭据挂载到 Jaeger 容器中。
monitoring-credentials volumeMount 会使凭据可在 /etc/jaeger/monitoring-credentials/ 下访问。
span_metrics connector 会根据 Jaeger 接收到的 spans 生成 RED 指标。由于 Collector 会将每个 service 路由到单个 Jaeger replica,因此每个 replica 都能正确聚合一组互不重叠的 services。
prometheus exporter 会在端口 8889 上暴露生成的指标。Jaeger 实例已经带有 prometheus: kube-prometheus 标签以及 observability.metrics.enableMetrics: true(在 jaeger.yaml 中设置),因此 Operator 会自动创建一个 ServiceMonitor,使 ACP Prometheus 能够抓取该 endpoint。
basicauth/monitoring extension 为 monitoring metrics endpoint 提供 basic authentication。
metric_backends 部分配置了 Jaeger 为 SPM 数据查询的兼容 PromQL 的 metrics storage。
- 在
jaeger_query extension 中引用该 metrics store。
- 必须将
basicauth/monitoring extension 添加到 service.extensions 列表中才能生效。
- 现在
traces pipeline 也会导出到 span_metrics(存储加 metrics 生成),并且一个专用的 metrics/spanmetrics pipeline 会将生成的 metrics 转发到 prometheus exporter。
WARNING
volumes、volumeMounts、service.extensions 以及 pipeline 的 exporters 字段都是数组。merge patch 会整体替换数组,而不是向其中追加内容。上面的 patch 文件包含了所有现有条目以及新增条目,以防止数据丢失。
-
应用该 patch:
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,只需增加 otel 和 ${JAEGER_INSTANCE_NAME} collectors 上的 spec.replicas;无需其他更改。无状态的 Collector 层可以自由扩展,并且由于 spans 会按 service 进行负载均衡,因此每个 Jaeger replica 都会拥有一组互不重叠的 services,并且不会发生冲突。请注意以下事项:
验证
启用 SPM 后,你可以按照上文 Verification 章节中的说明部署 telemetrygen 测试客户端来进行验证。
生成 traces 后,导航到 Jaeger UI 中的 Monitor 标签页,查看 telemetrygen service 的聚合 RED 指标。
卸载
要从集群中移除 Alauda Distributed Tracing 组件,请参阅 Uninstalling Alauda Distributed Tracing。