使用 Elasticsearch 安装 Alauda Distributed Tracing

安装 Alauda Distributed Tracing 平台涉及以下步骤:

  1. 安装 Alauda Build of Jaeger v2 集群插件
  2. 安装 Alauda Build of OpenTelemetry v2 Operator
  3. 部署 Alauda Build of Jaeger v2
  4. 部署 OpenTelemetry Collector 以将 traces 转发到 Jaeger

安装 Alauda Build of Jaeger v2 集群插件

Alauda Build of Jaeger v2 集群插件提供 tracing 组件所需的容器镜像:Jaeger(jaegerjaeger-es-rolloverjaeger-es-index-cleaner)和 OAuth2 Proxy。安装该插件会将这些镜像同步到平台内置 registry,并在目标集群的 cpaas-system 命名空间中创建一个名为 jaeger-cluster-plugin-manifest 的 ConfigMap。后续步骤会从该 ConfigMap 中读取镜像地址。

通过 web 控制台安装

  1. 在平台管理视图中,导航到 Administrator > Marketplace > Cluster Plugins
  2. 选择将部署 tracing 组件的集群。
  3. 找到 Alauda Build of Jaeger v2 并单击 Install。该插件不需要安装参数。
NOTE

如果列表中未显示该插件,请从 Customer Portal 下载插件包,并使用 violet 工具将其发布到平台,或者联系技术支持。

通过 CLI 安装

无论插件目标集群是哪一个,集群插件都通过在 global 集群 中创建 ModuleInfo 资源来安装。

  1. global 集群中运行以下命令,检查已发布的插件版本:

    kubectl get moduleconfigs -l cpaas.io/module-name=jaeger-cluster-plugin \
      -o custom-columns=NAME:.metadata.name,VERSION:.spec.version
  2. 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
  3. global 集群中验证安装:

    kubectl get moduleinfo -l cpaas.io/module-name=jaeger-cluster-plugin

    STATUS 列显示 Running 时,表示插件已成功安装。

  4. 验证 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 实例的生命周期。在部署任何 tracing 组件之前,必须先安装此 Operator。

通过 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。
  • 可用的 Elasticsearch 8.x 实例,且你已拥有其 endpoint URL、username 和 password。
  • 由具有 cluster-admin 角色的 cluster administrator 建立的有效 ACP CLI (kubectl) 会话。

