Skip to content
Jaeger 部署与 Kubernetes

Jaeger 部署与 Kubernetes

v1 时代的部署文档先讲"装四个组件",v2 只需要回答一个问题:这一个 jaeger 二进制,进程要扮演几个角色、怎么切。本章按数据规模给出一条完整的谱系——all-in-one → collector 直写存储 → 读写分离 → Kafka 削峰 → ingest 前端 + 远端管理存储——每种形态给官方出处与可跑的配置骨架,然后落到裸机、Docker、Kubernetes 三种交付方式。组件与配置的底层机制(角色由 --config 决定、无热加载)见 02-v2架构与组件.md,存储参数细节见 04-存储后端.md。

本章基线 Jaeger v2.22.0;所有配置片段逐字取自 GitHub tag v2.22.0(路径为 cmd/jaeger/ 下文件)与 docs.jaegertracing.io/docs/2.22/,个别"本手册惯例"会显式标注。

部署模式谱系

模式一:all-in-one(开发/演示,及小规模生产的 badger 变体)

最简单形态:什么都不传。

docker run --rm --name jaeger \
  -p 16686:16686 -p 4317:4317 -p 4318:4318 \
  -p 5778:5778 -p 9411:9411 \
  cr.jaegertracing.io/jaegertracing/jaeger:2.22.0

getting-started 页的官方一行式(端口一致)。不带 --config 时二进制用内嵌 all-in-one 配置,日志里明说:“No ‘–config’ flags detected, using default All-in-One configuration with memory storage."。UI 在 http://localhost:16686。

官方边界(docs/2.22/architecture 原文直译):all-in-one + 内存存储"最适合开发和测试,不建议用于生产,因为数据在重启时丢失”。内嵌配置里 jaeger_storage 只注册了 some_storage: memory: max_traces: 100000——容量、TTL 全是玩具值。

要持久化但不想上集群,可以换成 badger 后端(all-in-one 变体)。官方 storage/badger 页对边界的表述相当克制,值得原文背下来:

Badger 是"仅适合单节点部署"的嵌入式 KV:官方原话——“It is only suitable for a single-node deployment, so it cannot scale horizontally for higher data volumes.” 且 “If Badger backend is enabled in jaeger-collector, it cannot be accessed from jaeger-query, and vice versa. Therefore, Badger can only used either in the all-in-one configuration or with the remote storage component.”

也就是说:badger 数据文件是进程内嵌的,写它的 collector 和读它的 query 不能是两个进程——除非走模式五的 remote-storage 共享。生产规模上限,architecture 页给的口径是"can be used in production, but only for modest data volumes"。仓库 cmd/jaeger/config-badger.yaml 的骨架(节选,注意 keys/values 目录分离与 spans TTL):

extensions:
  jaeger_storage:
    backends:
      some_store:
        badger:
          directories:
            keys: "/tmp/jaeger/"
            values: "/tmp/jaeger/"
          ephemeral: false
          ttl:
            spans: 48h # 2 days
processors:
  batch:
exporters:
  jaeger_storage_exporter:
    trace_storage: some_store

生产用记得换 PVC 挂上 directories(容器内 /tmp 默认是 VOLUME,见下文 Helm 一节),并查官方 badger 页末尾"非 root 服务运行时的文件权限"排障条目。

模式二:collector 直写存储

collector 收 span 直接落 ES/Cassandra/ClickHouse,可多副本水平扩。architecture 页对这个形态的告诫很朴素:“The storage must be able to handle both average and peak traffic”——collector 内存队列只能抹平短时尖峰,持续高峰而存储跟不上就会丢数据,那时再考虑模式四的 Kafka。

cmd/jaeger/config-elasticsearch.yaml(节选,&elasticsearch_config 锚点被 metrics 后端复用,归档库独立前缀):

service:
  extensions: [jaeger_storage, jaeger_query, healthcheckv2]
  pipelines:
    traces:
      receivers: [otlp]
      processors: [batch]
      exporters: [jaeger_storage_exporter]
