从 Alauda Container Platform Tracing 迁移

本文介绍如何将基于旧版 Alauda Container Platform (ACP) Tracing 堆栈的现有 tracing 部署 — Alauda Build of Jaeger(Jaeger 1.60.0)加 Alauda Build of OpenTelemetry — 迁移到基于 Jaeger v2(2.20.0)加 Alauda Build of OpenTelemetry v2Alauda Distributed Tracing

迁移分为两个阶段:

  1. OpenTelemetry 堆栈迁移。 将旧版 Alauda Build of OpenTelemetry Operator 和 Collector 替换为 Alauda Build of OpenTelemetry v2。应用 Pod 会执行滚动更新,以注入 v2 Java agent。完成此阶段后,telemetry 由 v2 Collector 收集,但仍写入旧版 Jaeger 后端。按照 从 Alauda Build of OpenTelemetry 迁移到 Alauda Build of OpenTelemetry v2 中的步骤执行此阶段。

  2. Jaeger 后端迁移。 在旧版 Jaeger 旁部署新的 Jaeger v2 实例,将旧版 Elasticsearch 索引附加到新实例的读取别名,将 v2 Collector 的 trace exporter 切换到新后端,并在新 pipeline 验证完成后卸载旧版 Jaeger。

旧版 trace 数据不会被复制或重新索引。其索引会附加到新 Jaeger 的读取别名,因此切换后,新的 Jaeger UI 会同时提供切换前和切换后的 trace,您可以在确信新 pipeline 正常工作后立即移除旧版堆栈,而不必等待完整的保留期限结束。

概述

ACP Tracing 与 Alauda Distributed Tracing 的变化

