从 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 v2 的 Alauda Distributed Tracing。

迁移分为两个阶段:

  1. OpenTelemetry 堆栈迁移。 将旧版 Alauda Build of OpenTelemetry Operator 和 Collector 替换为 Alauda Build of OpenTelemetry v2。重新部署应用 pod,以注入 v2 Java agent。完成此阶段后,telemetry 由 v2 Collector 收集,但仍写入旧版 Jaeger 后端。此阶段按照 Migrating from Alauda Build of OpenTelemetry to Alauda Build of OpenTelemetry v2 中的步骤执行。

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

旧版 trace 数据不会被复制或重新建立索引。其索引会关联到新 Jaeger 的读取别名,因此切换后,新的 Jaeger UI 会同时提供切换前和切换后的 trace,且只要确认新管道运行可靠,就可以移除旧版堆栈,无需等待完整的保留周期。

概述

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.Jaeger)Alauda Build of OpenTelemetry v2 Operator(Jaeger v2 部署为 opentelemetry.io/v1beta1.OpenTelemetryCollector)
默认 Elasticsearch 索引前缀acp-tracing-<cluster>(按日期标记的每日索引)acp-<cluster>(滚动写入/读取别名)
Elasticsearch 保留策略jaeger-es-index-cleaner CronJob 会删除早于 numberOfDays 的每日索引(默认值为 7)Index Lifecycle Management (ILM) 策略 jaeger-ilm-policy 会自动滚动和删除索引(默认在 7d 后删除)
Tracing UI 入口由 acp-tracing-ui 功能开关控制的平台定制 Observability → Tracing 视图通过带有 OAuth2 Proxy sidecar 的 Ingress 暴露的原生 Jaeger UI

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

NOTE

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

迁移中断窗口

Trace ingestion 会在以下两个时点中断:

  1. 在 OpenTelemetry v1 → v2 迁移期间,从删除旧版 OpenTelemetryCollector 到 v2 OpenTelemetryCollector 就绪之间。请参阅 OpenTelemetry v2 迁移指南中的 Migration outage window。

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

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

在整个迁移期间,旧版 Jaeger 的查询路径仍然可用,因此在新管道启动期间,仍可在旧版 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 迁移期间按照 Recreate the OpenTelemetryCollector resources 中的指导操作时,v2 OpenTelemetry Collector 会部署在与旧版 Collector 相同的命名空间中,并使用相同的 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 增加了 scopeTags 和 references.traceState — 不会影响 Jaeger 查询所使用的任何字段。

由于从关联别名的那一刻起,新的 Jaeger UI 就已完整可用,用户无需了解不同时间范围由哪个 UI 提供,旧版堆栈也不再需要仅仅为了响应历史查询而持续运行完整的保留周期。

前置条件

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

迁移前任务

将 Alauda Build of OpenTelemetry 迁移到 v2

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

  • 备份并卸载旧版 Alauda Build of OpenTelemetry Operator 及其 OpenTelemetryCollector 和 Instrumentation 资源。
  • 安装 v2 Operator。
  • 准备用于 Java 自动插桩的镜像,并重新创建 OpenTelemetryCollector 和 Instrumentation 资源,包括设置现在必需的 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,而没有任何应用会与其通信。

到达变量设置步骤时,保留默认索引前缀和基础路径。两者都必须与旧版实例使用的值不同:

export JAEGER_NS="jaeger-system"
export JAEGER_INSTANCE_NAME="jaeger"
export JAEGER_ES_INDEX_PREFIX="acp-${CLUSTER_NAME}"      # must differ from the legacy "acp-tracing-${CLUSTER_NAME}"
export JAEGER_BASEPATH="/clusters/${CLUSTER_NAME}/jaeger"  # must differ from the legacy "/clusters/${CLUSTER_NAME}/acp/jaeger"
共享索引前缀会破坏旧版索引系列的清理

接管旧版索引的保留期限和禁用旧版功能开关并弃用旧版索引系列会根据 ${LEGACY_ES_INDEX_PREFIX}-jaeger-* 选择索引。如果新系列共享该前缀,则匹配模式也会匹配其编号索引:删除专用策略会应用于这些索引,弃用步骤会将它们与读写别名一起删除。此外,新系列的 rollover 初始化还会覆盖旧版索引模板,因为此时两个系列使用相同的模板名称。

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

  • 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 通过读别名解析所有读取请求,因此只需将旧版日期索引添加到该别名,即可在新的 Jaeger UI 中查询迁移前的 trace。不会复制、重命名或重新索引任何内容,旧版 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,而不会匹配新系列的编号 rollover 索引。在未启用依赖分析和自适应采样的情况下运行的旧版 Jaeger 不会有 dependencies 和 sampling 索引,因此这两次迭代会返回 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 OpenTelemetryCollector 仍位于 cpaas-system 中,并继续向旧版 Jaeger 写入 trace,因为其 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. 从 v1 备份继承的旧版 Jaeger exporter 名为 otlp,目标是 cpaas-system 中旧版 Jaeger Collector 的 headless Service。balancer_name: round_robin 会在 headless Service 的端点之间分发 span。otlp 是 otlp_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(debug、otlp_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 会显示为十个。请参阅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),并且 MANAGEMENT 为 managed。如果 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 的新索引(rollover、持续增长)。

  4. 抽查一个真实业务请求,确认其在新的 Jaeger UI 中生成 trace。选择一个或两个已完成 instrumentation 的应用,触发一个具有代表性的请求,然后在新的 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。已经附加的旧版索引不受影响,但后续 rollover 索引将不再添加到读别名,并且 ILM 将无法继续执行 rollover。在 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 将被停用。

确认新 pipeline 运行可靠后,继续执行清理。

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 只能对 rollover 别名的写入索引执行 rollover。将其应用于带日期标记的旧版索引时,会失败并显示 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 控制台中,打开 Feature Switch,并禁用 acp-tracing-ui。卸载旧版 Alauda Build of OpenTelemetry v1 Operator 后,平台定制的 Observability → 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 迁移指南中的 Rollback。对于本文档中执行的 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 迁移指南中的 Rollback 执行回滚,并再次发布应用 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 迁移指南中 Recreate the OpenTelemetryCollector resources 的指导操作后,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 添加了 scopeTags 和 references.traceState——但 Jaeger 会通过 tags.key 和 tags.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 通过 rollover 别名写入(由 *-000001、*-000002 等提供支持的 acp-<cluster>-jaeger-span-write)。它们的生命周期分别管理,并且只有新的编号索引会被写入。请保留部署新版 Jaeger v2 实例中显示的默认前缀,以避免两个索引系列发生冲突。

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

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

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

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