Prometheus和Opentelemetry等工具可以帮助我们监控复杂分布式系统的运行状况、性能和可用性。Opentelemetry(简称OTel)是一个与供应商无关的开放标准,用于检测、生成、收集和导出指标数据。Prometheus是可观察性领域的一个基础设施,广泛用于内部的监控和告警。
虽然Prometheus和OTel都能够导出指标,但它们之间的差异和相似之处还有很多,超出了本文的范围。本文向您展示OTel如何支持Prometheus,特别是在Kubernetes环境中。在本文中能看到:
- 如何使用OTel收集器的Prometheus接收器来摄取Prometheus指标。
- 通过OTel原生配置(如K8s cluster receiver 和 Kubelet stats receiver)收集Prometheus指标的方法。
本文还将深入描述OTel Operator 的 Target Allocator(下面简写成TA):
- 如何将其用于Prometheus服务发现。
- 如何确保prometheus target 均匀分布到多个Opentelemetry collector。
OTel 和 Prometheus
OTel主要关注可观测的instrumentation部分,因此它不会存储指标数据;您必须将数据转发给后端服务进行存储、警报和查询。
另一方面,Prometheus提供了一个时序数据库,他可以同时用于数据采集和存储。您可以通过web界面查看图表、设置警报和查询数据。它还包含一种数据格式,称为Prometheus text-based exposition format。
Prometheus数据存储为维度时间序列,这些数据具有属性(例如标签或维度)和时间戳。
Prometheus服务器从配置文件中定义的target中收集Prometheus指标。target是一个http接口,它将指标暴露给prometheus。
Prometheus在监控领域无处不在,许多工具都以Prometheus格式原生发布指标,包括Kubernetes和HashiCorp的Nomad。对于那些没有这样做的人,有许多供应商和社区构建的Prometheus exporter可以收集并导出数据。
虽然你可以使用Prometheus来监控各种基础设施和应用程序指标,但它最流行的用法是监控Kubernetes。这也是我们将在本文中重点讨论的。
Prometheus 指标以及Opentelemetry
在本节中,您将了解几个OTel receiver组件,这些组件演示了OTel和Prometheus之间的互操作性。
collector是一个OTel组件,可用于从多个来源收集指标数据并将数据导出到多个目的地。collector还能够处理指标数据,比如修改数据属性和清除个人身份信息。您可以使用Prometheus SDK生成指标,用collector摄取它们,进行一些处理(如果需要),然后将它们转发到您选择的后端。
Prometheus receiver是collector的一个组件,它可以作为Prometheus的直接替代品来抓取指标,并支持scrap_config中的全套配置。
Prometheus receiver还支持examplar类型的数据。examplar是一个与OTel上下文和指标事件相关联的记录值。请注意,目前仅有OpenMetrics格式支持examplar。
Prometheus receiver还在积极开发中,因此它有几个局限性:它是一个有状态的组件;另外,在没有目标分配器(Target Allocator,简称TA)的情况下,不建议在collector集群中使用此组件,因为在这种状态下:
- collector抓取指标的时候无法自动缩放
- 如果collector副本以相同的配置运行,它将多次抓取目标
- 如果要对抓取目标进行分片,你需要为每个副本配置不同的抓取配置
要将指标从OTel collector导出到Prometheus,您有以下选项:Prometheus exporter 和Prometheus remote-write exporter。您还可以使用collector默认的OTLP HTTP exporter,将他导出到Prometheus的OTLP端点。Prometheus现在也原生支持OTLP。
Prometheus exporter可以按照Prometheus格式暴露数据,然后由Prometheus抓取。然而,这种抓取过程不存在数据缩放,因为所有指标都是在一次抓取中发送的。
为了解决数据缩放问题,您也可以使用Prometheus remote write exporter,它可以将数据从多个collector实例推送到Prometheus。由于Prometheus也接受远程写入,如果您正在生成OTel指标并希望将其发送到支持Prometheus远程写入的后端,您也可以使用这个exporter。
请注意,Prometheus 中的Prometheus remote write目前不支持元数据,如HELP和TYPE。有关更多信息,请查看问题#13163和问题#12608。这将在 Prometheus Remote Write v2.0中解决。
要了解这两个导出器的架构的更多信息,请参阅Use Prometheus Remote Write exporter。
使用Target Allocator,目标分配器
可扩展性是Prometheus面临的一个常见挑战,在管理越来越多的监控目标和指标的同时,可扩展性意味着能够有效维护性能和资源分配。一种方法是根据标签或维度对工作负载进行分片,这意味着使用多个Prometheus实例根据特定参数来处理指标。这可能有助于减轻单个实例的负担。然而,这种方法需要考虑以下2方面的问题:
首先,需要一个管理节点来避免直接查询实例的各个分片,这意味着你需要有N+1个Prometheus实例,其中管理节点的内存等于其他N个节点的总和,这让内存需求翻倍。其次,prometheus分片要求每个节点都抓取目标,即使它马上就会被丢弃。
需要注意的是,如果内存足够大到创建单个prometheus实例,那么分片并没有多大好处,因为你可以直接使用更大的实例来抓取所有内容。人们分片的一个原因通常是为了一定程度的容错。例如,如果一个Prometheus实例内存不足(OOM),则整个告警系统可以继续工作。
OTel Operator的Target Allocator(TA)能够解决其中一些问题。例如,它可以自动丢弃任何它知道不会被抓取的目标。Target Allocator还会对目标自动分片,而如果用hashmod分片,你需要根据你拥有的副本数量更新你的配置。Target Allocator还允许您继续使用PodMonitor和ServiceMonitor等资源来收集有关Kubernetes基础设施的Prometheus指标。
Target Allocator是OTel Operator的一部分。OTel Operator是一个Kubernetes Operator,它有以下功能:
- 管理Opentelemetry collector
- 在pod中注入并配置autoinstrumentation
事实上,Operator在Kubernetes中创建了两种新的自定义资源(CR)类型来支持此功能:Opentelemetry Collector CR和Autoinstrumentation CR。
今天,我们将重点介绍Target Allocator。Target Allocator是OTel Operator的 collector管理功能的可选组件。
简而言之,Target Allocator将prometheus服务发现和指标收集功能解耦,允许它们独立扩展。OTel collector无需安装Prometheus即可管理Prometheus指标。Target Allocator管理collector的prometheus receiver的配置。
Target Allocator有两个功能:
- prometheus target在OTel collector池中的均匀分布
- prometheus自定义资源的发现
让我们逐一深入探讨。
Prometheus target 在collector集群中均匀分布
Target Allocator功能包括发现要抓取的目标、然后把目标分配给OTel collector。它的工作流程如下:
- Target Allocator找到所有要抓取的指标目标
- Target Allocator找到所有可用的collector
- Target Allocator确定哪些收集器抓取哪些指标
- collector查询Target Allocator,找出要抓取的指标
- collector从分配给他们的目标中抓取数据
这意味着OTel collector收集指标数据,而不是prometheus。
Target是一个http端点,为Prometheus提供Metrics数据。抓取(Scrape)是指通过HTTP请求从目标实例收集Metrics、解析响应并将收集到的数据写入存储组件的操作。
prometheus自定义资源的发现
Target Allocator的另一项功能是发现prometheus Operator CR,即ServiceMonitor和PodMonitor。
在过去,所有prometheus抓取配置都必须通过collector的prometheus receiver 完成。启用Target Allocator的服务发现功能后,Target Allocator可以通过从部署在集群中的PodMonitor和ServiceMonitor实例,在Prometheus receiver中创建抓取配置,简化了Prometheus receiver的配置。
尽管不需要在Kubernetes集群中安装Prometheus来使用Target Allocator的功能,但Target Allocator确实要求安装ServiceMonitor和PodMonitor。这些CR经常与Prometheus Operator捆绑在一起,它们也可以单独安装。最简单的方法是获取 PodMonitor YAML和ServiceMonitor YAML自定义资源定义(CRD)的副本。
OTel支持PodMonitor和ServiceMonitor 这两种Prometheus资源,因为这些资源在Kubernetes基础设施监控中得到了广泛的应用。因此,OTel Operator开发人员希望能够轻松地将它们添加到OTel生态系统中。
PodMonitor和ServiceMonitor仅限于从Pod收集指标,无法抓取其他端点,如kubelet。在这种情况下,您仍然必须依赖collector的prometheus receiver插件的抓取配置。
配置
以下是OTel收集器CR的YAML配置。请注意,此收集器在名为opentelemetry的命名空间中运行,但它可以在您喜欢的任何命名空间中运行。
主要部分包括:
- mode:Operator支持的部署模式:Sidecar、deployment、StatefulSet和DaemonSet。
- targetallocator:这是您配置Target Allocator的地方。请注意,Target Allocator仅支持deployment、DaemonSet和StatefulSet部署模式。
- config:内容是OTel collector配置YAML
apiVersion: opentelemetry.io/v1alpha1
kind: OpenTelemetryCollector
metadata:
name: otelcol
namespace: opentelemetry
spec:
mode: statefulset
targetAllocator:
enabled: true
serviceAccount: opentelemetry-targetallocator-sa
prometheusCR:
enabled: true
config: |
receivers:
otlp:
protocols:
grpc:
http:
prometheus:
config:
scrape_configs:
- job_name: 'otel-collector'
scrape_interval: 30s
static_configs:
- targets: [ '0.0.0.0:8888' ]
target_allocator:
endpoint: otelcol-targetallocator
interval: 30s
collector_id: "${POD_NAME}"
…
要使用Target Allocator,需要将spec.targetallocator.enabled设置为true。
接下来需要设置Target_Allocator.endpoint,确保collector的Prometheus receiver插件知道Target Allocator地址:
receivers:
prometheus:
config:
scrape_configs:
- job_name: 'otel-collector'
scrape_interval: 30s
static_configs:
- targets: ['0.0.0.0:8888']
target_allocator:
endpoint: otelcol-targetallocator
interval: 30s
collector_id: '${POD_NAME}'
Prometheus receiver配置中的Target Allocator端点名称,是OTel collector名称(在上面的例子中是otelcol)和-targetallocator后缀拼接起来的。
要使用Prometheus服务发现功能,您需要通过将spec.targetallotor.promotheusCR.enabled设置为true。
最后,如果你想启用Target Allocator的Prometheus CR功能,你需要定义自己的ServiceMonitor和PodMonitor实例。以下是ServiceMonitor定义的示例,它的含义是,找到一个带有特定标签(app: my-app)的服务,endpoint的port名称是prom,抓取间隔15秒。
apiVersion: monitoring.coreos.com/v1
kind: ServiceMonitor
metadata:
name: sm-example
namespace: opentelemetry
labels:
app.kubernetes.io/name: py-prometheus-app
release: prometheus
spec:
selector:
matchLabels:
app: my-app
namespaceSelector:
matchNames:
- opentelemetry
endpoints:
- port: prom
interval: 15s
对应的Service定义如下:
apiVersion: v1
kind: Service
metadata:
name: py-prometheus-app
namespace: opentelemetry
labels:
app: my-app
app.kubernetes.io/name: py-prometheus-app
spec:
selector:
app: my-app
app.kubernetes.io/name: py-prometheus-app
ports:
- name: prom
port: 8080
因为该服务有一个名为app:my app的标签和一个名称为prom的端口,所以它将被ServiceMonitor接收。
您可以为要监视的每个服务创建单独的ServiceMonitor,也可以创建一个包含所有服务的单一ServiceMonitor。这种规则同样适用于PodMonitor。
在Target Allocator 开始抓取之前,您需要设置Kubernetes的访问权限(RBAC)。这意味着需要有一个ServiceAccount和相应的集群角色,以便Target Allocator 可以访问必需的资源来提取指标。
您可以创建自己的ServiceAccount,并在OTel Collector CR中将其引用为spec.targetAllocator.ServiceAccount。然后,您需要为此服务帐户配置ClusterRole和ClusterRoleBinding。
如果省略ServiceAccount配置,Target Allocator 将自动创建ServiceAccount。ServiceAccount的默认名称是collector名称加上-Collector后缀。默认情况下,此ServiceAccount没有定义策略,因此您需要另外创建ClusterRole和ClusterRoleBinding。
以下取自OTel Target Allocator自述文件的RBAC配置示例。它包括ServiceAccount、ClusterRole和ClusterRoleBinding配置:
apiVersion: v1
kind: ServiceAccount
metadata:
name: opentelemetry-targetallocator-sa
namespace: opentelemetry
---
apiVersion: rbac.authorization.k8s.io/v1
kind: ClusterRole
metadata:
name: opentelemetry-targetallocator-role
rules:
- apiGroups:
- monitoring.coreos.com
resources:
- servicemonitors
- podmonitors
verbs:
- '*'
- apiGroups: ['']
resources:
- namespaces
verbs: ['get', 'list', 'watch']
- apiGroups: ['']
resources:
- nodes
- nodes/metrics
- services
- endpoints
- pods
verbs: ['get', 'list', 'watch']
- apiGroups: ['']
resources:
- configmaps
verbs: ['get']
- apiGroups:
- discovery.k8s.io
resources:
- endpointslices
verbs: ['get', 'list', 'watch']
- apiGroups:
- networking.k8s.io
resources:
- ingresses
verbs: ['get', 'list', 'watch']
- nonResourceURLs: ['/metrics']
verbs: ['get']
---
apiVersion: rbac.authorization.k8s.io/v1
kind: ClusterRoleBinding
metadata:
name: opentelemetry-targetallocator-rb
subjects:
- kind: ServiceAccount
name: opentelemetry-targetallocator-sa
namespace: opentelemetry
roleRef:
kind: ClusterRole
name: opentelemetry-targetallocator-role
apiGroup: rbac.authorization.k8s.io
详细描述一下ClusterRole,以下规则可以为Target Allocator提供所需的最小访问权限,以便根据任何Prometheus配置查询所需的所有目标:
- apiGroups: ['']
resources:
- nodes
- nodes/metrics
- services
- endpoints
- pods
verbs: ['get', 'list', 'watch']
- apiGroups: ['']
resources:
- configmaps
verbs: ['get']
- apiGroups:
- discovery.k8s.io
resources:
- endpointslices
verbs: ['get', 'list', 'watch']
- apiGroups:
- networking.k8s.io
resources:
- ingresses
verbs: ['get', 'list', 'watch']
- nonResourceURLs: ['/metrics']
verbs: ['get']
如果要在OpenTelemetry Collector CR中启用prometheus CR(将spec.targetAllocator.prometheusCoR.enabled设置为true),您还需要定义以下角色。这使 Target Allocator可以访问podMonitor和ServiceMonitor 。它还提供对PodMonitor和ServiceMonitor的命名空间访问权限。
- apiGroups:
- monitoring.coreos.com
resources:
- servicemonitors
- podmonitors
verbs:
- '*'
- apiGroups: ['']
resources:
- namespaces
verbs: ['get', 'list', 'watch']
其他OTel组件
本节介绍可用于Kubernetes的其他OTel 组件。
- Kubernetes Cluster Receiver:从Kubernetes API Server 收集集群级指标和实体事件
- Kubernetes Objects Receiver:从Kubernetes API Server收集(pull/watch)对象
- Kubelet Stats Receiver:从Kubelet中提取指标,并将其发送到pipeline进行进一步处理
- Host Metrics Receiver:从集群的宿主机中抓取系统指标
- Kubernetes Attributes Processor:添加Kubernetes上下文,将应用程序指标与Kubernetes 指标相关联。被认为是Opentelemetry监控Kubernetes最重要的组件之一
Kubernetes attributes processor还可以用于为跟踪、指标和日志添加自定义属性,以及Pod和命名空间上的自定义标签和注释。
还有其他一些collector组件可以用来监控Kubernetes,包括一些专用于Kubernetes的组件以及通用的processor,如 batch, memory limiter, resource processors。
在collector配置文件中添加配置之后,您需要在pipeline部分启用它们。pipeline让您能够从任何源收集、处理数据并将其路由到一个或多个目标。
优点和缺点
优点:
- 不必将Prometheus作为数据存储来维护,减少了需要维护的基础设施数量——特别是使用一体化的可观测后端来摄取OTel数据的时候(跟踪、指标、日志)。
- 虽然您仍然需要维护ServiceMonitor和PodMonitor,但这种维护工作量要比保持Prometheus Operator的最新状态要少得多。
- 使用完整的OTel解决方案,同时仍能兼顾Prometheus指标
- OTel除了提供指标外,还可以提供trace和日志,并将它们关联起来,从而增强Kubernetes环境的可观察性。
- OTel提供了方便的工具,如Target Allocator和OTel collector组件,为配置和部署选项提供了灵活性。
缺点:
- 对于不熟悉OTel概念、组件和工作流程的用户来说,采用和管理新的可观察性工具需要陡峭的学习曲线。
- 用户可以继续使用Prometheus强大的查询语言PromQL,如果将指标发送到兼容Prometheus的后端。
- OTel本身包含许多移动部件,并在可扩展性方面有挑战性。
- OTel内部的成熟度和稳定性各不相同;prometheus拥有一个成熟的生态系统。
- 维护OTel组件需要额外的计算和人力资源。
- 管理和维护Prometheus和OTel组件会在监控基础架构中引入复杂性。
结论
Prometheus的维护人员还从Prometheus方面进一步开发了两个项目之间的互操作性,使其更容易成为OTLP指标的后端。例如,Prometheus现在可以接受OTLP,很快,您将能够使用Prometheus exporter导出OTLP。因此,如果服务中内置了Prometheus SDK,就可以推送OTLP,以利用丰富的Prometheus exporter生态。维护人员也在努力增加对delta临时性的支持。该组件将把增量样本聚合成为累积值。
是否决定使用OTel来收集Prometheus指标,取决于您的业务需求。使用前面讨论的OTel组件,您可以将所有指标转换为Prometheus格式,也可以将Prometheus指标转换为OTLP。尽管prometheus本身不是为长期数据存储而构建的,并且其扩展性存在挑战,但Mimir、Thanos和Cortex等开源项目可以帮助解决这些问题。