使用 Elasticsearch 升级 Alauda Distributed Tracing

将基于 Elasticsearch 的部署从 v2.0(Jaeger 2.16.0、Alauda Build of OpenTelemetry v2 Operator 0.147.0)升级到 v2.1(Jaeger 2.20.0、Operator 0.157.0)涉及以下步骤:

  1. 安装 Alauda Build of Jaeger v2 集群插件
  2. 升级 Alauda Build of OpenTelemetry v2 Operator
  3. 更新 OpenTelemetry Collector
  4. 更新 Elasticsearch 索引模板
  5. 更新 Alauda Build of Jaeger v2
WARNING

Jaeger v2.20.0 会拒绝旧版 Elasticsearch 轮转标志 use_aliasesuse_ilm。请将镜像和 Jaeger 实例的配置在同一个 patch 中更新(步骤 5),否则新的 Pod 会在启动时因 invalid configuration: ... deprecated ES rotation flags ... are no longer supported 而退出。由于新 Pod 永远不会变为就绪状态,之前的 Pod 会继续提供 trace 服务,因此卡住的 rollout 不会中断 tracing。

此操作步骤会保留所有 trace 数据。不会重新创建任何 index、alias 或 ILM policy,现有索引仍然可读。

前提条件

  • 已按照 Installing Alauda Distributed Tracing with Elasticsearch 中的说明安装 Alauda Distributed Tracing v2.0 部署。
  • Alauda Build of Jaeger v2 集群插件以及 Alauda Build of OpenTelemetry v2 Operator 0.157.0 已发布到平台。
  • 集群管理员使用 cluster-admin 角色在目标集群和 global 集群中均建立了有效的 ACP CLI(kubectl)会话。
  • 请查看 Upgrade Notes,了解此版本引入的行为变更。

设置环境变量

在目标集群上运行以下命令。Elasticsearch endpoint 和 index 前缀会从正在运行的 Jaeger 实例中读取,以确保始终与现有部署一致:

# Namespace where the tracing components are deployed
export JAEGER_NS="jaeger-system"
# Name of the OpenTelemetryCollector resource that runs Jaeger
export JAEGER_INSTANCE_NAME="jaeger"

export ES_ENDPOINT=$(kubectl -n${JAEGER_NS} get opentelemetrycollector ${JAEGER_INSTANCE_NAME} \
  -o jsonpath='{.spec.config.extensions.jaeger_storage.backends.es_storage.elasticsearch.server_urls[0]}')
export JAEGER_ES_INDEX_PREFIX=$(kubectl -n${JAEGER_NS} get opentelemetrycollector ${JAEGER_INSTANCE_NAME} \
  -o jsonpath='{.spec.config.extensions.jaeger_storage.backends.es_storage.elasticsearch.indices.index_prefix}')

# Maximum expected duration of a single trace. Controls how far beyond the search
# window spans are looked up. The Jaeger default changed from 1h to 24h in v2.20.0.
export JAEGER_MAX_TRACE_DURATION="1h"

安装 Alauda Build of Jaeger v2 集群插件

从 v2.1 开始,tracing 组件的容器镜像由 Alauda Build of Jaeger v2 集群插件提供,而不是由 Operator bundle 提供。安装插件会将镜像同步到平台内置 registry,并在目标集群的 cpaas-system namespace 中创建 jaeger-cluster-plugin-manifest ConfigMap。后续步骤会从该 ConfigMap 读取镜像地址。

通过 Web 控制台安装

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

通过 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 集群中验证安装。STATUS 列显示 Running 时,表示插件已成功安装:

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

    平台会为该资源分配一个生成的名称,因此请通过 label 查询 ModuleInfo,而不是使用清单中指定的名称。

读取镜像地址

在目标集群上运行以下命令。导出的变量会在后续步骤中使用:

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}')

echo "${JAEGER_IMAGE}"
echo "${JAEGER_ES_ROLLOVER_IMAGE}"
echo "${JOAUTH2_PROXY_IMAGE}"