extensions:
  jaeger_storage:
    backends:
      some_storage: &elasticsearch_config
        elasticsearch:
          server_urls:
            - http://localhost:9200
          indices:
            index_prefix: "jaeger-main"
            spans:
              date_layout: "2006-01-02"   # 照官方 config-elasticsearch.yaml 原样(legacy 周期字段,v2.22 仍接受)
              rollover_frequency: "day"    # v2.22 推荐 rotation.periodic 新语法,见 04-存储后端.md
              shards: 5
              replicas: 1
      another_storage:
        elasticsearch:
          server_urls:
            - http://localhost:9200
          indices:
            index_prefix: "jaeger-archive"
    # Optional, enable metrics backend to use Monitor tab
    metric_backends:
      some_storage: *elasticsearch_config
exporters:
  jaeger_storage_exporter:
    trace_storage: some_storage

ES 的连接、认证、索引生命周期(rollover/data-stream 两种变体文件 config-elasticsearch-auto-rollover.yaml、config-elasticsearch-data-stream.yaml 都在 cmd/jaeger/)见 04-存储后端.md;这里只想让读者看到:直写形态与 all-in-one 的差别只是 backend 换了类型,管道结构一字未动。

模式三:collector 与 query 分离

读写流量拆开:写侧 deployment 只跑 receivers+exporter(把上面配置里的 jaeger_query extension 删掉即可);读侧跑 query-only——service.extensions: [jaeger_storage, jaeger_query, healthcheckv2],管道用 nop 占位。configuration 页原文:“config-query.yaml is an example of running Jaeger in a standalone query role (with UI).”

分离的收益(architecture 页直译):读写独立伸缩、可施加不同的访问与安全策略——UI 只在内网/办公网暴露,写入口对全集群开放。两个进程都必须指向同一份物理存储(同一个 ES 集群、同一个 keyspace),否则 UI 看不到数据。

cmd/jaeger/config-query.yaml(节选;该示例的后端是 grpc 远端存储,换成 elasticsearch: 段就是一个纯读 ES 的 query 服务):

service:
  extensions: [jaeger_storage, jaeger_query, healthcheckv2]
  pipelines:
    traces:
      receivers: [nop]
      processors: [batch]
      exporters: [nop]
extensions:
  jaeger_query:
    storage:
      traces: query_storage
    ui:
      config_file: ./cmd/jaeger/config-ui.json
  jaeger_storage:
    backends:
      query_storage:
        grpc:
          endpoint: localhost:17271
          tls:
            insecure: true

nop receiver/exporter 让 query 进程不占任何写端口——官方组件表里专门给它写了用途:“Used for Jaeger UI / query service deployment that does not require an ingestion pipeline.”

模式四:collector → Kafka → ingester(削峰防丢)

architecture 页:“To prevent data loss between collectors and storage, Kafka can be used as an intermediary, persistent queue.” 写侧 collector 不再直连存储,exporter 换成 kafka;新增 ingester 角色进程从 Kafka 消费落库。官方一句话讲清 ingester 的本质:“In practice, an ingester is very similar to a collector, only configured with a Kafka receiver instead of RPC-based receivers.”

cmd/jaeger/config-kafka-collector.yaml(节选):

service:
  extensions: [healthcheckv2]
  pipelines:
    traces:
      receivers: [otlp, jaeger]
      processors: [batch]
      exporters: [kafka]
exporters:
  kafka:
    brokers:
      - ${env:KAFKA_BROKER:-localhost:9092}
    traces:
      topic: ${env:KAFKA_TOPIC:-jaeger-spans}
      encoding: ${env:KAFKA_ENCODING:-otlp_proto}

cmd/jaeger/config-kafka-ingester.yaml(节选;注意它与 collector 同机跑时要错开端口,官方注释原文就写了 “use different port to avoid conflict with collector”):

service:
  extensions: [jaeger_storage, jaeger_query, healthcheckv2]
  pipelines:
    traces:
      receivers: [kafka]
      processors: [batch]
      exporters: [jaeger_storage_exporter]
  telemetry:
    metrics:
      readers:
        - pull:
            exporter:
              prometheus:
                host: 0.0.0.0
                port: 8889
extensions:
  healthcheckv2:
    use_v2: true
    http:
      endpoint: 0.0.0.0:14133