项目Alauda Container Platform Tracing(旧版)Alauda Distributed Tracing(目标)
Jaeger 版本1.60.02.20.0
Jaeger OperatorAlauda Build of Jaeger Operator(CRD:jaegertracing.io/v1.JaegerAlauda Build of OpenTelemetry v2 Operator(Jaeger v2 部署为 opentelemetry.io/v1beta1.OpenTelemetryCollector
默认 Elasticsearch 索引前缀acp-tracing-<cluster>(按日期标记的每日索引)acp-<cluster>(滚动写入/读取别名)
Elasticsearch 保留策略jaeger-es-index-cleaner CronJob 删除早于 numberOfDays 的每日索引(默认值为 7Index Lifecycle Management (ILM) 策略 jaeger-ilm-policy 自动滚动和删除索引(默认删除期限为 7d
Tracing UI 入口平台定制的 Observability → Tracing 视图,由 acp-tracing-ui feature switch 控制通过带有 OAuth2 Proxy sidecar 的 Ingress 暴露的原生 Jaeger UI

有关 OpenTelemetry Operator、Collector 和 Instrumentation 资源的变化(包括现在必需的 spec.java.image 字段、与 Service Mesh v1 的不兼容性以及 Collector 配置架构迁移),请参阅 OpenTelemetry v2 迁移指南中的 v1 与 v2 之间的变化

NOTE

旧版 Alauda Build of Jaeger Operator 管理独立的 CRD(jaegertracing.io/v1.Jaeger),与 v2 OpenTelemetry Operator 冲突。因此,在迁移期间会继续运行它,使旧版 Jaeger 在新 pipeline 验证完成前持续可用,作为回滚目标。

迁移中断窗口

Trace ingestion 会在以下两个位置中断:

  1. OpenTelemetry v1 → v2 迁移期间,即从删除旧版 OpenTelemetryCollector 到 v2 OpenTelemetryCollector 就绪之间。请参阅 OpenTelemetry v2 迁移指南中的 迁移中断窗口

  2. Jaeger 切换期间,即修补 v2 Collector,将其 trace exporter 从旧版 Jaeger 重定向到新版 Jaeger v2 后端时。Collector deployment 会执行滚动更新,因此更新期间可能出现短暂的 ingestion 间隔。

在这两个窗口期间,应用 Pod 均会继续正常运行,但在间隔期间生成的 telemetry 可能会暂时缓冲;如果无法及时导出,也可能被丢弃。请在低流量窗口期间规划每个阶段,并提前通知 telemetry 使用者(开发人员、SRE、Kiali 用户)。

在整个迁移过程中,旧版 Jaeger 查询路径仍然可用,因此在新 pipeline 启动期间,仍可在旧版 Jaeger UI 中搜索之前存储的 trace。

迁移流程概览

[Stage 1] Migrate Alauda Build of OpenTelemetry to v2 (per external guide)
              ↓ v2 Collector keeps writing traces to the legacy Jaeger
[Step 1]  Deploy the new Jaeger v2 instance (jaeger-system)
[Step 2]  Attach the legacy indices to the new read aliases
              ↓ the new Jaeger UI now serves pre-cutover traces
[Step 3]  Switch the v2 OpenTelemetry Collector to write to the new Jaeger
              ↓ trace ingestion cutover; new traces go to the new Jaeger
[Step 4]  Verify the migration

[Validation] as long as you need — the legacy Jaeger stays as a rollback target

[Step 5]  Take over retention of the legacy indices
[Step 6]  Uninstall the legacy Jaeger instance and Operator
[Step 7]  Disable the legacy feature switch

Trace 数据连续性策略

按照 OpenTelemetry v2 迁移期间 重新创建 OpenTelemetryCollector 资源 中的指导,v2 OpenTelemetry Collector 会部署在与旧版 Collector 相同的 namespace 中,并使用相同的 Service 名称(otel-collector,位于 cpaas-system 中)。将 OTLP 导出到 otel-collector.cpaas-system 的应用无需任何配置更改即可继续工作。

Trace 数据既不会被复制,也不会被重新索引。旧版按日期标记的索引会保留在原处,并在将旧版索引附加到新的读取别名中附加到新 Jaeger 的读取别名。Jaeger v2 的每次读取都会通过这些别名解析,因此附加后:

  • 切换前摄取的 trace 会保留在旧版索引(acp-tracing-<cluster>-jaeger-*-YYYY-MM-DD)中,并由位于 <platform-url>/clusters/<cluster>/jaeger Jaeger UI 与新 trace 一起提供服务,直到其自身的保留策略将其删除。只要旧版实例仍被保留,这些 trace 也会继续显示在旧版 Jaeger UI 中。
  • 切换后摄取的 trace 会通过 *-write 别名写入新的索引系列(acp-<cluster>-jaeger-*-000001-000002、……)。旧版索引不会再次被写入。

之所以能够实现这一点,是因为 Jaeger 2.20.0 可以直接读取 Jaeger 1.60.0 写入的文档:两个版本使用相同的 Elasticsearch 文档模型,它们之间的映射差异 — 旧版模板声明 tags.tagType,而 v2 模板声明 tags.type,并且 v2 增加了 scopeTagsreferences.traceState — 不会影响 Jaeger 查询所使用的任何字段。

由于新的 Jaeger UI 从附加别名的那一刻起就具备完整视图,用户无需了解哪个 UI 保存哪个时间范围的 trace;旧版堆栈也不再需要仅为了响应历史查询而持续运行完整的保留期限。

前置条件

  • 由具有 cluster-admin 角色的集群管理员建立的活动 ACP CLI(kubectl)会话。
  • 旧版 ACP Tracing 堆栈(Alauda Build of Jaeger Operator 及其 Jaeger 实例,以及包含 OpenTelemetryCollector 和一个或多个 Instrumentation 资源的 Alauda Build of OpenTelemetry)当前已安装。
  • 集群可以访问 Elasticsearch 8.x,并且你拥有具有创建 ILM 策略、索引模板和索引别名权限,以及更新索引设置权限的 Elasticsearch 用户。
  • jqenvsubst 命令行工具已安装在运行迁移命令的工作站上。
  • 已通知 telemetry 使用者(开发人员、Kiali 用户、SRE 仪表板使用者)和应用所有者计划中的中断窗口。

迁移前任务

将 Alauda Build of OpenTelemetry 迁移到 v2

在迁移 Jaeger 后端之前,请按照 从 Alauda Build of OpenTelemetry 迁移到 Alauda Build of OpenTelemetry v2 完成从 Alauda Build of OpenTelemetryAlauda Build of OpenTelemetry v2 的迁移。该指南涵盖:

  • 备份并卸载旧版 Alauda Build of OpenTelemetry Operator 及其 OpenTelemetryCollectorInstrumentation 资源。
  • 安装 v2 Operator。
  • 准备用于 Java 自动插桩的镜像,并重新创建 OpenTelemetryCollectorInstrumentation 资源,包括设置现在必需的 spec.java.image 字段。
  • 滚动更新应用 pod,以便注入新的 Java agent。

在此阶段结束时:

  • v2 Alauda Build of OpenTelemetry Operator 已安装,旧版 Operator 已卸载。
  • cpaas-system 中的 v2 OpenTelemetryCollector 正在运行,其 trace exporter 仍指向旧版 Jaeger(这是从 v1 备份重新创建 Collector 的自然结果)。
  • 所有 Instrumentation 资源均已设置 spec.java.image,并且应用 pod 已使用 v2 Java agent 完成滚动更新。

在本指南的将 v2 OpenTelemetry Collector 切换到新 Jaeger之前,Trace 摄取会继续流入旧版 Jaeger。

清点旧版 Jaeger 部署

记录旧版 Jaeger 的当前状态,以便了解迁移范围,并生成用于回滚的备份。

  1. 列出旧版 Alauda Build of Jaeger Operator 和 Jaeger 实例:

    kubectl get csv -A | grep -i jaeger
    kubectl get jaeger -A
  2. 记录旧版 Jaeger 资源中引用的旧版 Elasticsearch 端点、凭据和索引前缀。新 Jaeger v2 实例也会重复使用这些信息。

备份旧版 Jaeger 资源

导出旧版 Jaeger 资源,以便重新构建这些资源(并在需要时执行回滚):

mkdir -p ./acp-tracing-backup

# Jaeger CR (covers the jaeger-prod instance in cpaas-system).
kubectl get jaeger -A -o yaml \
  > ./acp-tracing-backup/jaegers.yaml

# Alauda Build of Jaeger Operator Subscription and CSV.
kubectl get subscription -n jaeger-operator jaeger-operator -o yaml \
  > ./acp-tracing-backup/jaeger-v1-subscription.yaml || true
kubectl -n jaeger-operator get csv -o yaml \
  > ./acp-tracing-backup/jaeger-v1-csv.yaml || true

# Supporting resources for jaeger-prod in cpaas-system. Each is removed in
# Cleanup, so back them up here so rollback can restore them. Skip silently
# (|| true) if a resource is not present in this environment.
kubectl -n cpaas-system get ingress     jaeger-prod-query         -o yaml \
  > ./acp-tracing-backup/jaeger-prod-ingress.yaml             || true
kubectl -n cpaas-system get podmonitor  jaeger-prod-monitor       -o yaml \
  > ./acp-tracing-backup/jaeger-prod-podmonitor.yaml          || true
kubectl -n cpaas-system get rolebinding jaeger-prod-rb            -o yaml \
  > ./acp-tracing-backup/jaeger-prod-rolebinding.yaml         || true
kubectl -n cpaas-system get role        jaeger-prod-role          -o yaml \
  > ./acp-tracing-backup/jaeger-prod-role.yaml                || true
kubectl -n cpaas-system get sa          jaeger-prod-sa            -o yaml \
  > ./acp-tracing-backup/jaeger-prod-sa.yaml                  || true
kubectl -n cpaas-system get secret      jaeger-prod-oauth2-proxy  -o yaml \
  > ./acp-tracing-backup/jaeger-prod-oauth2-proxy-secret.yaml || true
kubectl -n cpaas-system get secret      jaeger-prod-es-basic-auth -o yaml \
  > ./acp-tracing-backup/jaeger-prod-es-basic-auth-secret.yaml || true
kubectl -n cpaas-system get configmap   jaeger-prod-oauth2-proxy  -o yaml \
  > ./acp-tracing-backup/jaeger-prod-oauth2-proxy-configmap.yaml || true
NOTE

备份文件仅用作配置参考和回滚构件。在 v2 上重新构建 Jaeger 时,请遵循安装 Alauda Distributed Tracing中所述的 v2 约定。

验证 Elasticsearch 容量

新 Jaeger 会写入单独的索引系列(acp-<cluster>-jaeger-*),而旧版索引(acp-tracing-<cluster>-jaeger-*)会在旧版保留期限内逐渐过期。请为 Elasticsearch 规划额外一整个保留期限所需的 trace 存储空间。

迁移操作步骤

部署新的 Jaeger v2 实例

按照 Alauda Distributed Tracing 安装指南中的部署 Alauda Build of Jaeger v2进行操作。新的 Jaeger v2 实例将部署在专用命名空间(默认为 jaeger-system)中,因此不会与 cpaas-system 中的旧版 jaeger-prod 实例冲突。

WARNING

仅按照上面链接的部署 Alauda Build of Jaeger v2部分进行操作。不要执行同一安装指南中的部署 OpenTelemetry Collector部分 — 面向应用的 v2 OpenTelemetry Collector 已在阶段 1(OpenTelemetry v2 迁移)期间部署到 cpaas-system。执行该部分会在 jaeger-system 中创建重复的 otel Collector,而没有任何应用会与其通信。

到达变量设置步骤时,保留默认索引前缀,以便新的 Jaeger 将数据写入与旧版索引明确分离的索引:

export JAEGER_NS="jaeger-system"
export JAEGER_INSTANCE_NAME="jaeger"
export JAEGER_ES_INDEX_PREFIX="acp-${CLUSTER_NAME}"      # different from the legacy "acp-tracing-${CLUSTER_NAME}"
export JAEGER_BASEPATH="/clusters/${CLUSTER_NAME}/jaeger"  # different from the legacy "/clusters/${CLUSTER_NAME}/acp/jaeger"

完成安装步骤后,验证以下内容:

  • jaeger-system 中的 Jaeger Pod 处于 Ready 状态。
  • Jaeger UI 可通过 <platform-url>/clusters/<cluster>/jaeger 访问。此时 UI 为空,因为尚无 exporter 向其中写入数据,旧版索引也尚未附加。
  • Service jaeger-collector.jaeger-system.svc.cluster.local 在端口 4317 上接受 OTLP gRPC — 这就是 v2 OpenTelemetry Collector 将在将 v2 OpenTelemetry Collector 切换到新的 Jaeger中导出的端点。

将旧版索引附加到新的读取别名

上一步中运行的 jaeger-es-rollover init Job 为新索引系列创建了 <prefix>-jaeger-<type>-read<prefix>-jaeger-<type>-write 别名。Jaeger v2 通过读取别名解析所有读取操作,因此只需将旧版按日期标记的索引添加到该别名,就能使切换前的 trace 可在新的 Jaeger UI 中查询。不会复制、重命名或重新索引任何内容,旧版 Jaeger 仍会提供相同索引的服务。

在切换前执行此步骤,以便新的 Jaeger UI 在开始接收 trace 时就已包含完整数据。

操作步骤

  1. 设置旧版索引前缀。该前缀是在清点旧版 Jaeger 部署中记录的 es.index-prefix 值:

    export LEGACY_ES_INDEX_PREFIX="acp-tracing-${CLUSTER_NAME}"
  2. 将旧版索引添加到新索引系列的读取别名:

    for TYPE in span service dependencies sampling; do
      echo -n "${TYPE}: "
      curl -k -sS -u "${ES_USER}:${ES_PASS}" -X POST \
        "${ES_ENDPOINT}/_aliases" -H 'Content-Type: application/json' \
        -d "{\"actions\":[{\"add\":{\"index\":\"${LEGACY_ES_INDEX_PREFIX}-jaeger-${TYPE}-2*\",\"alias\":\"${JAEGER_ES_INDEX_PREFIX}-jaeger-${TYPE}-read\"}}]}"
      echo
    done

    -2* 模式匹配按日期标记的旧版索引,例如 -2026-08-27,不会匹配新索引系列的编号滚动索引。未启用依赖分析和自适应采样运行的旧版 Jaeger 没有 dependenciessampling 索引,因此这两次迭代会返回 index_not_found_exception。这是预期行为,不会影响另外两次迭代。

    若只需附加部分历史数据,请将模式缩小到所需的日期范围,例如 ${LEGACY_ES_INDEX_PREFIX}-jaeger-${TYPE}-2026-08-1*。每次查询都会扫描所有已附加的索引,因此只附加仍需要搜索的索引。

  3. 确认两个索引系列都由读取别名解析,并且写入别名仍仅指向新的编号索引:

    curl -k -sS -u "${ES_USER}:${ES_PASS}" \
      "${ES_ENDPOINT}/_cat/aliases/${JAEGER_ES_INDEX_PREFIX}-jaeger-*?v&h=alias,index,is_write_index&s=alias"

    示例输出

    alias                                     index                                                  is_write_index
    acp-${CLUSTER_NAME}-jaeger-service-read   acp-${CLUSTER_NAME}-jaeger-service-000001              -
    acp-${CLUSTER_NAME}-jaeger-service-read   acp-tracing-${CLUSTER_NAME}-jaeger-service-YYYY-MM-DD  -
    acp-${CLUSTER_NAME}-jaeger-service-write  acp-${CLUSTER_NAME}-jaeger-service-000001              true
    acp-${CLUSTER_NAME}-jaeger-span-read      acp-${CLUSTER_NAME}-jaeger-span-000001                 -
    acp-${CLUSTER_NAME}-jaeger-span-read      acp-tracing-${CLUSTER_NAME}-jaeger-span-YYYY-MM-DD     -
    acp-${CLUSTER_NAME}-jaeger-span-write     acp-${CLUSTER_NAME}-jaeger-span-000001                 true

    只有 -000001 索引带有 is_write_index: true。旧版索引仅附加用于读取,因此新的 Jaeger 无法向其中写入数据。

  4. 打开 <platform-url>/clusters/<cluster>/jaeger 中的新的 Jaeger UI,确认切换前上报数据的服务已列出,并且可以打开其中一个服务的 trace。

    NOTE

    在 UI 中选择覆盖旧版数据的时间范围。Jaeger UI 始终会发送明确的时间范围,因此时间范围选择器会按预期工作。

将 v2 OpenTelemetry Collector 切换到新的 Jaeger

在完成 OpenTelemetry v1 → v2 迁移后,重建的 otel OpenTelemetryCollectorcpaas-system 中仍会将 trace 写入旧版 Jaeger,因为其 trace exporter 继承自 v1 备份。其 spec.config 中与 trace 相关的部分通常如下所示(其他字段与此步骤无关,已省略):

otel collector — post-OpenTelemetry-migration state
spec:
  config:
    exporters:
      debug: {}
      otlp:
        balancer_name: round_robin
        endpoint: dns:///jaeger-prod-collector-headless.cpaas-system:4317
        tls:
          insecure: true
    service:
      pipelines:
        traces:
          receivers:  [otlp]
          processors: [memory_limiter, batch]
          exporters:  [debug, otlp] 
  1. 旧版 Jaeger exporter — 继承自 v1 备份 — 名为 otlp,目标为 cpaas-system 中旧版 Jaeger Collector 的无头 Service。balancer_name: round_robin 会在无头 Service 的端点之间分发 span。otlpotlp_grpc exporter 类型的已弃用别名,下面的切换步骤将采用后者。
  2. trace pipeline 会将 span 发送到 debug(日志)和 otlp(旧版 Jaeger)。

修补 Collector,以便:(1) 添加一个指向 jaeger-system 中新 Jaeger v2 Collector Service 的新 otlp_grpc/jaeger-v2 exporter;(2) 将旧版 otlp exporter 设置为 null,从而移除该 exporter;以及 (3) 将 trace pipeline 的 exporter 列表替换为 [debug, otlp_grpc/jaeger-v2]

kubectl -n cpaas-system patch opentelemetrycollector otel --type=merge -p '
spec:
  config:
    exporters:
      otlp_grpc/jaeger-v2:
        endpoint: jaeger-collector.jaeger-system.svc.cluster.local:4317
        tls:
          insecure: true
      otlp: null # the inherited exporter is named otlp, so it is removed under that name
    service:
      pipelines:
        traces:
          exporters: [debug, otlp_grpc/jaeger-v2]
'
kubectl rollout status deployment/otel-collector -n cpaas-system --timeout=180s
OTLP gRPC exporter 的名称为

otlp_grpc exporter 类型名称为 otlp_grpc,而不是 otlp。前一个名称作为已弃用别名仍然有效,但 Collector 会在启动时为每个受影响的组件实例记录弃用警告。上游计划在未来版本中移除该别名。由于继承的 exporter 无论如何都将被替换,此次迁移正好可以采用当前名称。

此重命名适用于新创建的 exporter。保留 otlp: null 不变:它会移除 Collector 上已经以该名称存在的 exporter。

WARNING

service.pipelines.traces.exporters 是一个数组,而合并补丁会整体替换数组,而不是追加数组。上面的补丁列出了 trace pipeline 中必须保留的所有 exporter(debugotlp_grpc/jaeger-v2)。如果你的 trace pipeline 包含其他自定义 exporter,请在应用补丁前将其添加到此列表中。

如果 Collector 上继承的旧版 Jaeger exporter 不名为 otlp(例如你的 v1 备份使用了 jaeger 或其他 OTLP 变体),请在 null 移除步骤中相应替换该名称。

trace pipeline 中必须恰好保留一个 Jaeger exporter

上面的补丁会替换旧版 exporter,而不是添加第二个 exporter。不要让两个 exporter 同时保留在 pipeline 中。由于旧版索引已附加到读取别名,写入两个后端的 span 会同时建立在两个索引系列中,新的 Jaeger 会将其返回两次 — 一个包含五个 span 的 trace 会显示为十个 span。请参阅trace 数据连续性策略

至此,trace 摄取已恢复。新的 trace 会写入新的 Jaeger v2 后端,并可在新的 Jaeger UI 中搜索。

验证迁移

  1. 确认两个 OpenTelemetryCollector 资源均运行正常:

    kubectl get opentelemetrycollector -A

    示例输出:

    NAMESPACE       NAME     MODE         VERSION   READY   AGE   IMAGE                                                           MANAGEMENT
    cpaas-system    otel     deployment   0.156.0   1/1     5h    build-harbor.alauda.cn/asm/opentelemetry-collector:0.158.0-r0   managed
    jaeger-system   jaeger   deployment   0.156.0   1/1     33m   build-harbor.alauda.cn/asm/jaeger:2.20.0-2.1.0-r0               managed

    cpaas-system/otel(面向应用的 Collector,由 OpenTelemetry v1 → v2 迁移重新部署)和 jaeger-system/jaeger(新的 Jaeger v2 后端,在部署新的 Jaeger v2 实例中部署)都必须将 READY 报告为 <ready>/<desired>,其中 <ready> 等于 <desired>(通常为 1/1),且 MANAGEMENTmanaged。如果 READY 列显示 0/1 或为空,请先检查相应命名空间中的 Collector Pod 日志,再继续操作。

  2. 使用 telemetrygen 生成示例 trace,并确认它们显示在新的 Jaeger UI 中:

    kubectl apply -n cpaas-system -f - <<EOF
    apiVersion: v1
    kind: Pod
    metadata:
      name: jaeger-migration-check
    spec:
      restartPolicy: Never
      containers:
        - name: telemetrygen
          image: ghcr.io/open-telemetry/opentelemetry-collector-contrib/telemetrygen:latest
          args:
            - traces
            - --otlp-endpoint=otel-collector.cpaas-system.svc.cluster.local:4317
            - --otlp-insecure
            - --duration=120s
            - --service=jaeger-migration-check
            - --rate=2
    EOF
    
    kubectl wait -n cpaas-system --for=jsonpath='{.status.phase}'=Succeeded \
      pod/jaeger-migration-check --timeout=10m
    kubectl delete -n cpaas-system pod/jaeger-migration-check

    <platform-url>/clusters/<cluster>/jaeger 中的新 Jaeger UI 应列出 jaeger-migration-check 服务及其 trace。

  3. 确认 Elasticsearch 中正在创建新的索引系列,并且旧版索引系列保持完整:

    curl -k -sS -u "${ES_USER}:${ES_PASS}" "${ES_ENDPOINT}/_cat/indices?v" \
      | grep -E 'acp-tracing-|acp-' | sort

    你应看到匹配 acp-tracing-<cluster>-jaeger-* 的旧版索引(按日期标记,不再增长)和匹配 acp-<cluster>-jaeger-*-000001 的新索引(滚动增长)。

  4. 抽查真实业务请求是否会在新的 Jaeger UI 中生成 trace。选择一个或两个已完成插桩的应用,触发具有代表性的请求,然后在新的 Jaeger UI 中查找其 traceID。

  5. 确认切换前的 trace 仍可访问,并且新的 Jaeger 没有覆盖索引模板:

    curl -k -sS -u "${ES_USER}:${ES_PASS}" \
      "${ES_ENDPOINT}/_cat/aliases/${JAEGER_ES_INDEX_PREFIX}-jaeger-span-read?v&h=alias,index&s=index"
    curl -k -sS -u "${ES_USER}:${ES_PASS}" \
      "${ES_ENDPOINT}/_index_template/${JAEGER_ES_INDEX_PREFIX}-jaeger-span" \
      | grep -o "rollover_alias\|${JAEGER_ES_INDEX_PREFIX}-jaeger-span-read"

    读取别名必须列出旧版按日期标记的索引以及新的 -000001 索引,并且在切换前最后一次上报数据的服务仍必须显示在新的 Jaeger UI 中。

    第二条命令必须输出读取别名和 rollover_alias。如果结果为空,表示 Jaeger 实例在启动时重新创建了索引模板,因为 create_mappings 未设置为 false。已附加的旧版索引不受影响,但未来的滚动索引将不再添加到读取别名中,ILM 也将无法执行滚动。请在 Jaeger 实例上设置 create_mappings: false,然后重新运行安装指南中的 jaeger-es-rollover init Job。

验证期

无需让旧版 Jaeger 保留完整的保留期。切换前的 trace 会通过读取别名由新 Jaeger 提供,因此旧版实例仅作为回滚目标。只要你希望保留该回退能力,就应保留旧版实例——通常为几小时到几天——并利用此窗口:

  • 针对新的 Jaeger UI 和 v2 Java agent 指标名称验证仪表板、告警和 Kiali 集成。
  • 确认切换前和切换后的 trace 都可在新的 Jaeger UI 中搜索。
  • 告知用户新的 Jaeger UI 现在是 trace 的唯一入口,旧版 UI <platform-url>/clusters/<cluster>/acp/jaeger 将被停用。

确认新管道运行可靠后,继续执行清理

WARNING

删除旧版 Jaeger 实例不会删除其 Elasticsearch 索引,因此切换前的 trace 之后仍可在新的 Jaeger UI 中查询。删除的是由 Jaeger 资源拥有的旧版 jaeger-es-index-cleaner CronJob。此后将没有任何机制使这些索引过期,这就是为什么必须先执行接管旧版索引的保留策略

清理

接管旧版索引的保留策略

截至目前,旧版 jaeger-es-index-cleaner CronJob 一直在使旧版索引过期。该 CronJob 由旧版 Jaeger 资源拥有,并将在下一步中随该资源一起被垃圾回收,因此必须先移交保留策略。否则旧版索引会无限期保留在 Elasticsearch 中,并且由于这些索引已附加到读取别名,还会在每次查询时持续被扫描。

为这些索引设置独立的 Index Lifecycle Management 策略,其中仅包含 delete 阶段。

新的

jaeger-ilm-policy 无法管理旧版索引 jaeger-ilm-policy 还包含 rollover 操作,而 Elasticsearch 只能对作为滚动别名写入索引的索引执行滚动。将其应用于按日期标记的旧版索引时,会失败并显示 setting [index.lifecycle.rollover_alias] for index [...] is empty or not defined;该索引将永远不会离开 hot 阶段,也不会被删除。因此必须使用单独的仅删除策略。

在切换完成后执行此步骤,并确保旧版 Jaeger 已停止创建新的每日索引。

操作步骤

  1. 创建策略。将 min_age 设置为旧版清理器应用的保留时长,即盘点旧版 Jaeger 部署中记录的 esIndexCleaner.numberOfDays 值,默认为 7

    export LEGACY_RETENTION_DAYS="7"
    
    curl -k -sS -u "${ES_USER}:${ES_PASS}" -X PUT \
      "${ES_ENDPOINT}/_ilm/policy/jaeger-legacy-ilm-policy" \
      -H 'Content-Type: application/json' --data-binary @- << EOF
    {
      "policy": {
        "phases": {
          "delete": {
            "min_age": "${LEGACY_RETENTION_DAYS}d",
            "actions": { "delete": {} }
          }
        }
      }
    }
    EOF
  2. 将其应用于整个旧版索引系列:

    curl -k -sS -u "${ES_USER}:${ES_PASS}" -X PUT \
      "${ES_ENDPOINT}/${LEGACY_ES_INDEX_PREFIX}-jaeger-*/_settings" \
      -H 'Content-Type: application/json' \
      -d '{"index.lifecycle.name":"jaeger-legacy-ilm-policy"}'
  3. 确认每个旧版索引都受策略管理,并且没有任何索引报告错误。默认情况下,Elasticsearch 每 10 分钟轮询一次 ILM,因此阶段在推进前会暂时保持为 new

    curl -k -sS -u "${ES_USER}:${ES_PASS}" \
      "${ES_ENDPOINT}/${LEGACY_ES_INDEX_PREFIX}-jaeger-*/_ilm/explain?pretty" \
      | grep -E '"index"|"managed"|"policy"|"phase"|"step"|"reason"'

    每个索引都必须报告 "managed" : true,策略为 jaeger-legacy-ilm-policy,并且不得出现 "reason" 行。

当索引达到保留期末尾时,Elasticsearch 会将其删除,并自动将其从读取别名中移除——无需维护别名。

卸载旧版 Jaeger 实例

删除旧版 Jaeger 实例及其支持资源。不会触及 Elasticsearch 索引,因此切换前的 trace 仍可在新的 Jaeger UI 中查询:

kubectl -n cpaas-system delete ingress      jaeger-prod-query         --ignore-not-found
kubectl -n cpaas-system delete podmonitor   jaeger-prod-monitor       --ignore-not-found
kubectl -n cpaas-system delete jaeger       jaeger-prod               --ignore-not-found
kubectl -n cpaas-system delete rolebinding  jaeger-prod-rb            --ignore-not-found
kubectl -n cpaas-system delete role         jaeger-prod-role          --ignore-not-found
kubectl -n cpaas-system delete sa           jaeger-prod-sa            --ignore-not-found
kubectl -n cpaas-system delete secret       jaeger-prod-oauth2-proxy  --ignore-not-found
kubectl -n cpaas-system delete secret       jaeger-prod-es-basic-auth --ignore-not-found
kubectl -n cpaas-system delete configmap    jaeger-prod-oauth2-proxy  --ignore-not-found

卸载 Alauda Build of Jaeger Operator:

kubectl -n jaeger-operator delete subscription jaeger-operator --ignore-not-found
TIP

如果集群中不再有其他 Jaeger 资源,也可以删除 jaegers.jaegertracing.io CRD:

kubectl get jaeger -A
kubectl delete crd jaegers.jaegertracing.io

禁用旧版功能开关并停用旧版索引系列

  1. 在 ACP Web 控制台中打开功能开关,并禁用 acp-tracing-ui。卸载旧版 Alauda Build of OpenTelemetry v1 Operator 后,平台定制的可观测性 → Tracing视图将不再可用。更新内部文档和操作手册,将其指向 Jaeger UI URL <platform-url>/clusters/<cluster>/jaeger

  2. 等待旧版索引过期。接管旧版索引的保留策略中应用的策略会在每个索引达到保留期后将其删除,并将其从读取别名中移除,因此此步骤无需执行任何操作,只需检查剩余内容:

    curl -k -sS -u "${ES_USER}:${ES_PASS}" \
      "${ES_ENDPOINT}/_cat/indices/${LEGACY_ES_INDEX_PREFIX}-jaeger-*?v&h=index,docs.count,store.size&s=index"

    若要在保留期结束前停用切换前的 trace,请直接删除索引,而不是等待其过期:

    # ?h=index returns just the index-name column (no table header),
    # which the for-loop iterates over.
    for idx in $(curl -k -sS -u "${ES_USER}:${ES_PASS}" \
                   "${ES_ENDPOINT}/_cat/indices/${LEGACY_ES_INDEX_PREFIX}-jaeger-*?h=index"); do
      curl -k -sS -u "${ES_USER}:${ES_PASS}" -X DELETE "${ES_ENDPOINT}/${idx}"
      echo
    done

    删除索引也会将其从读取别名中移除,因此新的 Jaeger 将不再返回这些 trace。

  3. 上一步的列表为空后,删除 ILM 不会自行清理的内容——旧版索引模板和仅删除策略:

    for TYPE in span service dependencies sampling; do
      curl -k -sS -u "${ES_USER}:${ES_PASS}" -X DELETE \
        "${ES_ENDPOINT}/_index_template/${LEGACY_ES_INDEX_PREFIX}-jaeger-${TYPE}"
      echo
    done
    
    curl -k -sS -u "${ES_USER}:${ES_PASS}" -X DELETE \
      "${ES_ENDPOINT}/_ilm/policy/jaeger-legacy-ilm-policy"

回滚

有关 OpenTelemetry v1 → v2 阶段的回滚,请参阅 OpenTelemetry v2 迁移指南中的 回滚。对于本文档中执行的 Jaeger 迁移阶段,请根据当前所处的阶段选择相应的回滚路径:

已达到的阶段建议的回滚操作
部署新版 Jaeger v2 实例之前Jaeger 阶段无需执行任何操作——旧版 Jaeger 仍在接收 trace,且新版 Jaeger 尚未部署。
部署新版 Jaeger v2 实例之后,但在将 v2 OpenTelemetry Collector 切换到新版 Jaeger之前如果旧版索引已附加到读取别名,请将其从读取别名中分离(见下文),然后删除新版 Jaeger 实例(kubectl -n jaeger-system delete opentelemetrycollector jaeger)。旧版 Jaeger 及其索引不会受到影响。
附加操作本身导致问题——查询速度缓慢或返回意外结果将旧版索引从读取别名中分离(见下文)。不会影响任何 trace 数据:新版 Jaeger 将恢复为仅提供切换后的 trace,旧版 Jaeger UI 仍会提供其余 trace。
新版 Jaeger 在验证期间出现问题修补 v2 Collector,使其 trace pipeline 指回旧版 Jaeger collector——将 otlp_grpc/jaeger-v2 替换为指向 dns:///jaeger-prod-collector-headless.cpaas-system:4317 的 exporter。旧版 Jaeger 会立即重新接收 trace。切勿同时运行两个 exporter;请参阅Trace 数据连续性策略
验证期结束后——完全回滚到旧版堆栈首先,将 v2 Collector 的 trace pipeline 指回旧版 Jaeger,并分离旧版索引。然后按照 OpenTelemetry v2 迁移指南中的 回滚 执行操作,并重新发布 Application Pod,以便重新注入旧版 Java agent。重新安装旧版 Operator 之前,必须先卸载新版 Jaeger v2 实例和 OpenTelemetry v2 Operator。

要分离旧版索引,请反向执行将旧版索引附加到新的读取别名中的别名操作:

for TYPE in span service dependencies sampling; do
  echo -n "${TYPE}: "
  curl -k -sS -u "${ES_USER}:${ES_PASS}" -X POST \
    "${ES_ENDPOINT}/_aliases" -H 'Content-Type: application/json' \
    -d "{\"actions\":[{\"remove\":{\"index\":\"${LEGACY_ES_INDEX_PREFIX}-jaeger-${TYPE}-2*\",\"alias\":\"${JAEGER_ES_INDEX_PREFIX}-jaeger-${TYPE}-read\"}}]}"
  echo
done

如果已经应用了接管旧版索引的保留策略中的仅删除 ILM 策略,也请将其移除,以免在恢复旧版堆栈期间旧版索引过期:

curl -k -sS -u "${ES_USER}:${ES_PASS}" -X PUT \
  "${ES_ENDPOINT}/${LEGACY_ES_INDEX_PREFIX}-jaeger-*/_settings" \
  -H 'Content-Type: application/json' \
  -d '{"index.lifecycle.name":null}'

FAQ

应用是否需要更新其 OTLP 端点?

不需要。按照 OpenTelemetry v2 迁移指南中的 重新创建 OpenTelemetryCollector 资源 指南操作后,v2 OpenTelemetry Collector 会部署在相同的命名空间(cpaas-system)中,使用相同的 Service 名称(otel-collector)和相同的端口(4317/4318)。导出到 otel-collector.cpaas-system:4317 的工作负载无需任何更改即可继续工作。

新版 Jaeger UI 是否会显示切换前的 trace?

会,在完成将旧版索引附加到新的读取别名后即可显示。旧版索引会添加到新版索引系列的读取别名中,因此在旧版索引达到其保留期限之前,新版 Jaeger UI 会同时提供切换前和切换后的 trace。不会复制或重新建立索引,旧版索引仍保持只读。

如果跳过此步骤,行为将与 2.1 之前的版本相同:切换前的 trace 只能通过旧版 Jaeger UI 访问,并且在移除旧版堆栈后会丢失。

是否需要对旧版数据重新建立索引,或将其转换为 Jaeger v2 格式?

不需要。Jaeger 1.60.0 和 Jaeger 2.20.0 写入相同的 Elasticsearch 文档模型,因此 Jaeger v2 可以直接读取旧版文档。索引模板有所不同——旧版模板声明 tags.tagType,而 v2 模板声明 tags.type,并且 v2 增加了 scopeTagsreferences.traceState——但 Jaeger 会通过 tags.keytags.value 解析标签搜索,而这两个模板对这两个字段的索引方式完全相同。可以将旧版数据重新建立索引到 v2 映射中,但不会带来任何功能上的收益。

可以同时写入两个 Jaeger 后端吗?

不可以。将旧版索引附加到读取别名后,导出到两个后端的 span 会分别由旧版 Jaeger 写入旧版索引系列,并由新版 Jaeger 写入新版索引系列。单个读取别名会解析到这两个索引系列,而 Jaeger 不会对 span 去重,因此新版 Jaeger UI 会将每个 span 渲染两次。在 Collector trace pipeline 中始终只保留一个 Jaeger exporter。回滚时,应将这一个 exporter 切换回旧版 Jaeger,而不是添加第二个 exporter;请参阅回滚

旧版 Jaeger 和新版 Jaeger 可以共享同一个 Elasticsearch 索引吗?

不可以——它们共享的是读取别名,而不是索引。旧版 Jaeger 写入按日期标记的每日索引(acp-tracing-<cluster>-jaeger-span-YYYY-MM-DD),而 Jaeger v2 通过滚动别名写入(由 *-000001*-000002 等支持的 acp-<cluster>-jaeger-span-write)。它们的生命周期分别管理,并且实际写入的始终只有新版的编号索引。请保留部署新版 Jaeger v2 实例中显示的默认前缀,以确保两个索引系列不会发生冲突。

迁移期间需要额外多少 Elasticsearch 存储空间?

新版索引系列会从零开始增长,而旧版索引系列会在旧版保留期限内逐渐过期;请按一整套额外保留期限所需的 trace 存储量规划稳定状态下的缓冲空间。将旧版索引附加到读取别名完全不会增加存储空间——它只会改变查询解析到的索引。

可以在迁移过程中启用 Service Performance Monitoring (SPM) 吗?

SPM 是可选功能,在验证迁移之后的任何时间都可以启用。按照(可选)启用 Service Performance Monitoring (SPM)中的说明,在新版 Jaeger 中添加 span_metrics connector 并配置 metrics 后端。