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

    Установка платформы 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. В качестве хранилища используется Elasticsearch, а интеграция с системой аутентификации Alauda Container Platform выполняется через сайдкар OAuth2 Proxy.

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

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

    Порядок выполнения

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

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

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

    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_ROLLOVER_IMAGE=$(echo "$JAEGER_RELATED_IMAGES" | jq -r '.[] | select(.name=="component.jaeger-es-rollover") | .image')
      export JOAUTH2_PROXY_IMAGE=$(echo "$JAEGER_RELATED_IMAGES" | jq -r '.[] | select(.name=="component.oauth2-proxy") | .image')
      NOTE

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

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

      # Namespace для экземпляра Jaeger
      export JAEGER_NS="jaeger-system"
      # Имя экземпляра Jaeger
      export JAEGER_INSTANCE_NAME="jaeger"
      # Префикс индекса Elasticsearch для данных Jaeger
      export JAEGER_ES_INDEX_PREFIX="acp-${CLUSTER_NAME}"
      # Базовый путь для UI Jaeger
      export JAEGER_BASEPATH="/clusters/${CLUSTER_NAME}/jaeger"
    4. Создайте namespace Jaeger и Secret с учетными данными Elasticsearch:

      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}

      Убедитесь, что Secret создан:

      kubectl get secret es-credentials -n ${JAEGER_NS}
    5. Создайте в Elasticsearch политику ILM (Index Lifecycle Management). 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:

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

      В выводе должны отображаться сведения о политике ILM, включая фазы hot и delete.

    6. Инициализируйте aliases и templates индексов с помощью инструмента 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: 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, затем убедитесь, что templates и aliases индексов созданы:

      kubectl wait --for=condition=complete job/jaeger-es-rollover-init \
        -n ${JAEGER_NS} --timeout=120s
      
      # Проверка templates индексов
      curl -k -sS -u "${ES_USER}:${ES_PASS}" "${ES_ENDPOINT}/_index_template?pretty" \
        | grep ${JAEGER_ES_INDEX_PREFIX}-jaeger-
      
      # Проверка aliases индексов
      curl -k -sS -u "${ES_USER}:${ES_PASS}" "${ES_ENDPOINT}/_alias?pretty" \
        | grep ${JAEGER_ES_INDEX_PREFIX}-jaeger-

      Ожидаемые результаты:

      • Статус Job — Complete.
      • В Elasticsearch существуют templates индексов, соответствующие ${JAEGER_ES_INDEX_PREFIX}-jaeger-*.
      • В Elasticsearch существуют aliases индексов ${JAEGER_ES_INDEX_PREFIX}-jaeger-*-read и ${JAEGER_ES_INDEX_PREFIX}-jaeger-*-write.
    7. Очистите Job инициализации после его завершения:

      kubectl delete job jaeger-es-rollover-init -n ${JAEGER_NS}
    8. Создайте Secret для OAuth2 Proxy, который используется для интеграции UI 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}
    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
                    use_aliases: true
                    use_ilm: true
                    service_cache_ttl: 12h
                    create_mappings: false
                    indices:
                      index_prefix: "${JAEGER_ES_INDEX_PREFIX}"
                      spans:
                        shards: 5
                        replicas: 1
                      services:
                        shards: 5
                        replicas: 1
                      dependencies:
                        shards: 5
                        replicas: 1
                      sampling:
                        shards: 5
                        replicas: 1
      
            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:
              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; это пользовательский binary Jaeger, собранный на фреймворке OpenTelemetry Collector.
      3. Включает endpoint метрик Prometheus для экземпляра Jaeger.
      4. Запросы и лимиты ресурсов для контейнера Jaeger. Настройте их в зависимости от ожидаемого объема трассировок; для сред с более высокой пропускной способностью могут потребоваться больше CPU и памяти.
      5. Расширение jaeger_storage настраивает backend Elasticsearch для хранения данных трассировки.
      6. service_cache_ttl определяет, как долго хранится кэш имен сервисов. Значение по умолчанию — 12h. Если интервал ILM от hot до delete короткий, уменьшите это значение, чтобы UI Jaeger мог своевременно обнаруживать сервисы.
      7. При использовании режима ILM параметр create_mappings должен быть установлен в false, поскольку mappings индекса управляются инициализацией rollover.
      8. index_prefix должен совпадать с префиксом, использованным при инициализации jaeger-es-rollover на шаге 6. Подробнее о настройке shards и replicas см. в разделе Shards and Replicas.
      9. Расширение jaeger_query обслуживает Jaeger Query API и UI Jaeger.
      10. Раздел additionalContainers определяет сайдкар OAuth2 Proxy, который обрабатывает аутентификацию для UI Jaeger путем интеграции с провайдером идентификации Dex в Alauda Container Platform.
      11. Запросы и лимиты ресурсов для сайдкара OAuth2 Proxy. У этого контейнера низкие требования к ресурсам, поскольку он только проксирует запросы аутентификации.
    10. Сгенерируйте манифест с помощью envsubst и примените конфигурацию:

      envsubst < jaeger.yaml | kubectl apply -f -
    11. Дождитесь готовности Pod Jaeger:

      kubectl rollout status deployment/${JAEGER_INSTANCE_NAME}-collector \
        -n ${JAEGER_NS} --timeout=180s
    12. Добавьте метку namespace и создайте Ingress для публикации UI Jaeger:

      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

    Проверка

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

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

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

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

    После запуска Jaeger v2 разверните экземпляр OpenTelemetry Collector, чтобы принимать данные трассировки от инструментированных приложений и пересылать их в Jaeger.

    1. Создайте ресурс OpenTelemetryCollector:

      kubectl apply -f - <<EOF
      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
      EOF
      1. Метка prometheus: kube-prometheus позволяет ACP Prometheus собирать метрики Collector через автоматически создаваемый ServiceMonitor.
      2. Запросы и лимиты ресурсов для контейнера Collector. Настройте их в зависимости от ожидаемой пропускной способности трассировки.
      3. Позволяет Operator автоматически создавать ресурсы ServiceMonitor для endpoint метрик Collector.
      4. Receiver OTLP принимает данные трассировки от инструментированных приложений по gRPC (порт 4317) и HTTP (порт 4318).
      5. Экспортёр otlp/traces пересылает полученные трассировки в сервис Jaeger collector. Endpoint формируется на основе имени и namespace экземпляра Jaeger.
      6. Конвейер трассировки принимает данные через OTLP и Zipkin, обрабатывает их через memory_limiter и batch, а затем экспортирует в debug exporter (для логирования) и otlp/traces (для пересылки в Jaeger).
    2. Дождитесь готовности pod Collector:

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

    Проверка

    После установки всех компонентов проверьте end-to-end pipeline трассировки, сгенерировав тестовые данные трассировки.

    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. Откройте UI Jaeger по адресу <platform-url>/clusters/<cluster-name>/jaeger.

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

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

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

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

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

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

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

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

    Порядок выполнения

    1. Получите из кластера 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. Создайте Secret для учетных данных мониторинга:

      kubectl create secret generic monitoring-credentials \
        --namespace=${JAEGER_NS} \
        --from-literal=username=${MONITORING_USERNAME} \
        --from-literal=password=${MONITORING_PASSWORD}
    3. Внесите patch в OpenTelemetry Collector, чтобы включить SpanMetrics Connector. Это добавит connector spanmetrics, который генерирует метрики 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 со следующим содержимым. Этот patch добавляет в Jaeger backend метрик, совместимый с PromQL, и включает вкладку 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:
          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 монтирует учетные данные basic-auth мониторинга в контейнер Jaeger.
      2. volumeMount monitoring-credentials делает учетные данные доступными по пути /etc/jaeger/monitoring-credentials/.
      3. Расширение basicauth/monitoring предоставляет basic authentication для endpoint метрик мониторинга.
      4. Раздел metric_backends настраивает хранилище метрик, совместимое с PromQL, которое Jaeger запрашивает для данных SPM.
      5. Укажите хранилище метрик в расширении jaeger_query.
      6. Чтобы расширение basicauth/monitoring стало активным, его необходимо добавить в список service.extensions.
      WARNING

      Поля volumes, volumeMounts и service.extensions являются массивами. Merge patch полностью заменяет массивы, а не дополняет их. Приведенный выше файл patch включает все существующие записи вместе с новыми, чтобы предотвратить потерю данных.

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

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