receivers:
  kafka:
    brokers:
      - localhost:9092
    traces:
      topics:
        - ${env:KAFKA_TOPIC:-jaeger-spans}
      encoding: ${env:KAFKA_ENCODING:-otlp_proto}
    initial_offset: earliest
exporters:
  jaeger_storage_exporter:
    trace_storage: some_storage

关键机制(performance-tuning 页):span 以 trace ID 作为分区键(“The trace IDs are used as sharding keys for Kafka partitions”),同一 trace 落同一分区;ingester 自动协商重平衡分区,“run more jaeger-ingesters than there are partitions in the Kafka topic” 是纯浪费——副本数上限就是分区数。topic 分区数、消费组、死信(config-kafka-ingester-dead-letter.yaml)等队列侧细节见 04-存储后端.md 与 09-性能与运维.md。

模式五:ingest 前端 + 远端管理存储(remote storage)

解决一个很具体的痛点:memory/badger 这类单节点后端,怎么让 collector 和 query 两个进程共用? 或者——多个 collector 副本,怎么共享一个还没到上 ES 规模的存储?

答案是 grpc 后端类型(官方称 remote storage):存储只挂在一个"后端"进程里,其他所有进程通过 gRPC Remote Storage API(apis 页:实现 TraceReader/DependencyReader/TraceService 三个服务,Status: Stable)读写它。官方仓库给了整套三件套范例:

后端进程(config-remote-storage-backend.yaml,节选)——remote_storage extension 把注册表里的后端通过 gRPC 端点对外共享,管道自己还兼收 OTLP:

service:
  extensions: [jaeger_storage, remote_storage, healthcheckv2]
  pipelines:
    traces:
      receivers: [otlp]
      processors: [batch]
      exporters: [jaeger_storage_exporter]
extensions:
  healthcheckv2:
    use_v2: true
    http:
      # use different port to avoid conflict with collector on 13133
      endpoint: 0.0.0.0:12133
  jaeger_storage:
    backends:
      memory-storage:
        memory:
          max_traces: 100000
  remote_storage:
    endpoint: localhost:17271
    storage: memory-storage

前端 collector 进程(config-remote-storage.yaml 节选)——jaeger_storage.backends 注册一个 grpc 类型的后端:读走主 endpoint(17271),写可用 writer 子段单独指定目标;源码 internal/storage/v2/grpc/config.go 注释原文:“Writer allows overriding the endpoint for writes, e.g. to an OTLP receiver. If not defined the main endpoint is used for reads and writes.”

  jaeger_storage:
    backends:
      some-storage:
        grpc:
          endpoint: "${env:REMOTE_STORAGE_ENDPOINT:-localhost:17271}"
          tls:
            insecure: true
          writer:
            endpoint: ${env:REMOTE_STORAGE_WRITER_ENDPOINT:-0.0.0.0:4316}
            tls:
              insecure: true

(示例文件的默认值是为单机演示凑的,4316 这个写端点与后端 OTLP 监听 4317 并未对齐——生产两套进程分开部署时,按自己的端口规划显式设环境变量。)

前端 query 进程就是模式三的 config-query.yaml:管道 nop,jaeger_storage 里同样注册 grpc: endpoint: localhost:17271。三个进程拼起来:

SDK ─▶ 前端 collector(收 OTLP)─ gRPC 写 ─▶ 后端(remote_storage: 内存/badger + 兼收 OTLP)
UI  ─▶ 前端 query(16686)      ─ gRPC 读 ─▶ 同一个后端(17271)

还有一个免写管道的捷径:独立的 jaeger-remote-storage 工具(源码 cmd/remote-storage,独立镜像 cr.jaegertracing.io/jaegertracing/jaeger-remote-storage:2.22.0,download 页有 v2 条目)。它不走 OTel 五段式配置,用自己的扁平 YAML(README 实测):--config-file 是唯一业务 flag;默认 gRPC 服务端口 17271、admin 端口 17270(admin 上挂健康检查、/metrics、/debug/pprof);storage.backends 里声明 memory/badger;支持多租户 multi_tenancy。它的 README 一句话定位:“allows sharing single-node storage implementations like memory or Badger over gRPC”。