升级 Alauda Build of OpenTelemetry v2 Operator

该 Operator 使用 Manual 批准策略订阅,因此必须显式批准升级。关于 Operator 升级的一般背景,请参见 Operator

通过 Web 控制台升级

请选择以下方法之一:

  • 批量升级:导航到 Platform Management > Cluster Management > Clusters > cluster > Functional Components,然后升级 Alauda Build of OpenTelemetry v2
  • 单独升级:导航到 Administrator > Marketplace > OperatorHub,打开 Alauda Build of OpenTelemetry v2,并批准待处理的升级请求。

通过 CLI 升级

  1. 确认订阅的 channel 中已提供目标版本:

    kubectl -ncpaas-system get packagemanifest opentelemetry-operator2 \
      -o jsonpath='{range .status.channels[*]}{.name}{"\t"}{.currentCSV}{"\n"}{end}'
  2. 批准待处理的 InstallPlan

    PLAN=$(kubectl -nopentelemetry-operator2 get subscription opentelemetry-operator2 \
      -o jsonpath='{.status.installPlanRef.name}')
    kubectl -nopentelemetry-operator2 patch installplan "${PLAN}" \
      --type=json -p='[{"op": "replace", "path": "/spec/approved", "value": true}]'
  3. 等待新的 ClusterServiceVersion 进入 Succeeded 阶段:

    kubectl -nopentelemetry-operator2 get csv

    示例输出

    NAME                                  DISPLAY                            VERSION      REPLACES                              PHASE
    opentelemetry-operator2.v0.157.0-r1   Alauda Build of OpenTelemetry v2   0.157.0-r1   opentelemetry-operator2.v0.147.0-r0   Succeeded
NOTE

Operator 升级会重启其管理的 collector。otel Collector 不固定 spec.image,因此会立即采用随新 Operator 一起发布的 Collector 版本,而 Jaeger 实例会一直使用 spec.image 中固定的镜像,直到步骤 5。重命名后的组件类型仍可作为已弃用的别名使用,因此 Collector 会继续运行,只会记录弃用警告,直到下一步。

更新 OpenTelemetry Collector

NOTE

Operator 会在升级期间重新签发其 admission webhook 证书。在该时间窗口内应用的 patch 会被拒绝,并显示 failed calling webhook "mopentelemetrycollectorbeta.kb.io": ... x509: certificate signed by unknown authority。请等待几秒后再重新应用。

操作步骤

  1. 创建名为 otel-upgrade-patch.yaml 的文件,内容如下:

    otel-upgrade-patch.yaml
    spec:
      config:
        exporters:
          otlp/traces: null
          otlp_grpc/traces:
            endpoint: "${JAEGER_INSTANCE_NAME}-collector.${JAEGER_NS}.svc.cluster.local:4317"
            tls:
              insecure: true
          prometheus:
            add_metric_suffixes: null
            translation_strategy: UnderscoreEscapingWithoutSuffixes
        service:
          pipelines:
            traces:
              exporters: [debug, otlp_grpc/traces]
          telemetry:
            metrics:
              readers:
                - pull:
                    exporter:
                      prometheus:
                        host: 0.0.0.0
                        port: 8888
    1. otlp exporter 类型已重命名为 otlp_grpc。将旧键设置为 null 会将其移除,而新键会使用相同 endpoint 重新创建 exporter。
    2. add_metric_suffixes 已弃用并会被静默忽略。translation_strategy: UnderscoreEscapingWithoutSuffixes 可使 metric 名称不带 Prometheus 风格的后缀。
    3. Prometheus reader 的 without_scope_infowithout_type_suffixwithout_units 设置现在默认值为 true,并会被移除。由于 readers 是一个 list,patch 会整体替换它。暴露的 metric 名称保持不变。
  2. 使用 envsubst 渲染该 patch 并应用:

    kubectl patch opentelemetrycollector otel -n ${JAEGER_NS} \
      --type=merge -p "$(envsubst < otel-upgrade-patch.yaml)"
  3. 等待 Collector 重启,并确认其启动时没有弃用警告:

    kubectl rollout status deployment/otel-collector -n ${JAEGER_NS} --timeout=180s
    sleep 3
    kubectl logs deployment/otel-collector -n ${JAEGER_NS} --tail=200 \
      | grep -i "deprecated" || echo "No deprecation warnings"

