工程

Elasticsearch 可观察性:采用 Prometheus 和 OpenMetrics 标准收集指标

本篇博文将介绍以下内容:

  • 为什么开放标准很重要
  • Prometheus 公开格式
  • Elastic 如何看待可观察性
  • Elasticsearch 可以使用 Prometheus 指标的三种方式
  • 举例说明如何收集和可视化由 Prometheus Redis 导出器公开的指标

开放标准

opensource.com 上,有一篇名为“什么是开放标准?”的参考性资源文档。 在该文档中 阐述了很多重要观点,但基于多年的 操作经验来看,我对下面几点比较认同:

  1. 可用性:开放标注可供所有人读取和 实施。
  2. 使最终用户的选择最大化
  3. 无歧视(供应商中立):开放标准以及 管理开放标准的组织不会偏爱 其中的某个实施者。
  4. 没有刻意的秘密:标准不得隐瞒 针对可互操作实施所必需的任何详细信息。

这些无可争议的理由足以说明为什么开放标准是优秀的了。 接下来,我们先来谈谈为什么 Prometheus 公开格式 OpenMetrics 的基础。在 PromCon 2018 和 KubeCon + CloudNativeCon North America 2018 的会谈中,Richard Hartmann 总结了 受 Prometheus 公开格式影响而创建开放标准的几点原因:

  • 大部分数据格式是专有的,或者很难实施, 亦或是两种情况都有
  • Prometheus 已成为云原生 指标监测的实际标准
  • 公开数据的易用性使得 兼容指标端点出现激增
  • Prometheus 的公开格式虽然是基于大量操作 经验,但一直是在少数人之中设计的
  • 其他一些项目和供应商在采用 “竞争性”产品中的某些功能时极为受挫

Prometheus 公开格式

您可以在 Prometheus Github 存储库中阅读有关公开格式的信息。现在,我们来看一个示例。 我有一个导出器, Oliver006 Redis 导出器,其在 /metrics 端点的端口 9121 上发布指标。 我在这里只介绍有关 Redis 的“每秒即时操作数”指标的信息。 有三行 需要阅读:

  1. 帮助文本
  2. 指标类型(在此用例中为仪表)
  3. 当前测量的 Redis 服务器(localhost 端口 6379),及其 当前读数(每秒操作数为 9 个)

roscigno-prometheus-exposition-format.png

Elastic 可观察性

我建议您阅读有关 Elastic 如何看待可观察性的文章,但其中 我最喜欢的部分是:

设计和构建“可观察”系统的目标在于, 确保当它在生产中运行时, 负责操作它的人员能够检测到不良行为(例如,服务停机、 错误、响应缓慢),并拥有可操作的信息, 以有效地确定根本原因(例如,详细的事件日志、 细粒度的资源使用信息,以及应用程序跟踪)。

我完全同意这种说法,它表明 我们需要所有日志、指标和跟踪信息,以运行、 修复和管理我们提供的服务。 Prometheus 是 可观察性中极其重要的一部分,因为它已被广泛采用 且拥有活跃的社区。 只有为“操作中产生”的符合常理的指标格式 扫除了采用障碍(无论这些障碍是真实的还是感知的), OpenMetrics 标准才会实现增值。

我交谈过的大部分人对使用 Elastic Stack (ELK) 进行日志分析都十分熟悉。 如果您不了解 Elastic Stack 还非常适合指标和 APM,请查看 指标 APM/分布式跟踪

我们认为,在 Elastic Stack 和 Prometheus 指标导出方式之间 进行深度集成很有意义,主要原因如下:

  • 在 Elasticsearch 中将指标与日志和 APM 合并, 并在 Kibana 中将它们关联起来。请查看来自 NS1 的 一个 用户案例,了解有关在 Elastic Stack 中合并日志与指标的信息。
  • 使用 Elasticsearch 作为长期存储,用于通过 Prometheus 服务器收集的指标, Prometheus 服务器目前 不支持原生集群。
  • 对分散在不同地理位置 的 Prometheus 实例的指标实现全球查看。

本博文的其余部分将详细描述我们如何实现这些 集成。

示例导出器

我的演示环境运行于 Google Kubernetes 引擎 (GKE) 中,所以我的应用程序、 Metricbeat 和 Prometheus 导出器都是在 Kubernetes 中运行。 下面 是一段 Oliver006 的清单,用于将 Redis 导出器部署 为 Redis 映像旁边的挎斗。 如您所见,导出器 在端口 9121 上发布指标,这是 Prometheus Redis 导出器的 默认分配的端口号

...
  - name: redis-exporter
    image: oliver006/redis_exporter:latest
    resources:
      requests:
        cpu:100m
        memory:100Mi
    ports:
    - containerPort:9121
...

GitHub 中的完整源代码

使用 Metricbeat Prometheus 模块收集指标

Metricbeat 是 Elastic 的轻量型指标采集器。 Metricbeat 随附的 Prometheus 模块可以采用三种方式 收集指标:

  1. 通过端口 9090 连接到 Prometheus 服务器, 并使用 Prometheus 联合 API 拉取已收集的指标 (以获得 Prometheus 收集的指标)
  2. 使用 /metrics 端点 通过端口 9090 连接到 Prometheus 服务器(Prometheus 自我监测)
  3. 连接到各个 Prometheus 导出器并解析 公开格式