什么时候值得上这套?badger 页说的就是它:badger 不能 collector/query 双进程直连,官方给的出路正是 “or with the remote storage component”。小规模团队没有 ES 运维预算、又想要读写分离时,这是最省事的形态。

谱系速查

模式 进程构成 有状态点 适用
all-in-one 1 无(memory)/数据目录(badger) 开发、演示、CI
all-in-one + badger 1 数据目录 单机小量生产
collector 直写 N 外部存储 标准生产
读写分离 collector×N + query×M 外部存储 独立伸缩、安全隔离
+ Kafka 削峰 collector×N + ingester×M Kafka + 存储 尖峰频繁、防丢
前端 + remote storage 前端×N + 后端×1 后端进程数据 单节点后端多进程共享

裸机与 Docker

tar.gz 二进制与 tools 包

GitHub release(tag v2.22.0,发布于 2026-10-06)资产命名规则实测:jaeger-2.22.0-<os>-<arch>.tar.gz(linux amd64/arm64/ppc64le/s390x、darwin amd64/arm64、windows amd64 另有 .zip),每个都配 .sha256sum.txt 与 .asc 签名;工具单独打包成 jaeger-tools-2.22.0-<os>-<arch>.tar.gz(含 es-index-cleaner、es-rollover、anonymizer、tracegen、remote-storage、esmapping-generator 等独立小二进制,见 02-v2架构与组件.md)。另有 jaeger-SBOM.spdx.json 供应链清单。

Linux 裸机惯例装法(本手册惯例,官方无 systemd 专页):解包到 /usr/local/bin,配置放 /etc/jaeger/config.yaml,单元文件:

[Unit]
Description=Jaeger v2 (collector role)
After=network-online.target

[Service]
ExecStart=/usr/local/bin/jaeger --config /etc/jaeger/config.yaml
Environment=JAEGER_LISTEN_HOST=0.0.0.0
Restart=on-failure
User=jaeger

[Install]
WantedBy=multi-user.target

要点仍是配置系统那一套:Environment= 只能喂 ${env:} 插值,不能替代配置文件;改配置后 systemctl restart,别试 SIGHUP(见 02-v2架构与组件.md)。

Windows 有官方专页(docs/2.22/deployment/windows,用 NSSM 把 Jaeger 注册为服务):

nssm install Jaeger C:\Jaeger\jaeger.exe --config=C:\Jaeger\config.yaml
nssm set Jaeger AppStdout C:\Jaeger\jaeger.out.log
nssm set Jaeger AppStderr C:\Jaeger\jaeger.err.log
nssm start Jaeger

官方页同时提醒:Windows 上最省事的是 all-in-one——不带配置文件直接跑,默认内存存储;要连可靠存储就得写 YAML。

单镜像切角色与 Docker Compose

一个镜像 cr.jaegertracing.io/jaegertracing/jaeger:2.22.0 扮演所有角色,差别只在挂载与命令行(getting-started 页原文示例):

docker run --rm --name jaeger \
  -p 16686:16686 -p 4317:4317 -p 4318:4318 -p 5778:5778 -p 9411:9411 \
  -v /path/to/local/config.yaml:/jaeger/config.yaml \
  cr.jaegertracing.io/jaegertracing/jaeger:2.22.0 \
  --config /jaeger/config.yaml

镜像自带 ENV JAEGER_LISTEN_HOST=0.0.0.0(内嵌配置里的插值据此监听所有网卡),EXPOSE 覆盖 5778/5779/4317/4318/14268/14250/9411/16686/13132/13133;容器以 UID 10001 非 root 运行。带 -debug 后缀的镜像把进程跑在 Delve headless 模式(端口 12345,--continue 不暂停),远程调试用。

本地最常见的双服务 compose(本手册惯例;官方 HotROD 例子在仓库 examples/hotrod/docker-compose.yml):

services:
  jaeger:
    image: cr.jaegertracing.io/jaegertracing/jaeger:2.22.0
    ports:
      - "4317:4317"
      - "4318:4318"
      - "16686:16686"
    volumes:
      - jaeger-data:/badger

  app:
    build: .
    environment:
      - OTEL_EXPORTER_OTLP_ENDPOINT=http://jaeger:4318
    depends_on:
      - jaeger