操作步骤

  1. 设置用于连接 Elasticsearch 的可配置环境变量:

    export ES_ENDPOINT='<Elasticsearch endpoint URL>'
    export ES_USER='<Elasticsearch username>'
    export ES_PASS='<Elasticsearch password>'

    将占位符值替换为你的实际 Elasticsearch 凭据。

  2. 从集群中检索平台配置,以及从 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}')
    NOTE

    请确认命令执行完成且无错误。

  3. 设置默认环境变量。你可以根据部署需求调整这些值:

    # Namespace for the Jaeger instance
    export JAEGER_NS="jaeger-system"
    # Name of the Jaeger instance
    export JAEGER_INSTANCE_NAME="jaeger"
    # Elasticsearch 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"
  4. 创建 Jaeger 命名空间和 Elasticsearch 凭据 Secret:

    kubectl get namespace ${JAEGER_NS} &> /dev/null || kubectl create namespace ${JAEGER_NS}
    
    kubectl create secret generic es-credentials \
      --namespace=${JAEGER_NS} \
      --from-literal=ES_USER=${ES_USER} \
      --from-literal=ES_PASS=${ES_PASS} \
      --dry-run=client -o yaml | kubectl apply -f -

    验证 Secret 是否已创建:

    kubectl get secret es-credentials -n ${JAEGER_NS}
  5. 在 Elasticsearch 中创建 ILM (Index Lifecycle Management) Policy。Jaeger 使用 ILM 来管理索引 rollover 和保留策略:

    curl -k -u "${ES_USER}:${ES_PASS}" -X PUT \
      "${ES_ENDPOINT}/_ilm/policy/jaeger-ilm-policy" \
      -H 'Content-Type: application/json' \
      --data-binary @- << 'EOF'
    {
      "policy": {
        "phases": {
          "hot": {
            "min_age": "0ms",
            "actions": {
              "rollover": {
                "max_primary_shard_size": "50gb",
                "max_age": "1d"
              },
              "set_priority": {
                "priority": 100
              }
            }
          },
          "delete": {
            "min_age": "7d",
            "actions": {
              "delete": {}
            }
          }
        }
      }
    }
    EOF

    关键字段:

    • policy.phases.hot.actions.rollover.max_primary_shard_size:单个 primary shard 的最大大小。当 shard 超过此大小时,将触发 rollover 以创建新索引。默认值:50gb
    • policy.phases.hot.actions.rollover.max_age:触发 rollover 前索引的最大存活时间。默认值:1d(1 天)。
    • policy.phases.delete.min_age:在 rollover 后删除旧索引之前的等待时间。默认值:7d(7 天)。

    验证 ILM Policy:

    curl -k -u "${ES_USER}:${ES_PASS}" "${ES_ENDPOINT}/_ilm/policy/jaeger-ilm-policy?pretty"

    输出应显示 ILM Policy 详细信息,包括 hotdelete 阶段。

  6. 使用 jaeger-es-rollover 工具初始化索引别名和模板。这将为 Elasticsearch 准备 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
              - "${ES_ENDPOINT}"
            env:
            - name: INDEX_PREFIX
              value: "${JAEGER_ES_INDEX_PREFIX}"
            - name: ES_USE_ILM
              value: "true"
            - 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: es-credentials
                  key: ES_USER
            - name: ES_PASSWORD
              valueFrom:
                secretKeyRef:
                  name: es-credentials
                  key: ES_PASS
          restartPolicy: Never
      backoffLimit: 3
    EOF

    等待 Job 完成,然后验证是否已创建索引模板和别名:

    kubectl wait --for=condition=complete job/jaeger-es-rollover-init \
      -n ${JAEGER_NS} --timeout=120s
    
    # Verify index templates
    curl -k -sS -u "${ES_USER}:${ES_PASS}" "${ES_ENDPOINT}/_index_template?pretty" \
      | grep ${JAEGER_ES_INDEX_PREFIX}-jaeger-
    
    # Verify index aliases
    curl -k -sS -u "${ES_USER}:${ES_PASS}" "${ES_ENDPOINT}/_alias?pretty" \
      | grep ${JAEGER_ES_INDEX_PREFIX}-jaeger-

    预期结果如下:

    • Job 状态为 Complete
    • Elasticsearch 中存在匹配 ${JAEGER_ES_INDEX_PREFIX}-jaeger-* 的索引模板。
    • Elasticsearch 中存在 ${JAEGER_ES_INDEX_PREFIX}-jaeger-*-read${JAEGER_ES_INDEX_PREFIX}-jaeger-*-write 的索引别名。
  7. Job 完成后清理初始化 Job:

    kubectl delete job jaeger-es-rollover-init -n ${JAEGER_NS}
  8. 为 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 -
  9. 创建名为 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: es-credentials
          secret:
            secretName: es-credentials
            items:
              - key: ES_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: es-credentials
          mountPath: /etc/jaeger/es-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: es_storage
    
        extensions:
          healthcheckv2:
            use_v2: true
            http:
              endpoint: "0.0.0.0:13133"
    
          jaeger_storage:
            backends:
              es_storage:
                elasticsearch:
                  server_urls:
                    - "${ES_ENDPOINT}"
                  auth:
                    basic:
                      username: "${ES_USER}"
                      password_file: /etc/jaeger/es-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: es_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
    1. prometheus: kube-prometheus 标签会被自动创建的 ServiceMonitor 资源继承,使 ACP Prometheus 能够抓取 Jaeger 指标。
    2. Jaeger v2 容器镜像。这不是默认的 OpenTelemetry Collector 镜像;它是基于 OpenTelemetry Collector framework 构建的自定义 Jaeger binary。
    3. 为 Jaeger 实例启用 Prometheus metrics endpoint。
    4. Jaeger 容器的资源 requests 和 limits。请根据预期的 trace 量进行调整;更高吞吐量的环境可能需要更多 CPU 和 memory。
    5. jaeger_storage extension 配置用于存储 trace 数据的 Elasticsearch backend
    6. service_cache_ttl 控制 service name cache 的保留时长。默认值为 12h。如果 ILM hot-to-delete 间隔较短,请减小此值,以确保 Jaeger UI 能及时发现 services。
    7. max_trace_duration 是单条 trace 的最大预期持续时间,此处从 JAEGER_MAX_TRACE_DURATION 设置。query service 会在搜索范围两侧按该值扩展时间范围过滤器,以便仍能找到延伸到搜索窗口之外的 spans。默认值为 24h;如果 traces 生命周期较短,可降低该值。请参见 Query Time Range
    8. 使用 auto_rollover rotation strategy 时,create_mappings 必须设置为 false,因为索引模板和 mappings 由 rollover 初始化过程管理。
    9. index_prefix 必须与第 6 步中 jaeger-es-rollover 初始化时使用的前缀一致。有关 shard 和 replica 调优的更多详细信息,请参见 Shards and Replicas
    10. rotation.auto_rollover strategy 使用读/写别名,并依赖第 5 步创建的 ILM policy 自动触发索引 rollover。默认别名名称与第 6 步 jaeger-es-rollover 初始化创建的别名一致。它取代了已弃用的 use_aliases/use_ilm 标志,这些标志自 Jaeger v2.20.0 起已不再接受。由于读别名始终会解析为其关联的每个索引,因此在此 strategy 下 max_span_age 不起作用,并被有意留空;保留策略完全由 ILM policy 管理。
    11. jaeger_query extension 提供 Jaeger Query API 和 Jaeger UI。
    12. additionalContainers 部分定义了 OAuth2 Proxy sidecar,它通过与 Alauda Container Platform Dex identity provider 集成来处理 Jaeger UI 的身份验证。
    13. OAuth2 Proxy sidecar 的资源 requests 和 limits。由于该容器仅负责代理认证请求,因此资源需求较低。
  10. 使用 envsubst 渲染 manifest 并应用配置:

    envsubst < jaeger.yaml | kubectl apply -f -
  11. 等待 Jaeger Pod 就绪:

    kubectl rollout status deployment/${JAEGER_INSTANCE_NAME}-collector \
      -n ${JAEGER_NS} --timeout=180s
  12. 为命名空间添加标签并创建 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。

  1. 创建名为 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
    1. prometheus: kube-prometheus 标签使 ACP Prometheus 能够通过自动创建的 ServiceMonitor 抓取 Collector 指标。
    2. Collector 容器的资源 requests 和 limits。请根据预期的 trace 吞吐量进行调整。
    3. 使 Operator 能够自动为 Collector 的 metrics endpoint 创建 ServiceMonitor 资源。
    4. OTLP receiver 接受来自已埋点应用的 gRPC(端口 4317)和 HTTP(端口 4318)trace 数据。
    5. otlp_grpc/traces exporter 将接收到的 traces 转发到 Jaeger collector service。endpoint 由 Jaeger 实例名称和命名空间派生。
    6. trace pipeline 通过 OTLP 和 Zipkin 接收数据,经 memory_limiterbatch 处理后,同时输出到 debug exporter(用于日志)和 otlp_grpc/traces(用于转发到 Jaeger)。
    OTLP gRPC exporter 名称为

    otlp_grpc exporter 类型名称是 otlp_grpc,而不是 otlp。前者名称作为已弃用的别名仍可使用,但此时 Collector 会在启动时为每个受影响的组件实例记录一条弃用警告,并且上游计划在未来版本中移除该别名。

  2. 使用 envsubst 渲染 manifest 并应用配置:

    envsubst < otel-collector.yaml | kubectl apply -f -
  3. 等待 Collector pod 就绪:

    kubectl rollout status deployment/otel-collector \
      -n ${JAEGER_NS} --timeout=180s