至于您选择哪种方法收集指标,要取决于 您对 Prometheus 服务器的熟悉程度。

  • 如果您已经设置了 Prometheus 服务器来收集指标, 并希望直接查询这些指标以进行集成, 则可以从选项 (1) 和 (2) 入手。
  • 另一方面,如果您还没有 Prometheus 服务器, 或者不介意通过多个工具并行收集导出器, 则可以使用选项 (3)。

注意:上述某些 Metricbeat 功能在 Metricbeat 版本 7.0 中为公测版。 我们建议您 下载 7.0 公测版, 或从 https://www.docker.elastic.co/ 复制容器链接,并在非生产环境中运行公测版。

Prometheus 联合 API

一般来说,联合用于支持扩展、将数据集合并在一起,或在不同位置提供数据副本(用于灾难恢复)。 Prometheus 服务器提供一个 /federation 端点,Elastic 可以连接到此端点,以复制 Prometheus 出于上述原因而收集的指标。

...
  - module: prometheus
    period:10s
    hosts: ["prometheus-service.monitoring.svc.cluster.local:9090"]
    metrics_path: '/federate'
    query:
      'match[]': '{__name__!=""}'
...

GitHub 中的完整源代码

在上例中,查询设置为“具有非空名称的任何内容”。 您不需要获取所有内容,Prometheus 文档中包含了有关如何编写更具限制性的匹配条件的信息。 此外,该示例中将期间设置为每 10 秒连接到 Pometheus 服务器一次,我的演示服务器仅从少数 Pod 和 kube-state-metrics 收集指标,但您可能需要更改该时间间隔。

Prometheus 自我监测

Prometheus 提供一个 /metrics 端点,像导出器一样。 这样您就可以收集有关 Prometheus 服务器的指标。 该端点的配置如下:

...
  - module: prometheus
    period:10s
    hosts: ["prometheus-service.monitoring.svc.cluster.local:9090"]
    metrics_path: /metrics
...

GitHub 中的完整源代码

Prometheus 导出器收集

某一清单中的这段 YAML 用于部署一个 Metricbeat DaemonSet,告知 Metricbeat 自动发现 其中 kubernetes.labels.app == redis 的内容,并从该 Pod 的端口 9121 读取指标。 请记住,为 Redis 导出器容器设置的 containerPort 为 9121。

...
- condition.equals:
    kubernetes.annotations.prometheus.io/scrape: "true"
  config:
    - module: prometheus
      period:10s
      # Redis pods
      hosts: ["${data.host}:9121"]
      metrics_path: /metrics
...

部署 Metricbeat 后,任何满足条件 kubernetes.labels.app == redis 的 Pod 都会应用 Prometheus 模块, 并从 端口 9121 的导出器挎斗中收集指标。

但是,在 k8s 环境中怎能缺了元数据呢,对吗? 让我们用 元数据和 Beats 自动发现功能来一展身手。 请看下面这段代替 上述 YAML 的内容:

...
- condition.equals:
    kubernetes.annotations.prometheus.io/scrape: "true"
  config:
    - module: prometheus
      period:10s
      hosts: ["${data.host}:${data.kubernetes.annotations.prometheus.io/port}"]
      metrics_path: /metrics
...

GitHub 中的完整源代码

现在,我们寻找的不是 Redis pod 的导出器, 而是任何注释 kubernetes.annotations.prometheus.io/scrape 设置为 true 的 Pod 导出器。 这也是 Prometheus 自动发现的设置方式。 通常情况下,Metricbeat 自动发现由 elastic.co 命名空间中的注释驱动,但既然我们在讨论从 Prometheus 导出器读取,我们就应遵守与 Prometheus 关联的标准 k8s 注释。 如果您查看上述内容中的主机列表:

hosts: ["${data.host}:${data.kubernetes.annotations.prometheus.io/port}"]

您可以看到,我们不再硬编码端口 9121,因为 它是 Redis 导出器的端口。 注释 prometheus.io/port 设置为导出器的端口号。 为了完整起见, 下面提供一段 guestbook.yaml, 其中设置了这些注释:

...
kind:Deployment
metadata:
  name: redis-master
spec:
  replicas:1
  template:
    metadata:
      annotations:
        prometheus.io/scrape: "true"
        prometheus.io/port:"9121"
      labels:
        app: redis
...

GitHub 中的完整源代码

我提到过元数据在 k8s 环境中不可或缺吗? 那不是七十年代后期的一首歌吗?

通过可视化获得洞察力

虽然将数据引入 Elastic Stack 非常好,但您必须能够与数据进行交互。 在以下视频中,我们将看到如何使用由 Prometheus 收集(然后导入 Elastic Stack)的 Redis 指标,以及使用 Metricbeat 直接从 kube-state-metrics 收集的 Kubernetes 事件来构建有用的可视化。

如果您希望按照视频操作并获得更详细的说明,请 参阅 示例存储库

返回可观察性

在最后这部分,我们为 Oliver006 Redis 导出器公开的 关键 Redis 指标(每秒即时操作数) 创建了一个 Kibana 可视化。 我们的下一步是收集日志, 然后创建一个仪表板,并在 我们的应用程序中将日志和指标合并在一起。

如需了解如何在 Kubernetes 环境中收集日志, 我建议您按照 elastic/examples GitHub 存储库中的说明进行操作。 只需几分钟,即可 让 Filebeat、Metricbeat 和 Packetbeat 收集数据,并 发布到 Elasticsearch。 使用随附的各种 Beats 的示例仪表板, 您可以随意 为 Prometheus 数据创建自己的可视化,并混合使用这些可视化, 以创建适合您工作方式的仪表板。如果您遇到任何问题或希望讨论可观察性,请访问 讨论论坛。