(可选)为 Service Performance Monitoring 更新 Collector

重命名将 spans 路由到 Jaeger tier 的 loadbalancing exporter。请在上一条 patch 后立即应用此 patch:如果中间有间隔,spans 会通过直接 exporter 到达 Jaeger,而不是由 service 路由,这会在 Jaeger tier 运行多个 replica 时导致 RED 指标碎片化。

  1. 创建名为 otel-spm-upgrade-patch.yaml 的文件,内容如下:

    otel-spm-upgrade-patch.yaml
    spec:
      config:
        exporters:
          otlp_grpc/traces: null # not used when spans are routed through load_balancing
          loadbalancing: null
          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"
        service:
          pipelines:
            traces:
              exporters: [debug, load_balancing]
  2. 使用 envsubst 渲染该 patch 并应用:

    kubectl patch opentelemetrycollector otel -n ${JAEGER_NS} \
      --type=merge -p "$(envsubst < otel-spm-upgrade-patch.yaml)"
    
    kubectl rollout status deployment/otel-collector -n ${JAEGER_NS} --timeout=180s

更新 Elasticsearch 索引模板

Jaeger v2.20.0 会写入额外的 span 字段,例如 scopeTagsreferences.traceState。请使用新镜像重新运行 jaeger-es-rollover 初始化,以便更新 index templates,并使未来 rollover 创建的索引带有新的 mappings。

该初始化是幂等的:它会覆盖 index templates,并跳过已存在的索引和 alias。现有数据不会被修改。

操作步骤

  1. 运行初始化 Job:

    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
    
    kubectl wait --for=condition=complete job/jaeger-es-rollover-init -n ${JAEGER_NS} --timeout=180s
    kubectl delete job jaeger-es-rollover-init -n ${JAEGER_NS}
  2. 验证 span index template 现在包含新字段:

    ES_USER=$(kubectl -n${JAEGER_NS} get secret es-credentials -o jsonpath='{.data.ES_USER}' | base64 -d)
    ES_PASS=$(kubectl -n${JAEGER_NS} get secret es-credentials -o jsonpath='{.data.ES_PASS}' | base64 -d)
    curl -k -sS -u "${ES_USER}:${ES_PASS}" \
      "${ES_ENDPOINT}/_index_template/${JAEGER_ES_INDEX_PREFIX}-jaeger-span" | grep -o scopeTags

更新 Alauda Build of Jaeger v2

