使用 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_aliases 和 use_ilm。请在单个补丁中更新 Jaeger 实例的镜像和配置(步骤 5),否则新 Pod 会在启动时退出,并显示 invalid configuration: ... deprecated ES rotation flags ... are no longer supported。由于新 Pod 始终无法就绪,之前的 Pod 会继续提供 trace,因此停滞的滚动更新不会中断 trace。

此操作步骤会保留所有 trace 数据。不会重新创建索引、别名或 ILM 策略,现有索引仍可读取。

前提条件

  • 已按照使用 Elasticsearch 安装 Alauda Distributed Tracing中所述安装 Alauda Distributed Tracing v2.0 部署。
  • Alauda Container Platform Distributed Tracing(之前称为 Alauda Build of Jaeger v2)集群插件和 Alauda Container Platform Application Observability(之前称为 Alauda Build of OpenTelemetry v2)Operator 0.157.0 已发布到平台。
  • 集群管理员已建立活动的 ACP CLI(kubectl)会话,并在目标集群和 global 集群中均具有 cluster-admin 角色。
  • 查看升级说明以了解此版本引入的行为变更。

设置环境变量

针对目标集群运行以下命令。Elasticsearch 端点和索引前缀会从正在运行的 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 开始,trace 组件的容器镜像由 Alauda Build of Jaeger v2 集群插件提供,而不再由 Operator bundle 提供。安装该插件会将镜像同步到平台的内置 registry,并在目标集群的 cpaas-system 命名空间中创建 jaeger-cluster-plugin-manifest ConfigMap。后续操作步骤会从该 ConfigMap 中读取镜像地址。

通过 Web 控制台安装

  1. 在平台管理视图中,导航至管理员 > Marketplace > 集群插件。
  2. 选择部署 trace 组件的集群。
  3. 找到 Alauda Container Platform Distributed Tracing(对于重命名之前发布的软件包,该名称显示为 Alauda Build of Jaeger v2),然后单击安装。该插件无需安装参数。

通过 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> 替换为部署 trace 组件的集群名称,并将 <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

    平台会为该资源分配生成的名称,因此请按标签而不是清单中使用的名称查询 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 控制台升级

选择以下方法之一:

  • 批量升级:导航至 平台管理 > 集群管理 > 集群 > 集群 > 功能组件,然后升级 Alauda Container Platform Application Observability(对于重命名前发布的软件包,此项显示为 Alauda Build of OpenTelemetry v2)。
  • 单独升级:导航至 管理员 > Marketplace > OperatorHub,打开 Alauda Container Platform Application Observability(对于重命名前发布的软件包,此项显示为 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 证书。在此期间应用的补丁会因 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 会将其移除,而新键会使用相同的端点重新创建 exporter。
    2. add_metric_suffixes 已弃用并会被静默忽略。translation_strategy: UnderscoreEscapingWithoutSuffixes 可使指标名称不带 Prometheus 风格的后缀。
    3. Prometheus reader 的 without_scope_info、without_type_suffix 和 without_units 设置现在默认使用 true,并会被删除。由于 readers 是一个列表,该补丁会整体替换它。公开的指标名称不会改变。
  2. 使用 envsubst 渲染补丁并应用:

    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"

(可选)为服务性能监控更新 Collector

重命名将 span 路由至 Jaeger 层的 loadbalancing exporter。请紧接着上一个补丁应用此补丁:在两者之间,span 会通过直接 exporter 到达 Jaeger,而不是由 service 路由;如果 Jaeger 层运行多个副本,这会导致 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 渲染补丁并应用:

    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 字段,例如 scopeTags 和 references.traceState。使用新镜像重新运行 jaeger-es-rollover 初始化,以便更新索引模板,并确保未来轮换创建的索引携带新的映射。

该初始化操作具有幂等性:它会覆盖索引模板,并跳过已存在的索引和别名。现有数据不会被修改。

操作步骤

  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 索引模板现在包含新字段:

    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 构建的 Jaeger v2

操作步骤

  1. 更新 OAuth2 Proxy sidecar 镜像。由于 additionalContainers 是一个列表,合并补丁会整体替换该列表,因此使用单独的 JSON 补丁更新此容器。此时 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 的文件,内容如下。镜像和配置必须同时更改,因此两者属于同一个补丁:

    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 会在两侧扩大查询时间范围,因此仍可找到超出搜索窗口的 span。请参阅查询时间范围。
    3. rotation.auto_rollover 会替代 use_aliases 和 use_ilm。其默认别名名称与 jaeger-es-rollover 初始化所创建的别名相匹配,因此无需更改数据、别名或 ILM 策略。请将 auto_rollover.policy_name 保持为空,因为 ILM 策略引用已嵌入索引模板中。请参阅索引管理策略。
    4. Operator 会将 service.telemetry.resource 解析为字符串的扁平映射;如果不是这种格式,则会静默丢弃整个 service.telemetry 部分。Jaeger 已经报告自己的 service.name 和 service.version,因此会移除该代码块,而不是进行迁移。
    5. 对于 otel Collector,without_* 设置现在默认采用 true,并通过替换 readers 列表将其删除。
  3. 使用 envsubst 渲染补丁,应用补丁并等待 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

(可选)为服务性能监控更新 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 渲染补丁,应用补丁并等待 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 分发版本。独立的 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. 生成示例追踪,并确认这些追踪已存储且可查询,具体请参阅安装操作步骤中的验证部分。如果已启用 SPM,还应打开 Jaeger UI 中的 Monitor 选项卡,并确认生成的服务显示了 RED 指标。