Jack Shirazi

Kubernetes Java 应用程序的零配置 OpenTelemetry 自动插桩

本文将介绍如何安装和启用 Kubernetes 的 OpenTelemetry Operator,以便自动插桩 Java 应用程序,而无需更改部署的任何配置

Zero config OpenTelemetry auto-instrumentation for Kubernetes Java applications

OpenTelemetry Java 代理有多种安装方法,可以将该代理安装到 Java 应用程序中。如果您在 Kubernetes Pod 中运行 Java 应用程序,则有一种单独的机制(在底层使用 JAVA_TOOL_OPTIONS 和其他环境变量)来自动插桩 Java 应用程序。这种自动插桩无需对应用程序和 Pod 进行任何配置更改即可实现!

在 Kubernetes 中实现 Java 应用程序零配置自动插桩的机制是通过 Kubernetes 的 OpenTelemetry Operator。此 Operator 具有许多功能,完整的文档(当然还有源代码)可在项目本身中找到。在本博客中,我将介绍如何使用 OpenTelemetry Operator 在 Kubernetes 中安装、设置和运行 Java 应用程序的零配置自动插桩。

安装 OpenTelemetry Operator

在撰写本博客时,OpenTelemetry Operator 需要安装证书管理器,然后才能安装该 Operator。从 Web 安装很简单。首先安装

cert-manager
(要安装的版本将在Kubernetes 的 OpenTelemetry Operator 文档中指定)

kubectl apply -f https://github.com/cert-manager/cert-manager/releases/download/v1.14.4/cert-manager.yaml

然后,当证书管理器准备就绪时(

kubectl get pods -n cert-manager
)… …

NAMESPACE      NAME                                         READY
cert-manager   cert-manager-67c98b89c8-rnr5s                1/1
cert-manager   cert-manager-cainjector-5c5695d979-q9hxz     1/1
cert-manager   cert-manager-webhook-7f9f8648b9-8gxgs        1/1

…您可以安装 OpenTelemetry Operator

kubectl apply -f https://github.com/open-telemetry/opentelemetry-operator/releases/latest/download/opentelemetry-operator.yaml

当然,您可以使用 Operator 的特定版本,而不是

最新版本
。但在这里我使用了
最新版本
最新版本。

Instrumentation 资源

现在,您只需添加一个 Kubernetes 资源即可启用自动插桩:一个

Instrumentation
资源。我将使用
banana
命名空间作为示例,因此我首先创建了该命名空间(
kubectl create namespace banana
)。自动插桩由这些 Instrumentation 资源指定和配置。这是一个基本的资源,它允许
banana
命名空间中的每个 Java Pod 使用 2.5.0 版本的 OpenTelemetry Java 代理进行自动插桩

apiVersion: opentelemetry.io/v1alpha1
kind: Instrumentation
metadata:
  name: banana-instr
  namespace: banana
spec:
  exporter:
    endpoint: "https://my.endpoint"
  propagators:
    - tracecontext
    - baggage
    - b3
  sampler:
    type: parentbased_traceidratio
    argument: "1.0"
  java:
    image: ghcr.io/open-telemetry/opentelemetry-operator/autoinstrumentation-java:2.5.0
    env:
      - name: OTEL_EXPORTER_OTLP_HEADERS
        value: "Authorization=Bearer MyAuth"

创建此资源(例如,使用

kubectl apply -f banana-instr.yaml
,假设上面的 yaml 保存在文件
banana-instr.yaml
中)使
banana-instr
Instrumentation 资源可供使用。(请注意,您需要将
my.endpoint
MyAuth
更改为适合您的收集器的值。)您可以通过向
banana
命名空间中的任何部署添加注释来立即使用此插桩

metadata:
  annotations:
    instrumentation.opentelemetry.io/inject-java: "true"

尚未将

banana-instr
Instrumentation 资源设置为默认应用于 banana 命名空间中的所有 Pod。目前,就应用程序而言,它是零配置的,但它需要向Pod 或部署添加注释。为了使所有 Pod
banana
命名空间中实现完全零配置,我们需要将该注释添加到命名空间本身,即编辑命名空间(
kubectl edit namespace banana
),使其内容类似于

apiVersion: v1
kind: Namespace
metadata:
  name: banana
  annotations:
    instrumentation.opentelemetry.io/inject-java: "banana-instr"
...

现在,我们有一个命名空间,它将使用 2.5.0 OpenTelemetry Java 代理自动插桩部署在

banana
命名空间中的每个 Java 应用程序!

尝试一下

docker.elastic.co/demos/apm/k8s-webhook-test 中有一个简单的 Java 应用程序示例,它只是重复调用链

main->methodA->methodB->methodC->methodD
并在调用中加入了一些休眠。运行它(
kubectl apply -f banana-app.yaml
),使用非常基本的 Pod 定义

apiVersion: v1
kind: Pod
metadata:
  name: banana-app
  namespace: banana
  labels:
    app: banana-app
spec:
  containers:
    - image: docker.elastic.co/demos/apm/k8s-webhook-test
      imagePullPolicy: Always
      name: banana-app
      env: 
      - name: OTEL_INSTRUMENTATION_METHODS_INCLUDE
        value: "test.Testing[methodB]"

会导致应用程序自动插桩,而无需更改任何配置!生成的应用程序会显示在任何 APM UI 中,例如 Elastic APM

正如您所看到的,对于这个示例,我还将此 env 变量添加到 Pod yaml 中,

OTEL_INSTRUMENTATION_METHODS_INCLUDE="test.Testing[methodB]"
以便显示来自 methodB 的跟踪。

自动插桩背后的技术

要使用自动插桩,无需特别了解底层机制,但对于那些感兴趣的人,这里有一个简单的概述。

  1. Kubernetes 的 OpenTelemetry Operator 安装了一个变更 Webhook,这是一个标准的 Kubernetes 组件。
  2. 部署时,Kubernetes 首先将所有定义发送到变更 Webhook。
  3. 如果变更 Webhook 发现应该应用自动插桩的条件(即
    1. 该命名空间有一个 Instrumentation 资源,并且
    2. 该 Instrumentation 的正确注释以某种方式应用于定义,无论是来自定义本身还是来自命名空间),
  4. 则变更 Webhook 会“变更”该定义以包含 Instrumentation 资源定义的环境。
  5. 该环境包括 env 中定义的显式值,以及一些隐式的 OpenTelemetry 值(有关完整详细信息,请参阅 Kubernetes 的 OpenTelemetry Operator 文档)。
  6. 最重要的是,Operator 会
    1. 拉取 Instrumentation 资源中定义的镜像,
    2. 提取路径
      /javaagent.jar
      中的文件(使用 shell 命令
      cp
      )
    3. 将其插入到 pod 中的路径
      /otel-auto-instrumentation-java/javaagent.jar
    4. 并添加环境变量
      JAVA_TOOL_OPTIONS=-javaagent:/otel-auto-instrumentation-java/javaagent.jar
      .
  7. JVM 会在启动时自动获取该 JAVA_TOOL_OPTIONS 环境变量,并将其应用于 JVM 命令行。

下一步

此演练可以在任何 Kubernetes 集群中重复进行,以演示和试验自动检测(您需要首先创建 banana 命名空间)。在本系列两部分中的第 2 部分中,《使用 OpenTelemetry Operator 为 Kubernetes 注入自定义代理》中,我将展示如何通过 OpenTelemetry operator 安装任何 Java 代理,并以 Elastic Java 代理为例。

分享这篇文章