操作步骤

  1. 更新 OAuth2 Proxy sidecar 镜像。由于 additionalContainers 是一个 list,merge patch 会整体替换它,因此此容器需要使用单独的 JSON patch 更新。此时 Jaeger 容器仍在运行旧版本,因此这次重启是安全的:

    kubectl patch opentelemetrycollector ${JAEGER_INSTANCE_NAME} -n ${JAEGER_NS} --type=json \
      -p "[{\"op\": \"replace\", \"path\": \"/spec/additionalContainers/0/image\", \"value\": \"${JOAUTH2_PROXY_IMAGE}\"}]"
  2. 创建名为 jaeger-upgrade-patch.yaml 的文件,内容如下。镜像和配置必须同时更改,因此两者都属于同一个 patch:

    jaeger-upgrade-patch.yaml
    spec:
      image: "${JAEGER_IMAGE}"
      config:
        extensions:
          jaeger_storage:
            backends:
              es_storage:
                elasticsearch:
                  use_aliases: null
                  use_ilm: null
                  max_trace_duration: "${JAEGER_MAX_TRACE_DURATION}"
                  indices:
                    spans:
                      rotation:
                        auto_rollover: {}
                    services:
                      rotation:
                        auto_rollover: {}
                    dependencies:
                      rotation:
                        auto_rollover: {}
                    sampling:
                      rotation:
                        auto_rollover: {}
        service:
          telemetry:
            resource: null
            metrics:
              level: detailed
              readers:
                - pull:
                    exporter:
                      prometheus:
                        host: 0.0.0.0
                        port: 8888
    1. 自 Jaeger v2.20.0 起,旧版轮转标志会被拒绝,必须移除。
    2. max_trace_duration 会向两侧扩展 query time range,以便仍能找到超出 search window 的 spans。请参见 Query Time Range
    3. rotation.auto_rollover 取代了 use_aliasesuse_ilm。其默认 alias 名称与 jaeger-es-rollover 初始化创建的 alias 名称一致,因此无需更改任何数据、alias 或 ILM policy。请将 auto_rollover.policy_name 留空,因为 ILM policy 引用已经嵌入在 index templates 中。请参见 Index Management Strategies
    4. Operator 将 service.telemetry.resource 解析为字符串的扁平 map;如果不是这种格式,则会静默丢弃整个 service.telemetry 部分。Jaeger 已经会报告其自身的 service.nameservice.version,因此这里是删除该 block,而不是迁移它。
    5. 对于 otel Collector,without_* 设置现在默认值为 true,并会通过替换 readers list 的方式移除。
  3. 使用 envsubst 渲染该 patch,应用,并等待 Jaeger 重启:

    kubectl patch opentelemetrycollector ${JAEGER_INSTANCE_NAME} -n ${JAEGER_NS} \
      --type=merge -p "$(envsubst < jaeger-upgrade-patch.yaml)"
    
    kubectl rollout status deployment/${JAEGER_INSTANCE_NAME}-collector -n ${JAEGER_NS} --timeout=300s

(可选)为 Service Performance Monitoring 更新 Jaeger

  1. 创建名为 jaeger-spm-upgrade-patch.yaml 的文件,内容如下:

    jaeger-spm-upgrade-patch.yaml
    spec:
      config:
        connectors:
          spanmetrics: null
          span_metrics: {}
        exporters:
          prometheus:
            add_metric_suffixes: null
            translation_strategy: UnderscoreEscapingWithoutSuffixes
        service:
          pipelines:
            traces:
              exporters: [debug, jaeger_storage_exporter, span_metrics]
            metrics/spanmetrics:
              receivers: [span_metrics]
  2. 使用 envsubst 渲染该 patch,应用,并等待 Jaeger 重启:

    kubectl patch opentelemetrycollector ${JAEGER_INSTANCE_NAME} -n ${JAEGER_NS} \
      --type=merge -p "$(envsubst < jaeger-spm-upgrade-patch.yaml)"
    
    kubectl rollout status deployment/${JAEGER_INSTANCE_NAME}-collector -n ${JAEGER_NS} --timeout=300s
NOTE

此重命名适用于 Jaeger distribution。独立的 OpenTelemetry Collector 仅从 Collector 0.152.0 开始注册 span_metrics,因此在前置 Collector 配置中重命名 connector 之前,请先确认 Collector 版本。

验证

  1. 确认组件版本以及所有 Pod 均已就绪:

    kubectl -n${JAEGER_NS} get opentelemetrycollector
    kubectl -n${JAEGER_NS} get pods
  2. 确认 Jaeger 启动时没有弃用警告:

    kubectl logs deployment/${JAEGER_INSTANCE_NAME}-collector -n ${JAEGER_NS} \
      -c otc-container --tail=300 | grep -iE "warn|error" || echo "No warnings"
  3. 生成示例 traces,并确认它们已被存储且可以查询,如安装操作步骤中的 Verification 部分所述。如果启用了 SPM,还请打开 Jaeger UI 中的 Monitor 选项卡,并确认为生成的 service 显示了 RED 指标。