volumes:
  jaeger-data:

注意上例埋着的坑——只给官方 all-in-one 挂 volume 并不会得到持久化:内嵌配置用的是 memory,而 v1 时代那套 BADGER_*/COLLECTOR_* 环境变量 v2 一概不认(见 02-v2架构与组件.md 配置一节;唯一被容器照顾的环境变量是 Dockerfile 里预设的 JAEGER_LISTEN_HOST)。要在 compose 里换 badger,正确做法是自备 config.yaml(backend 改 badger:、directories 指到 /badger)再挂载 --config 启动。

Kubernetes

官方两条路径,和一条已退役的老路

docs/2.22/deployment/kubernetes 页正文只有两行(原文照录):

  • Kubernetes Operator — “The OpenTelemetry Operator can be used to manage Jaeger v2.”
  • Helm Chart — “The Helm Chart for Jaeger v2 is available from the helm-charts main branch.”

值得留意的是被官方"除名"的那条路:jaegertracing/jaeger-operator 仓库已归档(archived,API 实测),README 顶部原话(转述):该 Operator 只对已退役的 Jaeger v1 有效;Jaeger v2 请使用 OpenTelemetry Collector Operator。配套的 Helm jaeger-operator chart(2.57.0)同样停更。看到任何教你 Jaeger CR 的教程,先检查它服务的是哪个大版本。

Helm chart 实测:默认装出来的是什么