验证

安装所有组件后,通过生成示例 trace 数据来验证端到端 tracing pipeline。

  1. 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。

  2. 打开 <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)

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 将 spans 从前端 OpenTelemetry Collector 路由到 Jaeger,这样即使两个组件都以多副本运行,指标也能保持准确。Jaeger 会在 Prometheus endpoint 上公开这些指标,并通过一个兼容 PromQL 的 backend 将其返回给 Monitor 选项卡。

前提条件

  • 已部署 Jaeger v2 和 OpenTelemetry Collector(已完成前述所有步骤)。
  • 集群中可用 ACP monitoring。

操作步骤

  1. 从集群中检索 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)
  2. 为 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 -
  3. 为 OpenTelemetry Collector 打补丁,使其通过 load_balancing exporter 将 spans 转发到 Jaeger,从而替换直接使用的 otlp_grpc/traces exporter。通过 routing_key: service,同一 service 的所有 spans 会稳定地发送到同一个 Jaeger 副本,因此在 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 自动提供的无头 Service(${JAEGER_INSTANCE_NAME}-collector-headless)发现每个 Jaeger collector Pod,因此无需额外的 Service 或 RBAC。

    等待 Collector 重启:

    kubectl rollout status deployment/otel-collector \
      -n ${JAEGER_NS} --timeout=180s
  4. 创建名为 jaeger-spm-patch.yaml 的文件,并包含以下内容。此补丁会在 Jaeger 内部运行 SpanMetrics Connector,在 Prometheus endpoint 上公开生成的 RED 指标,并添加一个兼容 PromQL 的 metrics backend,以便 Jaeger 可以将这些指标提供给 Monitor 选项卡:

    jaeger-spm-patch.yaml
    spec:
      volumes:
        - name: es-credentials
          secret:
            secretName: es-credentials
            items:
              - key: ES_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: es-credentials
          mountPath: /etc/jaeger/es-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]
    1. monitoring-credentials volume 会将 monitoring basic-auth 凭据挂载到 Jaeger 容器中。
    2. monitoring-credentials volumeMount 会使凭据在 /etc/jaeger/monitoring-credentials/ 下可用。
    3. span_metrics connector 会从 Jaeger 接收到的 spans 生成 RED 指标。由于 Collector 会将每个 service 路由到单个 Jaeger 副本,因此每个副本都能正确聚合一组互不重叠的 services。
    4. prometheus exporter 会在端口 8889 上公开生成的指标。Jaeger 实例已经带有 prometheus: kube-prometheus 标签以及 observability.metrics.enableMetrics: true(在 jaeger.yaml 中设置),因此 Operator 会自动创建一个 ServiceMonitor,使 ACP Prometheus 能够抓取该 endpoint。
    5. basicauth/monitoring extension 为 monitoring metrics endpoint 提供 basic authentication。
    6. metric_backends 部分配置 Jaeger 用于查询 SPM 数据的兼容 PromQL 的 metrics storage。
    7. jaeger_query extension 中引用 metrics store。
    8. basicauth/monitoring extension 必须添加到 service.extensions 列表中才会生效。
    9. traces pipeline 现在还会输出到 span_metrics(storage plus metrics generation),并且专用的 metrics/spanmetrics pipeline 会将生成的指标转发到 prometheus exporter。
    WARNING

    volumesvolumeMountsservice.extensions 和 pipeline exporters 字段都是数组。merge patch 会整体替换数组,而不是追加到数组中。上面的 patch 文件包含了所有现有条目以及新增条目,以防止数据丢失。

  5. 应用补丁:

    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 副本都拥有一组互不重叠的 services,并且不会发生冲突地进行聚合。

验证

启用 SPM 后,你可以按照上文 验证 部分所述,部署 telemetrygen 测试客户端进行验证。

生成 traces 后,导航到 Jaeger UI 中的 Monitor 选项卡,查看 telemetrygen service 的聚合 RED 指标。

卸载

如需从集群中移除 Alauda Distributed Tracing 组件,请参阅 卸载 Alauda Distributed Tracing