OpenTelemetry

OpenTelemetry(简称 OTel)是一个由 CNCF(云原生计算基金会)托管的顶级开源可观测性框架,它为分布式系统提供了一套标准化的 API 和工具,用于统一生成、收集、处理和导出核心的遥测数据(Metrics 指标、Traces 链路追踪、Logs 日志)。它的核心价值在于“厂商中立”——开发者只需在业务中做一次无侵入式的探针注入或 SDK 接入,就能将监控数据自由、无缝地推送到 Prometheus、Jaeger、Elastic 等任何主流后端平台,彻底打破了传统监控工具各自为战、强绑定的数据孤岛。

OpenTelemetry有两个最突出的特点:

  1. 零代码侵入的“自动挡” (Auto-Instrumentation) 对于 Java、Python、Node.js 等语言,OTel 提供了极其强大的自动注入探针

  2. 灵活强大的“数据路由器” (OTel Collector) 它不仅提供探针,还提供了一个数据中转站(Collector)。在数据发往最终的存储后端(Prometheus等)之前,你可以在 Collector 里面对数据进行过滤、脱敏、采样或者格式转换(比如咱们刚才把 K8s 的底层属性完美转换成了 Prometheus 标签)。

架构概述

本方案采用 OpenTelemetry (OTel) 提供的自动注入机制,无需修改业务代码即可实现 JVM 及基础框架指标的采集。

  • 数据链路:Java 探针 (OTel Agent) -> 通过 OTLP/gRPC 协议推送 -> OTel Collector -> 转换为 Prometheus 格式暴露 -> Prometheus 定时拉取。

零、 环境介绍

监控train-ticket微服务,部署在tt命名空间下

