OpenTelemetry(简称OTel)是一个开源可观测性框架,用于仪表化、生成、收集和导出诸如跟踪、度量、日志等遥测数据
部署参考文档:https://opentelemetry.io/zh/docs https://www.zhihu.com/question/545762884/answer/3323681028
Instrumentation Instrumentation 是 OpenTelemetry 中用于对应用程序进行监控和数据收集。它包括手动仪表化(Manual Instrumentation)和自动仪表化(Automatic Instrumentation)两种方式。通过 Instrumentation,开发人员可以将应用程序的运行数据(如追踪、指标、日志)收集并发送到后端系统进行分析和可视化。
手动仪表化:
开发者通过在代码中显式地添加 OpenTelemetry API 调用,来创建和管理追踪、指标等遥测数据。
可以对应用程序的特定部分进行详细的监控和分析,获取更深入的性能和行为信息。
在关键的业务逻辑处手动创建 span 来记录操作的开始和结束时间,从而精确地监控特定代码段的执行情况。
自动仪表化:
无需修改应用程序源代码,通过特定的机制(如字节码注入、代理等)自动对应用程序中的各种库、框架等进行监控,收集遥测数据。
减少手动添加监控代码的工作量,快速为应用程序添加基本的监控能力。例如,OpenTelemetry 的 Java 自动仪表化可以通过一个 agent 自动收集日志、指标、trace 并上报。
Collector Collector 是一个开源的、可扩展的代理,用于接收、处理和导出遥测数据(如 traces、metrics 和 logs)。它提供了一种厂商中立的方式来收集、处理和导出遥测数据,消除了运行、操作和维护多个代理/收集器的需要。
Deployment 在不修改应用程序代码的情况下,收集和处理遥测数据。
Agent:
部署方式:每个客户端SDK或下游采集器都配置一个collector。收集器实例与应用程序在同一主机上运行,例如sidecar或者daemonset方式。
工作方式:应用程序中的SDK以OTLP协议发送遥测数据给collector。然后collector处理遥测数据并对接到可观测性后端。
Gateway:
部署方式:使用开箱即用的负载均衡器(比如nginx)在otel-collector之间分配负载。
工作方式:应用程序中的SDK以OTLP协议发送遥测数据给负载均衡器,负载均衡器根据算法选择其中一个collector实例进行处理并对接到可观测性后端
Pipeline components
receiver:负责按照对应的协议格式监听接收遥测数据,并把数据转给一个或者多个processor。
processor:负责做遥测数据加工处理,如丢弃数据,增加信息,转批处理等,并把数据传递给下一个processor或者传递给一个或多个exporter。
exporter:负责把数据往下一个接收端发送(一般是遥测后端),exporter可以定义同时从多个不同的processor中获取遥测数据。
Collector 除了提供让遥测数据收集与业务逻辑处理正交的能力,还充当了遥测数据对接遥测后端的适配器。Collector可以接收 Otlp、Zipkin、Jaeger等任意格式的数据,然后以 Otlp、Zipkin、Jaeger等任意格式的数据转发出去。这一切只取决于你需要输入或输出的格式是否有对应的 receiver 和 exporter 实现
最佳实践 Jaeger 为了便于演示这里使用 jaegertracing/all-in-one 镜像来部署 Jaeger,这个镜像包含了 Jaeger 收集器、内存存储、查询服务和 UI 等组件,非常适合开发和测试使用。通过环境变量 COLLECTOR_OTLP_ENABLED
启动对 OTLP(OpenTelemetry Protocol) 的支持。
kubectl apply -f - <<EOF apiVersion: apps/v1 kind: Deployment metadata: name: jaeger spec: replicas: 1 selector: matchLabels: app: jaeger template: metadata: labels: app: jaeger spec: containers: - name: jaeger image: jaegertracing/all-in-one:latest env: - name: COLLECTOR_OTLP_ENABLED value: "true" ports: - containerPort: 16686 - containerPort: 14268 --- apiVersion: v1 kind: Service metadata: name: jaeger spec: selector: app: jaeger type: ClusterIP ports: - name: ui port: 16686 targetPort: 16686 - name: collector port: 14268 targetPort: 14268 - name: http protocol: TCP port: 4318 targetPort: 4318 - name: grpc protocol: TCP port: 4317 targetPort: 4317 EOF
OpenTelemetry Operator OpenTelemetry Operator用于管理OpenTelemetry 收集器(OpenTelemetry Collectors)和工作负载的自动检测(auto-instrumentation) 安装OpenTelemetry Operator
helm repo add open-telemetry https://open-telemetry.github.io/opentelemetry-helm-charts helm install opentelemetry-operator open-telemetry/opentelemetry-operator \ --set "manager.collectorImage.repository=otel/opentelemetry-collector-k8s" \ --set admissionWebhooks.certManager.enabled=false \ --set admissionWebhooks.autoGenerateCert.enabled=true
可以看到对应的 Pod 已经正常运行:
➜ ~ kubectl --namespace default get pods -l "app.kubernetes.io/name=opentelemetry-operator" NAME READY STATUS RESTARTS AGE opentelemetry-operator-f78f45ffc-sgns7 2/2 Running 0 2m44s
还会自动为我们添加OpenTelemetry 相关的 CRD:
➜ ~ kubectl get crd |grep opentelemetry instrumentations.opentelemetry.io 2025-01-14T07:32:04Z opampbridges.opentelemetry.io 2025-01-14T07:32:04Z opentelemetrycollectors.opentelemetry.io 2025-01-14T07:32:04Z
OpenTelemetry Collector kubectl apply -f - <<EOF apiVersion: opentelemetry.io/v1alpha1 kind: OpenTelemetryCollector metadata: name: otel spec: config: | receivers: otlp: protocols: grpc: http: processors: memory_limiter: check_interval: 1s limit_percentage: 75 spike_limit_percentage: 15 batch: send_batch_size: 10000 timeout: 10s exporters: debug: otlp/jaeger: endpoint: "jaeger.default:4317" tls: insecure: true service: pipelines: traces: receivers: [otlp] processors: [] exporters: [debug,otlp/jaeger] EOF
创建 CR OpenTelemetryCollector 后,Otel Operator 会创建一个 deployment 和 多个 service。
➜ ~ kubectl get deployment,service -l app.kubernetes.io/component=opentelemetry-collector NAME READY UP-TO-DATE AVAILABLE AGE deployment.apps/otel-collector 1/1 1 1 3m37s NAME TYPE CLUSTER-IP EXTERNAL-IP PORT(S) AGE service/otel-collector ClusterIP 10.111.0.124 <none> 4317/TCP,4318/TCP 3m36s service/otel-collector-headless ClusterIP None <none> 4317/TCP,4318/TCP 3m36s service/otel-collector-monitoring ClusterIP 10.111.151.111 <none> 8888/TCP 3m36s
Auto-instrumentation 创建一个Java 服务的基本检测资源
kubectl apply -f - <<EOF apiVersion: opentelemetry.io/v1alpha1 kind: Instrumentation metadata: name: instrumentation-sample spec: propagators: - tracecontext - baggage - b3 sampler: type: parentbased_traceidratio argument: "1" env: - name: OTEL_EXPORTER_OTLP_ENDPOINT value: otel-collector.default:4318 java: env: - name: OTEL_EXPORTER_OTLP_ENDPOINT value: http://otel-collector.default:4317 EOF
Instrumentation 由以下属性组成:exporter.endpoint
-(可选)将遥测数据发送到 OTLP 格式的地址。propagators
- 使所有数据源能够共享底层上下文机制,用于在事务的整个生命周期中存储状态和访问数据。 sampler
- 通过减少收集和发送到后端的跟踪样本数量来引入的噪音和开销的机制。 OpenTelemetry 提供两种类型:StaticSampler 和 TraceIDRatioBased。 语言属性,即java、nodejs、python 和dotnet - 根据 pod 注解中设置的语言,使用自动插桩的自定义镜像
默认情况下,自动检测 Java 服务的 Instrumentation 资源与协议otlp一起使用http/protobuf。这意味着配置的端点必须能够通过http有效protobuf负载接收 OTLP。因此,示例使用otel-collector.default:4318,它连接到 http上一步中创建的 Collector 的 otlpreceiver 的端口。
创建java示例应用
kubectl apply -f - <<EOF apiVersion: apps/v1 kind: Deployment metadata: name: java-sample spec: replicas: 1 selector: matchLabels: app: java-sample template: metadata: labels: app: java-sample annotations: instrumentation.opentelemetry.io/inject-java: "true" spec: containers: - name: java-sample image: pinakispecial/spring-boot-rest ports: - containerPort: 8080 EOF
可用注解: true
- 从命名空间注入和埋点资源。 my-instrumentation
- 当前命名空间中注入Instrumentation CR 实例的名称。 my-other-namespace/my-instrumentation
- 另一个命名空间中Instrumentation CR 实例的名称和命名空间。false
-不注入。
可以看到 Otel Operator 向 Pod 中注入了一个 otel 的初始化容器
➜ ~ kubectl get pod java-sample-6f688ffb4f-gq95j -o jsonpath='{.spec.initContainers[*].image} {.spec.containers[*].image}' ghcr.io/open-telemetry/opentelemetry-operator/autoinstrumentation-java:1.33.6 pinakispecial/spring-boot-rest%
以及在 java 容器中注入了一系列的环境变量进行配置
spec: containers: - env: - name: OTEL_NODE_IP valueFrom: fieldRef: apiVersion: v1 fieldPath: status.hostIP - name: OTEL_POD_IP valueFrom: fieldRef: apiVersion: v1 fieldPath: status.podIP - name: OTEL_EXPORTER_OTLP_ENDPOINT value: http://otel-collector.default:4317 - name: JAVA_TOOL_OPTIONS value: ' -javaagent:/otel-auto-instrumentation-java/javaagent.jar' - name: OTEL_SERVICE_NAME value: java-sample - name: OTEL_RESOURCE_ATTRIBUTES_POD_NAME valueFrom: fieldRef: apiVersion: v1 fieldPath: metadata.name - name: OTEL_RESOURCE_ATTRIBUTES_NODE_NAME valueFrom: fieldRef: apiVersion: v1 fieldPath: spec.nodeName - name: OTEL_PROPAGATORS value: tracecontext,baggage,b3 - name: OTEL_TRACES_SAMPLER value: parentbased_traceidratio - name: OTEL_TRACES_SAMPLER_ARG value: "1" - name: OTEL_RESOURCE_ATTRIBUTES value: k8s.container.name=java-sample,k8s.deployment.name=java-sample,k8s.namespace.name=default,k8s.node.name=$(OTEL_RESOURCE_ATTRIBUTES_NODE_NAME),k8s.pod.name=$(OTEL_RESOURCE_ATTRIBUTES_POD_NAME),k8s.replicaset.name=java-sample-6f688ffb4f,service.instance.id=default.$(OTEL_RESOURCE_ATTRIBUTES_POD_NAME).java-sample
请求服务接口
➜ ~ kubectl port-forward java-sample-6f688ffb4f-gq95j 8080:8080 Forwarding from 127.0.0.1:8080 -> 8080 Forwarding from [::1]:8080 -> 8080 ➜ ~ curl localhost:8080 OK% ➜ ~ kubectl port-forward svc/jaeger 16686:16686 Forwarding from 127.0.0.1:16686 -> 16686 Forwarding from [::1]:16686 -> 16686
访问 Jaeger UI 查看访问的链路信息