chart 仓库名是 jaegertracing/helm-charts(索引 https://jaegertracing.github.io/helm-charts/index.yaml;搜"jaeger-helm-charts"会扑空)。jaeger chart 最新 4.16.1,appVersion 2.22.0;Chart.yaml 声明 kubeVersion: ">= 1.21-0"(注释:CronJobs 需要 v1.21)、依赖 bitnami common 2.x.x、镜像 jaegertracing/jaeger:2.22.0(tag 留空即跟 appVersion)。

helm repo add jaegertracing https://jaegertracing.github.io/helm-charts
helm repo update
helm install jaeger jaegertracing/jaeger --version 4.16.1

装完检查(kubectl get deploy,svc)会看到一个名为 -jaeger 的单 Deployment:pod 标签 app.kubernetes.io/component: all-in-one、strategy: Recreate、replicas: 1(模板实测)。更关键的是容器 args:模板里 --config /etc/jaeger/user-config.yaml 只在 .Values.userconfig 非空时才渲染——不传 userconfig,容器就是裸 jaeger 进程,落到二进制内嵌的 all-in-one + 内存存储。kubectl port-forward 16686(NOTES.txt 给的正是这条命令)能看到 UI,但重启即清零。

反直觉点:storage.* 值不会配置 Jaeger 本身

注意:想连 Elasticsearch?必须自己写 userconfig。 chart 的 storage.type: elasticsearch(默认 url: http://elasticsearch-master:9200)和 storage.cassandra.* 不会让 Jaeger 进程连上 ES——values.yaml 官方注释原文:“In Jaeger v2, Elasticsearch is configured directly in config.extensions.jaeger_storage (see the ‘config’ section at the top of this file). The settings below are only used by the ES maintenance jobs (esIndexCleaner, esRollover, esLookback) via the elasticsearch.env helper."(注释里的 ‘config’ section 指的就是文件顶部示例化的 userconfig)。也就是说这些值只注入 ES 维护 CronJob 的环境变量(ES_SERVER_URLS/ES_USERNAME/ES_PASSWORD 等),jaeger 容器的 env 只来自 jaeger.extraEnv。这是 v1 chart 经验迁移过来最大的一个坑:v1 里 storage.* 真的会生成 collector 启动参数,v2 里它管的是"杂务”,配置主体在 userconfig。

正确姿势——把仓库的 config-elasticsearch.yaml 改成自己的存储地址后:

helm install jaeger jaegertracing/jaeger --version 4.16.1 \
  --set-file userconfig=my-config.yaml

userconfig 渲染成名为 user-config 的 ConfigMap 并挂载到 /etc/jaeger/user-config.yaml;pod 模板带 checksum/user-config 注解,configmap 内容变化会触发滚动更新(注意 strategy: Recreate 是先杀后起,单副本必然有短暂不可用;多副本 all-in-one 没有意义,该换角色拆分了)。UI 配置同理走 uiconfig(渲染为 ui-config.json,挂到 /etc/jaeger/ui-config.json,见 07-查询UI与API.md)。

chart 注释里的 userconfig 示例也提醒了采样文件:要启用 file 型 remote_sampling,策略 JSON 得自己用 extraVolumes/ConfigMap 挂进去(见 06-采样.md)。

Service 暴露的端口与残留

jaeger.<name> Service(ClusterIP,可 service.type 改)端口清单(模板实测):

端口 协议 用途 备注
4317/4318 TCP OTLP gRPC/HTTP 主入口
14250/14268 TCP Legacy Protobuf gRPC / Thrift HTTP Deprecated 状态,见 02-v2架构与组件.md
6831/6832 UDP Legacy Thrift compact/binary
5775 UDP (v1 agent 端口) 模板残留:v2 默认不监听 5775,Dockerfile EXPOSE 亦无
14267 TCP (v1 agent 配置通道) 同为模板残留,容器 ports 里没有对应 containerPort
5778 TCP 采样 HTTP
16686/16685 TCP UI+JSON API / gRPC QueryService oAuthSidecar 开启时 16686 的 targetPort 切到 4180
8888/8889 TCP collector 指标 / spanmetrics pod 注解 prometheus.io/scrape: "true", prometheus.io/port: "8888"

Service 暴露 ≠ 进程在听:默认 all-in-one 角色只监听内嵌配置那组端口,14250/14268 等要你的 userconfig 启用了 jaeger receiver 才有真实流量——别把这张表当防火墙白名单,按实际角色收敛。

探针、安全与定时任务

  • liveness/readiness:httpGet /status :13133(healthcheckv2 的 HTTP 端点);jaeger.<name> 部署默认没配 startupProbe,冷启动接大存储时建议补。
  • 安全上下文:pod runAsUser/runAsGroup/fsGroup: 10001,与镜像 USER 一致;badger/PVC 场景注意目录属主。
  • oAuthSidecar(默认关):jaeger.oAuthSidecar.enabled=true 注入 quay.io/oauth2-proxy/oauth2-proxy:v7.15.5 容器(4180),把 UI 挡在 OIDC 后面;args 示例见 values 注释。
  • 四个 CronJob 全部默认 disabled(ES 运维族,镜像与 jaeger-tools/独立 ES 工具镜像配套):
值路径 镜像 计划(crontab) 语义
esIndexCleaner jaeger-es-index-cleaner 55 23 * * *,numberOfDays: 7 每天 23:55 删除 7 天前的过期索引(ES 无 TTL)
esRollover jaeger-es-rollover 10 0 * * *,CONDITIONS: '{"max_age": "1d"}' 每天 00:10 按条件滚动写别名;另有安装时钩子 es-rollover-hook 初始化别名/mapping
esLookback jaeger-es-rollover 5 0 * * *,UNIT: days,UNIT_COUNT: "7" 预创建未来 7 天的索引,防止新的一天没人写入
spark spark-dependencies 49 23 * * * 从 span 汇总服务依赖图,供 UI Dependencies 视图

选 rollover 还是 cleaner 取决于索引管理策略(auto-rollover 模式下不能用 cleaner 删按天索引),与存储侧配置的联动见 04-存储后端.md。

chart 的官方自我定位:实验性

helm install 后 NOTES.txt 第一段横幅(原文转述,去 emoji):EXPERIMENTAL - NO STABILITY GUARANTEES,并明说 “Breaking changes may occur in minor versions”。这不是客套:横幅同时写明 “Breaking changes may occur in minor versions”,而 chart 版本(4.x)与 appVersion(2.x)两套号是解耦的,values 结构的演进不受 Jaeger 本体兼容性承诺约束。选型建议:测试集群用 chart 图快没问题;生产集群要么用 OpenTelemetry Operator 管 collector(CRD 语义化升级有保证),要么 helm template 渲染后收进 GitOps 锁版本(chart 版本、appVersion、--version 4.16.1 三处一起 pin),把 chart 的"实验性"风险转移成自己的变更管理。

伸缩与升级

  • HPA:collector 与 query 都是无状态(外部存储时),官方 performance-tuning 页:“jaeger-collector is nearly horizontally scalable”;扩容触发条件它给的也很实在——单实例接不完、滚动重启要有存量实例顶流量、CPU 需要摊开。query 同理按 UI 流量独立扩。ingester 副本数不要超过 Kafka topic 分区数(官方:超出部分只会空转),且它扩缩伴随消费组重平衡,设大一点的 stabilization window。
  • 升级顺序(本手册惯例,官方未成文):query → ingester → collector 逐组件滚动。先升 query 保证读 API 对新数据格式就绪;ingester 在 collector 之前,让消费端先兼容再放新流量;每一步保留旧 values/配置快照以便回退(Recreate 策略意味着回退伴随一次短暂中断)。
  • 改配置 = 滚动重启:没有 SIGHUP,唯一热更的是 remote_sampling 的策略文件——把这条写进变更流程,见 02-v2架构与组件.md 注意块。
  • 资源与限流:request/limit、memory_limiter 与 back-pressure 的调参不在本章展开,见 09-性能与运维.md(官方口径:性能建议大部分直接继承 Scaling the Collector 文档)。

实战建议

部署选型决策树(文字版)

日 span 量?
├─ < 50 万,且允许丢            → 裸 all-in-one(默认内存),不传 --config
├─ < 50 万,要持久化            → all-in-one + badger(单副本,挂 PVC,盯磁盘水位)
│   └─ 还想 UI 与写入分进程     → badger + jaeger-remote-storage 后端(模式五)
├─ 50 万 ~ 千万,尖峰明显       → collector×N 直写 ES/ClickHouse + query×M(模式二/三)
│   └─ 存储偶尔追不上/不能丢    → collector → Kafka → ingester×M(≤分区数)(模式四)
└─ 千万以上 / 多团队共享        → 全套读写分离 + Kafka 缓冲 + ES rollover 定时任务
    └─ 需要前端 SDK 同源上报    → jaeger_query.otlp_proxy;多出口再谈尾采样(06-采样.md)

K8s 交付:
├─ 测试环境:helm 4.16.1 + --set-file userconfig(锁版本)
├─ 生产环境:OTel Operator 管 collector,或渲染后 GitOps 锁 manifests
└─ 任何环境:别装 jaeger-operator(archived,只管 v1)

上线检查清单

  1. 端口连通:SDK→4317/4318 实测能收到 span(先用 tracegen 或 curl OTLP JSON);UI→16686、gRPC→16685、采样→5778/5779 按角色收敛暴露面;确认没有把 Service 表当监听表(残留 5775/14267 无进程在听)。
  2. 健康检查:liveness/readiness 指向 /status:13133 且在 userconfig 里确实启用了 healthcheckv2 extension——自己写的配置最容易漏挂 extension。
  3. 存储:后端类型与 TTL 策略落定(memory 仅限 demo;badger 单节点;ES 配 rollover/cleaner CronJob 或 data-stream),index_prefix 与 metric_backends(SPM)已规划,见 04-存储后端.md。
  4. 采样:策略来源(file 或 adaptive)明确;file 策略是唯一可热更项,变更流程里注明"改 JSON 不用重启,改 YAML 必须重启"。
  5. 迁移预期:v1 的 COLLECTOR_*/QUERY_* env 已全部失效;legacy Thrift 入口仍在但列入下线计划;v2 写入的新索引自 v2 起,查 v1 历史数据官方无兼容承诺——留好 v1 容器多跑一段共存期(迁移指南官方为 Google Doc,本手册以 2.22 文档对照为准)。
  6. 版本与回滚:镜像 tag 锁 2.22.0 不用 latest;chart 版本与 appVersion 配对记录在案;配置变更走 Git,回滚 = 回配置 + 重启,而非 SIGHUP。

更多跨主题的坑(采样下发失败、Kafka 重平衡空转、badger 权限等)汇总见 10-常见陷阱与最佳实践.md。