• Русский
  • Установка Alauda Distributed Tracing с OpenSearch

    Установка платформы Alauda Distributed Tracing включает следующие шаги:

    1. Установка Alauda Build of OpenTelemetry v2 Operator
    2. Развертывание Alauda Build of Jaeger v2
    3. Развертывание OpenTelemetry Collector для пересылки трассировок в Jaeger

    Установка Alauda Build of OpenTelemetry v2 Operator

    Alauda Build of OpenTelemetry v2 Operator управляет жизненным циклом экземпляров Jaeger v2 и OpenTelemetry Collector. Перед развертыванием любых компонентов трассировки необходимо установить этот Operator.

    Установка через веб-консоль

    Следуйте инструкциям в разделе Установка через веб-консоль документации Alauda Build of OpenTelemetry v2.

    Установка через CLI

    Следуйте инструкциям в разделе Установка через CLI документации Alauda Build of OpenTelemetry v2.

    Развертывание Alauda Build of Jaeger v2

    Jaeger v2 разворачивается как пользовательский ресурс OpenTelemetryCollector, управляемый Alauda Build of OpenTelemetry v2 Operator. Он использует бэкенд хранения и интегрируется с системой аутентификации Alauda Container Platform через сайдкар OAuth2 Proxy.

    Предварительные требования

    • Alauda Build of OpenTelemetry v2 Operator установлен.
    • Доступен экземпляр OpenSearch 3.x, и у вас есть URL конечной точки, имя пользователя и пароль для него.
    • Активная сессия ACP CLI (kubectl) у администратора кластера с ролью cluster-admin.
    • Установлена утилита командной строки jq.

    Процедура

    1. Задайте пользовательские переменные среды для подключения к OpenSearch:

      export OPENSEARCH_ENDPOINT='<OpenSearch endpoint URL>'
      export OPENSEARCH_USER='<OpenSearch username>'
      export OPENSEARCH_PASS='<OpenSearch password>'

      Замените значения-заполнители на ваши фактические учетные данные OpenSearch.

    2. Получите из кластера конфигурацию платформы и образы контейнеров, связанные с 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')
      NOTE

      Убедитесь, что команды завершаются без ошибок.

    3. Задайте переменные среды по умолчанию. При необходимости вы можете скорректировать эти значения в соответствии с требованиями вашего развертывания:

      # 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"
    4. Создайте namespace Jaeger и Secret с учетными данными OpenSearch:

      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}
    5. Создайте Secret для OAuth2 Proxy, который используется для интеграции интерфейса Jaeger с аутентификацией 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 -
    6. Создайте файл с именем 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
      1. Метка prometheus: kube-prometheus наследуется автоматически созданным ресурсом ServiceMonitor, что позволяет ACP Prometheus собирать метрики Jaeger.
      2. Образ контейнера Jaeger v2. Это не стандартный образ OpenTelemetry Collector; это пользовательский бинарный файл Jaeger, собранный на базе фреймворка OpenTelemetry Collector.
      3. Запросы и лимиты ресурсов для контейнера Jaeger. Настройте их в зависимости от ожидаемого объема трассировок; для окружений с высокой пропускной способностью может потребоваться больше CPU и памяти.
      4. Включает конечную точку метрик Prometheus для экземпляра Jaeger.
      5. Расширение jaeger_storage настраивает бэкенд OpenSearch для хранения данных трассировок.
      6. Драйвер opensearch выбирает реализацию хранилища OpenSearch. Jaeger использует ту же реализацию для OpenSearch, что и для Elasticsearch.
      7. service_cache_ttl определяет, как долго хранится кэш имен сервисов. Значение по умолчанию — 12h. Если срок хранения индексов небольшой, уменьшите это значение, чтобы интерфейс Jaeger мог оперативно обнаруживать сервисы.
      8. max_span_age — это максимальный возраст span, который будет искать сервис запросов; здесь он задается из JAEGER_MAX_SPAN_AGE. Держите его в соответствии с хранением jaeger-es-index-cleaner, чтобы интерфейс не запрашивал индексы, которые уже были удалены.
      9. index_prefix должен совпадать с INDEX_PREFIX, используемым CronJob jaeger-es-index-cleaner; в противном случае cleaner не сможет найти индексы для удаления. Подробности о настройке shards и replicas см. в разделе Shards and Replicas.
      10. rollover_frequency: day вместе с date_layout создает ежедневные индексы, такие как ${JAEGER_ES_INDEX_PREFIX}-jaeger-span-YYYY-MM-DD. Именно эти обычные ежедневные индексы (без rollover alias) сопоставляет jaeger-es-index-cleaner по суффиксу даты.
      11. Расширение jaeger_query предоставляет Jaeger Query API и интерфейс Jaeger UI.
      12. Раздел additionalContainers определяет сайдкар OAuth2 Proxy, который обрабатывает аутентификацию для интерфейса Jaeger UI, интегрируясь с поставщиком удостоверений Dex в Alauda Container Platform.
      13. Запросы и лимиты ресурсов для сайдкара OAuth2 Proxy. У этого контейнера низкие требования к ресурсам, поскольку он только проксирует запросы аутентификации.
    7. Отрендерите манифест с помощью envsubst и примените конфигурацию:

      envsubst < jaeger.yaml | kubectl apply -f -
    8. Дождитесь, пока Pod Jaeger будет готов:

      kubectl rollout status deployment/${JAEGER_INSTANCE_NAME}-collector \
        -n ${JAEGER_NS} --timeout=180s
    9. Разверните jaeger-es-index-cleaner, чтобы периодически удалять истекшие индексы.

      Почему не

      jaeger-es-rollover init? Подкоманда init утилиты jaeger-es-rollover обращается к конечной точке Elasticsearch _ilm/policy/..., чтобы проверить наличие ILM policy, но OpenSearch использует вместо этого _plugins/_ism/policies/.... Эти два механизма несовместимы, поэтому init завершается с ошибкой в OpenSearch (см. jaegertracing/jaeger#7121).

      В этом руководстве используются ежедневные индексы плюс jaeger-es-index-cleaner, который не зависит от rollover alias и, следовательно, не требует jaeger-es-rollover init.

      Как это работает

      Бэкенд OpenSearch записывает ежедневные индексы, такие как acp-<cluster>-jaeger-span-2026-04-22. jaeger-es-index-cleaner сопоставляет индексы с именами <prefix>-jaeger-(span|service|dependencies|sampling)-YYYY-MM-DD, сравнивает суффикс даты с выражением «сегодня минус N дней» и удаляет индексы, срок хранения которых истек.

      Задайте переменные среды для 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

      Связь между параметром хранения и Jaeger

      Чтобы интерфейс Jaeger UI не запрашивал индексы, которые cleaner только что удалил, держите JAEGER_INDEX_RETENTION_DAYS (срок хранения для cleaner) согласованным с max_span_age Jaeger (JAEGER_MAX_SPAN_AGE). Например, установите для обоих значение 7 дней (168h).

    10. Создайте jaeger-index-cleaner.yaml, чтобы развернуть index-cleaner как CronJob:

      jaeger-index-cleaner.yaml
      apiVersion: batch/v1
      kind: CronJob
      metadata:
        name: jaeger-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
      1. schedule использует стандартное Cron-выражение (UTC). Планируйте его на периоды низкой нагрузки; обычно достаточно запуска один раз в день.
      2. concurrencyPolicy: Forbid гарантирует, что новый Job не будет запущен, пока предыдущая очистка еще выполняется, что предотвращает одновременные удаления, которые могут кратковременно повысить нагрузку на OpenSearch.
      3. args — это позиционные аргументы jaeger-es-index-cleaner: первый — это срок хранения в днях, второй — конечная точка OpenSearch. ROLLOVER=true намеренно не задан, поэтому используется режим сопоставления ежедневных индексов по умолчанию.
      4. INDEX_PREFIX должен точно совпадать с indices.index_prefix Jaeger (здесь acp-<cluster>), иначе cleaner не сможет найти соответствующие индексы.
      5. ES_TLS_SKIP_HOST_VERIFY=true соответствует TLS-политике insecure_skip_verify: true на стороне Jaeger. Если вместо этого вы усиливаете TLS с помощью самоподписанного CA, подключите CA в контейнер и укажите ES_TLS_CA_FILE с путем к нему.

      Отрендерите и разверните CronJob:

      envsubst < jaeger-index-cleaner.yaml | kubectl apply -f -
    11. Пометьте namespace и создайте 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

    Проверка

    Откройте интерфейс Jaeger UI по адресу <platform-url>/clusters/<cluster-name>/jaeger, где <platform-url> — это URL Alauda Container Platform, а <cluster-name> — имя вашего кластера.

    Выполните следующую команду, чтобы вывести URL интерфейса Jaeger UI:

    echo "Jaeger UI: ${PLATFORM_URL}${JAEGER_BASEPATH}"

    Развертывание OpenTelemetry Collector

    После запуска Jaeger v2 разверните экземпляр OpenTelemetry Collector, чтобы принимать данные трассировок от приложений с инструментированием и пересылать их в 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/traces:
              endpoint: "${JAEGER_INSTANCE_NAME}-collector.${JAEGER_NS}.svc.cluster.local:4317"
              tls:
                insecure: true
            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 # 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
      1. Метка prometheus: kube-prometheus позволяет ACP Prometheus собирать метрики Collector через автоматически созданный ресурс ServiceMonitor.
      2. Запросы и лимиты ресурсов для контейнера Collector. Настройте их в зависимости от ожидаемой пропускной способности трассировок.
      3. Позволяет Operator автоматически создавать ресурсы ServiceMonitor для конечной точки метрик Collector.
      4. Получатель OTLP принимает данные трассировок по gRPC (порт 4317) и HTTP (порт 4318) от приложений с инструментированием.
      5. Экспортёр otlp/traces пересылает полученные трассировки в сервис Jaeger collector. Конечная точка выводится из имени и namespace экземпляра Jaeger.
      6. Конвейер трассировок принимает данные через OTLP и Zipkin, обрабатывает их через memory_limiter и batch, а затем экспортирует как в debug exporter (для логирования), так и в otlp/traces (для пересылки в Jaeger).
    2. Отрендерите манифест с помощью envsubst и примените конфигурацию:

      envsubst < otel-collector.yaml | kubectl apply -f -
    3. Дождитесь, пока pod Collector будет готов:

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

    Проверка

    После установки всех компонентов проверьте конвейер сквозной трассировки, сгенерировав тестовые данные трассировок.

    1. Разверните telemetrygen как тестовый клиент для генерации примеров трассировок:

      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, развернутый на предыдущем шаге.

    2. Откройте интерфейс Jaeger UI по адресу <platform-url>/clusters/<cluster-name>/jaeger.

      Выберите сервис telemetrygen в раскрывающемся списке Service и нажмите Find Traces, чтобы убедиться, что сгенерированные трассировки отображаются.

      Выполните следующую команду, чтобы вывести URL интерфейса Jaeger UI:

      echo "Jaeger UI: ${PLATFORM_URL}${JAEGER_BASEPATH}"

    (Необязательно) Включение Service Performance Monitoring (SPM)

    Service Performance Monitoring (SPM) отображается в интерфейсе Jaeger UI как вкладка Monitor и агрегирует данные span, чтобы формировать метрики RED (Request, Error, Duration). Это позволяет выявлять проблемы производительности без предварительного знания имен сервисов или операций. Подробнее см. в разделе Service Performance Monitoring (SPM).

    Для включения SPM требуются два изменения: добавление SpanMetrics Connector в OpenTelemetry Collector и настройка совместимого с PromQL бэкенда метрик в Jaeger.

    Предварительные требования

    • Jaeger v2 и OpenTelemetry Collector развернуты (все предыдущие шаги выполнены).
    • ACP monitoring доступен в кластере.

    Процедура

    1. Получите из кластера конечную точку мониторинга и учетные данные:

      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. Создайте 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, чтобы включить SpanMetrics Connector. Это добавит spanmetrics connector, который генерирует метрики RED из span и экспортирует их через Prometheus exporter:

      kubectl patch opentelemetrycollector otel -n ${JAEGER_NS} --type=merge -p '
      spec:
        config:
          connectors:
            spanmetrics: {}
          service:
            pipelines:
              traces:
                exporters: [debug, otlp/traces, spanmetrics]
              metrics/spanmetrics:
                receivers: [spanmetrics]
                exporters: [prometheus]
      '

      Дождитесь перезапуска Collector:

      kubectl rollout status deployment/otel-collector \
        -n ${JAEGER_NS} --timeout=180s
    4. Создайте файл с именем jaeger-spm-patch.yaml со следующим содержимым. Этот патч добавляет в Jaeger бэкенд метрик PromQL и включает вкладку 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:
          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] 
      1. Том monitoring-credentials монтирует в контейнер Jaeger учетные данные basic-auth для мониторинга.
      2. volumeMount monitoring-credentials делает учетные данные доступными по пути /etc/jaeger/monitoring-credentials/.
      3. Расширение basicauth/monitoring предоставляет базовую аутентификацию для конечной точки метрик мониторинга.
      4. Раздел metric_backends настраивает хранилище метрик, совместимое с PromQL, которое Jaeger запрашивает для данных SPM.
      5. Ссылайтесь на хранилище метрик в расширении jaeger_query.
      6. Чтобы расширение basicauth/monitoring стало активным, его необходимо добавить в список service.extensions.
      WARNING

      Поля volumes, volumeMounts и service.extensions являются массивами. Merge 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 вы можете проверить его, развернув тестовый клиент telemetrygen, как описано в разделе Проверка выше.

    После генерации трассировок перейдите на вкладку Monitor в интерфейсе Jaeger UI, чтобы просмотреть агрегированные метрики RED для сервиса telemetrygen.

    Удаление

    Чтобы удалить компоненты Alauda Distributed Tracing из кластера, следуйте инструкции Удаление Alauda Distributed Tracing.