本方案介绍OpenTelemetry方案进行指标采集(自动注入java agent无需手动修改微服务项目原本的配置文件

一、 前置准备与基础组件安装

OpenTelemetry Operator 依赖 cert-manager 来生成 Webhook 证书,必须先安装它。

安装 cert-manager

# 安装 cert-manager (建议使用官方最新稳定版)
kubectl apply -f https://github.com/cert-manager/cert-manager/releases/download/v1.13.0/cert-manager.yaml

# 验证所有 Pod 是否运行正常 (大概需要等待 1-2 分钟)
kubectl get pods -n cert-manager

安装 OpenTelemetry Operator

# 安装 OTel Operator
kubectl apply -f https://github.com/open-telemetry/opentelemetry-operator/releases/latest/download/opentelemetry-operator.yaml

# 验证 Operator 是否启动成功
kubectl get pods -n opentelemetry-operator-system


二、 部署 OTel Collector (数据收集与转换网关)

我们需要在微服务所在的命名空间(本文以 tt 为例)部署一个 Collector,用于接收探针发来的数据,并转换为 Prometheus 可识别的格式。

创建 otel-collector.yaml

apiVersion: opentelemetry.io/v1alpha1
kind: OpenTelemetryCollector
metadata:
  name: otel-collector
  namespace: tt
spec:
  config: |
    receivers:
      otlp:
        protocols:
          grpc:
            endpoint: 0.0.0.0:4317 # 接收 Java 探针数据的 gRPC 端口
    exporters:
      prometheus:
        endpoint: 0.0.0.0:8889 # 暴露给 Prometheus 拉取数据的端口
        # 【核心配置】将 K8s 的 Namespace, Pod, Container 等资源属性转换为 Prometheus 的独立标签,解决数据揉成一团的问题
        resource_to_telemetry_conversion:
          enabled: true
    service:
      pipelines:
        metrics:
          receivers: [otlp]
          exporters: [prometheus]

执行部署:

kubectl apply -f otel-collector.yaml

三、 解决探针镜像拉取难题 (针对 Containerd 内网/网络受限环境)

由于官方探针镜像存放在 ghcr.io,国内网络极易拉取失败。即便手动 docker pull,K8s 默认仍会尝试联网校验。我们需要利用 Containerd 的本地镜像机制进行“伪装”。

预拉取并重命名镜像 (所有 Node 节点执行)

将镜像拉取到 K8s 专用的 k8s.io 命名空间,并打上一个带有“伪造本地仓库域名”的标签(例如 dev.local),以彻底绕过 K8s 的公网校验机制。

# 1. 使用国内加速源拉取探针镜像
ctr -n k8s.io image pull ghcr.nju.edu.cn/open-telemetry/opentelemetry-operator/autoinstrumentation-java:latest

# 2. 重新打标签,伪装成私有/本地仓库镜像,并去除 latest 标签 (改用 v1)
ctr -n k8s.io image tag \
  ghcr.nju.edu.cn/open-telemetry/opentelemetry-operator/autoinstrumentation-java:latest \
  dev.local/otel-java-agent:v1

四、 配置 Java 探针注入规则 (Instrumentation)

定义探针的行为:使用什么镜像、往哪里发数据、使用什么协议。

创建 instrumentation.yaml

apiVersion: opentelemetry.io/v1alpha1
kind: Instrumentation
metadata:
  name: java-instrumentation
  namespace: tt
spec:
  exporter:
    # 指向本命名空间内 Collector 的 gRPC 服务地址
    endpoint: http://otel-collector-collector.tt.svc.cluster.local:4317
  sampler:
    type: always_on
  java:
    # 【避坑】指向我们刚才伪装好的本地镜像
    image: dev.local/otel-java-agent:v1
    env:
      # 【避坑】强制指定传输协议为 grpc,避免默认 http 协议导致的 Connection reset 或 404 错误
      - name: OTEL_EXPORTER_OTLP_PROTOCOL
        value: grpc
      # 【避坑】由于我们只配置了 metrics 流水线,禁用 traces 和 logs 导出,避免探针在微服务日志中疯狂打印 404 WARN 报错
      - name: OTEL_TRACES_EXPORTER
        value: none
      - name: OTEL_LOGS_EXPORTER
        value: none

执行部署:

kubectl apply -f instrumentation.yaml

五、 为微服务注入探针并重启生效

OTel Operator 通过监听 Namespace 或 Deployment 上的 Annotations (注解) 来决定是否注入探针。

开启命名空间级别的自动注入

# 告诉 Operator:请在这个命名空间下自动注入 Java 探针,配置依据名为 java-instrumentation
kubectl annotate namespace tt instrumentation.opentelemetry.io/inject-java="java-instrumentation"

重启微服务,触发注入

清理旧 Pod,Kubernetes 会根据注解自动将带有探针 jar 包的 InitContainer 挂载到新 Pod 中。

# 批量重启 tt 命名空间下所有前缀为 ts- 的 Deployment
kubectl rollout restart -n tt $(kubectl get deploy -n tt -o name | grep ts-)

# 观察启动状态,确保新 Pod 进入 1/1 Running 状态
kubectl get pods -n tt


六、 配置 Prometheus 抓取数据

最后,将 Collector 暴露出来的指标对接到 Prometheus。

编辑 Prometheus 的配置文件 (prometheus.yml),新增一个 Job:

scrape_configs:
  - job_name: 'otel-k8s-metrics'
    scrape_interval: 15s
    static_configs:
      # 指向 OTel Collector 的服务地址和 Prometheus Exporter 端口
      - targets: ['otel-collector-collector.tt.svc.cluster.local:8889']

热加载 Prometheus 配置:

curl -X POST http://<prometheus-ip>:9090/-/reload


七、 验收与数据可视化

  1. Prometheus 验证: 在 Prometheus Web UI 中搜索 jvm_memory_used_bytes,如果能查出数据,且数据带有 k8s_namespace_namek8s_pod_namek8s_container_name 等详细标签,说明全链路打通。

八、深入研究-什么是webhook

要理解 Webhook 这个词,我们可以把它拆成两半来看:WebHook

什么是 Hook(钩子)?

在计算机编程的历史里,“Hook(钩子)”是一个非常古老且核心的概念。 想象一条流水线,数据在管道里从 A 流向 B。如果你想在这条流水线中间“截胡”或者“偷窥”一下,你就在中间挂一个“钩子”。当数据经过时,触发你挂在钩子上的自定义代码。

  • 比如:Windows 键盘钩子(记录你敲了什么键)、Vue/React 里的生命周期钩子(mountedcreated,在组件加载到某个阶段时触发)。

什么是 Web?

Web 就是指 HTTP 网络请求

合体:Webhook(网络钩子)

把这两个概念合起来,Webhook 的本质就是:通过 HTTP 请求实现的回调机制(HTTP Callback)。

Kubernetes 里的 Webhook 是怎么工作的?

当你自己开发 Operator 并实现 replicas <= 10 这个功能时,你其实是在 K8s 的 API Server 内部署了一个“HTTP 钩子”。流程是这样的:

  1. 用户发起请求: 某人执行了 kubectl scale deploy my-app --replicas=15

  2. API Server 走到钩子点: API Server 收到请求,但在真正写入数据库(etcd)之前,它走到了一个叫做“准入控制(Admission Control)”的关卡。

  3. 触发 Webhook(发起 HTTP 请求): API Server 发现你注册了一个 Webhook 规则。于是,API Server 变成了一个客户端,向你写的 Operator 代码发送了一个 HTTP POST 请求,把那个要把 replicas 改成 15 的 JSON 数据发给了你。

  4. 你的代码做“裁判”: 你的 Operator 收到这个 HTTP 请求,解析出 replicas: 15,发现大于 10。

  5. 返回结果: 你的 Operator 给 API Server 返回一个 HTTP 响应:{"allowed": false, "message": "Replicas cannot exceed 10!"}

  6. API Server 拦截: API Server 收到你的拒绝响应,立刻中止操作,并把你的 message 报错打印在用户的终端上。

Webhook 家族的两大门派(对比 OTel)

在 K8s 的准入控制里,Webhook 明确分为两大门派。这正好把咱们今天聊的 OTel 和你之前的开发经验串起来了:

  • 门派一:Validating Webhook(验证型 - 你之前写的)

    • 特点: 只看不改,扮演**“安检员”或“裁判”**。

    • 作用: 检查配置合不合法。比如你写的“副本数不能大于 10”,或者“镜像必须来自私有仓库”、“必须要有资源限制(requests/limits)”。它只能回答 Yes 或 No。

  • 门派二:Mutating Webhook(变更型 - OTel Operator 用的)

    • 特点: 先看后改,扮演**“整容医生”或“魔术师”**。

    • 作用: 在资源存入数据库前,悄悄修改它的内容。比如咱们刚搞定的 OTel Operator,它发现你的 Pod 有特殊的 Annotation,就毫不客气地在你的 YAML 里塞进去了 InitContainer 和一堆环境变量,然后再还给 API Server。

九、 深入研究-如何实现自动注入

这个“自动注入”的过程看起来像魔法一样(无需改业务代码,探针就自动跑起来了),但其实它的底层原理是 Kubernetes 中一个非常经典且强大的机制:Mutating Admission Webhook(变更准入控制 Webhook)

为了让你在技术文档里或者跟团队分享时能讲得透彻,我把 OTel Operator 的“拦截-注入”全流程拆解为 核心原理分步流程 两个部分。


核心原理:Kubernetes 的准入控制 (Admission Control)

当你在 K8s 里执行 kubectl apply 创建一个 Pod 时,请求并不是直接丢给 Node 节点去运行的,而是要经过 API Server 的重重关卡。

其中有一关叫做 Mutating Admission(变更准入)。 OTel Operator 在安装的时候(其实是 cert-manager 帮它签发证书的时候),向 K8s API Server 注册了一个自己的“哨卡”(Webhook)。

它告诉 K8s:“兄弟,以后集群里但凡有人要创建或更新 Pod,你在存入 etcd 数据库之前,先把 Pod 的配置草稿发给我看一眼,我可能要改点东西。


OTel Operator 拦截与注入的完整流程

让我们以你刚才部署的 ts-travel-service 为例,看看 Operator 是怎么“偷梁换柱”的:

第一步:触发创建 (Trigger)

K8s 的 Deployment 控制器决定要创建一个 ts-travel-service 的 Pod,于是向 API Server 发送了创建 Pod 的请求。

第二步:拦截请求 (Intercept)

API Server 收到请求后,由于配置了 Mutating Webhook,它暂停了创建过程,把这个原始的 Pod YAML(JSON 格式)发送给了 OTel Operator 的 Webhook 服务。

第三步:规则匹配 (Evaluate)

OTel Operator 收到这个 Pod 的配置后,开始检查:

  1. 看命名空间: 这个 Pod 所在的命名空间 tt 或者 Pod 自身,有没有打上 instrumentation.opentelemetry.io/inject-java 这个 Annotation(注解)?

  2. 找配置字典: 发现了注解的值是 java-instrumentation。于是 Operator 去 K8s 里寻找名为 java-instrumentationInstrumentation 自定义资源(CRD),读取里面的配置(比如镜像地址、gRPC 端点、环境变量)。

第四步:执行注入 (Mutate / Inject)

一旦匹配成功,Operator 就会像做外科手术一样,直接在内存里修改这个 Pod 的配置(YAML)。它做了三件极其核心的事情:

  1. 塞入一个共享卷 (Volume): 增加一个类型为 emptyDir 的存储卷,挂载名为 opentelemetry-auto-instrumentation。这相当于在 Pod 里划出了一块 InitContainer 和主容器都能访问的“共享U盘”。

  2. 塞入一个 InitContainer(初始化容器): 使用你配置的探针镜像(dev.local/otel-java-agent:v1)作为 InitContainer。 这个容器启动后只执行一条命令:cp /javaagent.jar /otel-auto-instrumentation/javaagent.jar。把探针文件拷贝到上面的“共享U盘”里,然后自己就结束退出了。

  3. 篡改主容器的环境变量 (Env Vars): 向你的 ts-travel-service 容器中强行塞入一堆环境变量:

    1. OTEL_EXPORTER_OTLP_ENDPOINT=http://...:4317

    2. OTEL_EXPORTER_OTLP_PROTOCOL=grpc

    3. 最致命的一招: JAVA_TOOL_OPTIONS="-javaagent:/otel-auto-instrumentation/javaagent.jar"

第五步:放行并持久化 (Admit & Persist)

Operator 把修改后的 Pod 配置返回给 API Server。API Server 将这个“被加料”的 Pod 保存到 etcd 数据库中。

第六步:Kubelet 执行运行

Node 节点上的 Kubelet 拿到配置开始启动 Pod:

  1. 先跑 InitContainer,把探针 .jar 包准备好。

  2. 再跑你的 Java 主应用。此时,由于环境变量里有 JAVA_TOOL_OPTIONS,JVM 在启动你的 Spring Boot 之前,会极其听话地优先加载 -javaagent 指向的探针包。


💡 总结:Operator 的双重身份

在整个 OTel 体系里,Operator 其实扮演了两个角色(它是一个典型的 Reconciliation Loop 控制循环):

  1. Webhook 拦截器(Mutating Webhook): 专门负责拦截 Pod 创建请求,利用 InitContainer 和 JAVA_TOOL_OPTIONS 实现对业务应用“神不知鬼不觉”的探针注入。

  2. CRD 控制器(Controller): 负责监听 OpenTelemetryCollector 这个自定义资源。当你 apply 那个 YAML 时,它负责真正在 K8s 里帮你拉起 Collector 的 Deployment、Service 和 ConfigMap。

十、 深入研究-为什么要有cert-manager

一句话总结就是:Kubernetes 的 API Server 有一个极其严格的“安全强迫症”——它调用任何 Webhook 时,绝对不允许走普通的 HTTP,必须、强制、毫无商量余地要求走 HTTPS(TLS 加密)!

以下是具体的因果关系和 cert-manager 在其中扮演的“救火队长”角色:

为什么 API Server 强制要求 HTTPS?

当你在 K8s 里创建一个 Pod 时(比如带有数据库密码的环境变量),API Server 会把这个 Pod 的完整原始数据打包发送给 Webhook(比如 OTel Operator)。 如果走明文 HTTP,集群内部网络一旦被嗅探,所有的密码、密钥、核心配置将一览无余。所以,K8s 源码里写死了:Webhook 必须提供 TLS 证书,否则 API Server 拒绝通信。

没有 cert-manager 时,搞证书有多痛苦?

既然必须要 HTTPS,那你的 Operator Pod 跑起来的时候,就得自己准备好 tls.crt(公钥)和 tls.key(私钥)。 如果不借助自动化工具,你需要纯手工完成以下极其反人类的步骤:

  1. 自己用 openssl 命令生成一个根证书(CA)。

  2. 签发一个服务器证书,且证书的 SAN(备用名称)必须精确匹配你 Operator 的 K8s Service 域名(比如 otel-webhook-service.tt.svc)。

  3. 把证书变成 K8s Secret 挂载到 Operator Pod 里。

  4. 最变态的一步: 你必须修改 K8s 的 MutatingWebhookConfiguration 这个 YAML 资源,把刚才那个 CA 证书的 Base64 编码,硬编码填到 caBundle 这个字段里。以此告诉 API Server:“请信任这个 CA 签发的证书”。

而且,证书是会过期的!一旦过期,Webhook 就会瘫痪,导致你整个集群连最基本的 Pod 都创建不出来(因为 API Server 调不通 Webhook 就会拦截所有请求)。

cert-manager 的“魔法”登场

cert-manager 就是为了终结上述所有痛苦而诞生的。它是一个 K8s 原生的证书管理专家。

当 OTel Operator 配合 cert-manager 部署时,发生了什么?

  1. 自动发证: cert-manager 会自动在集群里充当一个“内部发证机关(CA)”,默默给 OTel Operator 签发有效期内的 TLS 证书,并挂载进去。

  2. 自动注入 caBundle(核心神技): OTel 的 Webhook YAML 里有一行特殊的注解(Annotation):cert-manager.io/inject-ca-from: ...。cert-manager 看到这个注解后,会自动把自己的 CA 证书 Base64 编码,精准地填入 Webhook 的 caBundle 字段中

  3. 自动续期: 证书快过期了?cert-manager 会在后台静默为你重新签发并替换,API Server 和 Operator 之间永远保持着合法的 HTTPS 连接。

Logo

AtomGit 是由开放原子开源基金会联合 CSDN 等生态伙伴共同推出的新一代开源与人工智能协作平台。平台坚持“开放、中立、公益”的理念,把代码托管、模型共享、数据集托管、智能体开发体验和算力服务整合在一起,为开发者提供从开发、训练到部署的一站式体验。

更多推荐