作者:来自 Elastic Bahubali Shetti

使用一个配置块,将你的 Kubernetes 集群中的 Prometheus 指向 Elastic Observability。PromQL 可以保持不变地运行,保留你的 PromQL,不产生基数计费。
现在是凌晨 2:14,你的 Kubernetes 集群触发了一条告警。你打开 Grafana 查看内存图表,然后打开 Loki 查看容器日志,接着打开 APM 工具检查上游服务是否已经出现性能下降。三个标签页,11 分钟之后,你得到了一个假设,而用于验证它的那个标签,在上个季度为了降低指标账单已经被删除。
Elasticsearch 现在可以在与日志和追踪相同的列式后端中存储 Prometheus 指标,每个数据点仅需 3.75 字节,并且不会产生自定义指标额外费用。图表、日志和追踪都可以通过一种查询语言进行查询。
使用一个现有的 Kubernetes 集群(本文示例使用 AWS EKS):通过一个配置块将 Prometheus 指向 Elastic,无需构建任何仪表板即可在 Discover 中查看所有指标,运行大部分现有 PromQL 而无需修改,探索 ES|QL 如何突破 PromQL 的表达能力限制,最后使用相同的查询语言读取日志。
你的采集方式不会发生任何变化。你的抓取配置、重新标记规则以及服务发现配置都可以原样迁移。大部分 PromQL 也可以继续使用 ------ 第 5 步中的覆盖说明会介绍其中的差异。
第 1 步:从 Elastic Observability 获取 Prometheus 端点和 API 密钥
你需要 Elastic Cloud Serverless 或 Elastic Cloud Hosted。这两者都无需配置即可提供 Prometheus 端点。
Serverless 是最快的开始方式。登录 cloud.elastic.co 并创建一个 Observability 项目。无需进行容量规划,也无需进行资源配置。
Elastic Cloud Hosted 对本文中的所有内容同样适用,并且当你需要特定的技术栈版本、特定区域拓扑,或者托管集群提供的部署级控制能力时,它是更合适的选择。
在 UI 中查找 Prometheus 端点并创建 API 密钥
要获取 Prometheus 端点和 API 密钥,请进入 Kibana,点击左侧导航栏中的 Add data。

对于 Prometheus,滚动到页面底部的 Connect directly to the endpoint ,然后选择 Prometheus 标签页。

需要复制两项内容:
端点。 它看起来像 https://my-observability-project-xxx.ingest.us-west-2.aws.elastic.cloud 。注意其中的 .ingest. 主机名。它与你的 Elasticsearch 搜索端点或 Kibana URL 不是同一个主机。
API 密钥。 点击 Create key。在关闭对话框之前复制该值,因为之后无法再次获取。
如果你希望手动设置权限范围,可以使用 Open in API keys 打开完整编辑器。指标写入所需的最低权限如下:
bash
`
1. {
2. "ingest": {
3. "indices": [
4. {
5. "names": ["metrics-*"],
6. "privileges": ["auto_configure", "create_doc"]
7. }
8. ]
9. }
10. }
`AI写代码
第 2 步:确保 Prometheus 正在抓取你的 Kubernetes 集群
Prometheus 应该已经在抓取你的集群。
如果还没有,最快的方式是使用 kube-prometheus-stack Helm chart,它可以通过一个命令安装 Prometheus Operator、Prometheus 本身、kube-state-metrics 和 node-exporter:
arduino
`
1. helm repo add prometheus-community https://prometheus-community.github.io/helm-charts
2. helm repo update
4. helm install prometheus prometheus-community/kube-prometheus-stack \
5. --namespace monitoring --create-namespace
`AI写代码
这会提供本文后续部分中看到的指标:
-
cAdvisor 容器指标(
container_cpu_usage_seconds_total、container_memory_working_set_bytes) -
kube-state-metrics 集群对象(
kube_deployment_spec_replicas、kube_daemonset_status_number_ready)。
第 3 步:配置 Prometheus 远程写入到第 1 步中的 Prometheus 端点
Elasticsearch 原生实现了 Prometheus Remote Write 协议。不需要适配器、不需要 sidecar,也不需要转换层。你只需要添加一个配置块,数据就会在下一个抓取周期开始流入。
如果你运行 Prometheus Operator
Operator 不会读取你手动编写的 prometheus.yml 。它会根据 Prometheus 自定义资源生成配置文件,而其中的 authorization.credentials 是对 Kubernetes Secret 的引用,而不是内联值。首先创建这个 Secret:
ini
`
1. kubectl create secret generic elastic-prometheus \
2. --namespace monitoring \
3. --from-literal=api_key='YOUR_API_KEY'
`AI写代码
然后在 values.yaml 中引用它:
markdown
`
1. prometheus:
2. prometheusSpec:
3. remoteWrite:
4. - url: "https://my-observability-project-xxxx.ingest.us-west-2.aws.elastic.cloud:443/api/v1/write"
5. authorization:
6. type: ApiKey
7. credentials:
8. name: elastic-prometheus
9. key: YOUR_API_KEY
`AI写代码
然后应用它:
markdown
`
1. helm upgrade prometheus prometheus-community/kube-prometheus-stack \
2. --namespace monitoring \
3. -f values.yaml
`AI写代码
使用 prometheus.yml 配置 Prometheus remote write
同样,在 prometheus.yml 中:
yaml
`1. remote_write:
2. - url: "https://YOUR_ES_ENDPOINT/_prometheus/metrics/node/eks/api/v1/write"
3. authorization:
4. type: ApiKey
5. credentials: YOUR_API_KEY` AI写代码
如果你运行 Grafana Alloy,请使用以下配置
ini
`1. prometheus.remote_write "elasticsearch" {
2. endpoint {
3. url = "https://YOUR_ES_ENDPOINT/_prometheus/metrics/node/eks/api/v1/write"
4. headers = {"Authorization" = "ApiKey YOUR_API_KEY"}
5. }
6. }` AI写代码
remote write URL 如何映射到 Elasticsearch 数据流
你不需要在任何地方指定索引。在 remote_write 配置中,请求负载中没有索引字段,也没有数据流字段。Elasticsearch 会根据写入路径推导目标数据流,并在收到第一个样本时创建它。/metrics/ 后面的两个路径段分别代表数据集和命名空间:
| URL | 数据流 |
|---|---|
/_prometheus/api/v1/write |
metrics-generic.prometheus-default |
/_prometheus/metrics/{dataset}/api/v1/write |
metrics-{dataset}.prometheus-default |
/_prometheus/metrics/{dataset}/{namespace}/api/v1/write |
metrics-{dataset}.prometheus-{namespace} |
上面的示例使用 /metrics/node/eks/ ,它会写入 metrics-node.prometheus-eks。这是你将在下一步 Discover 中看到的数据流。使用数据集和命名空间可以区分生产环境和预发布环境,或者为每个集群和每个团队提供具有独立保留策略和降采样策略的数据流。
如果你更希望保持简单的 /api/v1/write URL,也可以通过每个时间序列进行路由:为时间序列添加 data_stream_dataset 和 data_stream_namespace 标签,它们的优先级高于 URL 路径。这两个字段属于控制字段,因此它们会路由文档,但不会存储在其 labels 对象中。
Elasticsearch 会自行安装 metrics-*.prometheus-* 的索引模板。你不需要创建模板或映射。
Prometheus 指标在 Elastic Observability 中的形式
每个 Prometheus 样本都会变成一个文档。标签会成为作为时间序列维度的 keyword 字段。数值会存储在 metrics.<metric_name> 下:
bash
`
1. {
2. "@timestamp": "2026-07-02T10:30:00.000Z",
3. "data_stream": {
4. "type": "metrics",
5. "dataset": "node.prometheus",
6. "namespace": "eks"
7. },
8. "labels": {
9. "__name__": "container_memory_working_set_bytes",
10. "pod": "checkout-7d9f6c4b8-x2kqp",
11. "namespace": "oteldemo",
12. "container": "checkout",
13. "node": "ip-10-0-3-14.us-west-2.compute.internal"
14. },
15. "metrics": {
16. "container_memory_working_set_bytes": 36700160
17. }
18. }
`AI写代码
现在需要了解的一个注意事项。 Elasticsearch 会根据指标名称推断某个指标是 counter 还是 gauge。以 _total 、_sum 、_count 或 _bucket 结尾的名称会被识别为 counter。其他所有指标都会被识别为 gauge。对于 container_cpu_usage_seconds_total 和 container_memory_working_set_bytes ,这种推断是正确的。但对于你的环境中任何不遵循 Prometheus 命名规范的指标,这种推断可能是错误的,而错误分类的指标会被本应支持它的函数拒绝:RATE(my_metric::counter) 只能用于 counter。第 6 步会介绍如何覆盖这种推断。
当前限制。 仅支持 Remote Write v1。经典 histogram 和 summary 通过它们的 _bucket 、_sum 和 _count 序列获得支持,并分别映射到正确的指标类型。原生(稀疏)histogram 和 exemplars 会随着 Remote Write v2 到来,目前已在路线图中。Staleness 标记不会被存储或遵循,非有限值(NaN、Infinity)会被静默丢弃。完整列表请查看 Prometheus remote write ingest 文档。
第 4 步:验证 Prometheus 指标是否正在流入 Elasticsearch
不要先去构建仪表板。首先确认数据管道是否正常,而 Elastic 可以通过一个命令完成验证。
在 Kibana 中,打开 Discover,将查询编辑器切换到 ES|QL,然后输入你刚刚写入的数据流名称:
go
`TS metrics-node.prometheus-eks` AI写代码

这就是完整的查询。Discover 会读取数据流,找到其中的每个指标,并将每个指标渲染为独立的时间序列图表。50 个指标,50 个图表,不需要构建仪表板,也不需要为每个指标编写查询。它会读取指标类型并正确绘制图表:gauge 使用平均值,counter 使用速率,histogram 使用 p95 分布。
你也可以不用输入任何内容直接到达这里。在 Kibana 中选择 Observability → Streams ,会列出集群中的所有数据流。带有 Time series 标记的数据流表示它是一个时间序列数据流。点击 View in Discover ,系统会自动为你填入 TS 查询。
这是你的数据摄取健康检查。需要关注三件事:
-
数据正在流入。 存在最新且连续的值。不是出现间断,也不是一条一小时前就停止的曲线。
-
数值合理。 小型容器的内存应该是几十 MB。CPU 应该是核心使用量的一部分。网络字节数应该反映真实流量。
-
覆盖范围符合预期。 如果缺少
kube_pod_container_status_restarts_total,说明你的 kube-state-metrics 抓取配置有问题,你应该现在发现这个问题,而不是等到基于它构建告警时才发现。
在判断任何问题之前,扩大时间选择范围。一个安静时段内的 15 分钟窗口可能会让健康的数据看起来像一条平线。
要列出实际存在数据的内容,而不是映射中声明的内容:
go
`TS metrics-node.prometheus-eks | METRICS_INFO | SORT metric_name` AI写代码
图表上方的 No dimensions selected 控件可以让你根据标签拆分每个图表:选择 pod,每个图表会按照 pod 拆分成一条独立的时间序列。
第 5 步:在 Elastic Observability 中对 Prometheus 指标运行 PromQL 查询
如果你的团队编写 PromQL,就继续编写 PromQL。PROMQL 是 ES|QL 中的源命令,与 FROM 和 TS 并列,并且可以在所有运行 ES|QL 的地方执行:Discover、仪表板面板以及告警规则。
它不会运行一个独立的引擎。它会解析表达式,将每个函数解析为对应的 ES|QL 等价形式,并构建一个 TS 执行计划,因此你的 PromQL 可以获得与原生 ES|QL 相同的向量化并行执行能力。
当前限制。 PROMQL 已在 Elastic Cloud Serverless 中正式发布,并且在 Elastic Stack 9.4 中作为技术预览功能提供。根据热门 Grafana OSS 仪表板进行测试,其查询覆盖率超过 80%。在直接粘贴仪表板查询之前,需要了解以下差异:
histogram_quantile 尚未实现,这一点最重要,因为几乎所有延迟仪表板都使用它计算 p95;分组修饰符(on(...) group_left(...) )以及集合运算符 or 、and 和 unless 不受支持;此外,predict_linear 、label_join 和 label_replace 目前也不可用。时间桶会按照固定日历边界对齐,而不是根据查询开始时间对齐,因此短时间范围或较大的步长可能会与 Prometheus 存在轻微差异。请查看当前的 PROMQL 命令参考 获取完整列表。
CPU:使用 PromQL 查询每个 pod 的 CPU 速率
这是按照 pod 分组的容器每秒 CPU 使用速率。当某个地方出现高负载时,这是你首先查看的内容:
scss
`PROMQL sum by (pod) (rate(container_cpu_usage_seconds_total[5m]))` AI写代码
也可以按照 namespace 拆分,用于查找哪个团队正在消耗集群资源:
scss
`PROMQL sum by (namespace) (rate(container_cpu_usage_seconds_total[5m]))` AI写代码

注意返回的内容:有一个 pod 列、一个 step 列,以及一个以表达式本身命名的值列。这是一个普通的 ES|QL 表,这正是其核心,也是第 6 步构建的基础。
内存:使用 PromQL 查询工作集和 RSS
工作集(working set)是与 OOM 风险相关的重要指标。它是内核用于计算限制的数值,并且它不同于总分配内存:
scss
`PROMQL sum by (pod) (container_memory_working_set_bytes)` AI写代码
常驻集(resident set),用于对比,当你需要区分真正的内存泄漏和页面缓存时:
scss
`PROMQL sum by (pod) (container_memory_rss)` AI写代码

网络:使用 PromQL 查询每个 pod 的接收速率
scss
`PROMQL sum by (pod) (rate(container_network_receive_bytes_total[5m]))` AI写代码

集群对象:使用 PromQL 查询副本数量
查看声明的副本数未达到预期的 Deployment:
go
`PROMQL kube_deployment_spec_replicas` AI写代码
有一个值得特别指出的便利之处:在 Prometheus 中,每个查询都需要显式指定 start 、end 和 step 。而在 Kibana 中,你无需指定这三个参数。时间选择器会提供时间范围,Kibana 会自动推导 step,这就是为什么上面的每个查询都只有一行。
使用 PromQL 查询构建 Kibana 仪表板
上面的每个查询都可以作为一个仪表板面板。在 Discover 中点击 Save ,或者进入 Dashboards → Create → Add panel → ES|QL,然后将查询粘贴进去即可。
时间选择器会自动驱动 start 、end 和 step,因此一个面板只需编写一次,就可以适用于任意缩放级别。

四个面板,四条单行 PromQL 查询,没有任何转换步骤。如果你是从 Grafana 迁移过来的,这与你已有的仪表板完全相同,大约五分钟就能重新构建完成。如果你根本不想重新构建,也可以继续使用 Grafana,并将现有的 Prometheus 数据源指向 Elasticsearch。文章末尾会介绍这种方式。
第 6 步:使用 ES|QL 查询 Prometheus 指标,突破 PromQL 的表达能力
ES|QL 中的 PROMQL 命令会编译为 TS。下面这两个查询是等价的:
scss
`PROMQL sum by (pod) (rate(container_cpu_usage_seconds_total[5m]))` AI写代码
scss
`
1. TS metrics-node.prometheus-eks
2. | WHERE TRANGE(1h)
3. | STATS SUM(RATE(metrics.container_cpu_usage_seconds_total, 5m)) BY labels.pod, TBUCKET(1m)
`AI写代码

第二种形式才是真正让指标不再是一个与日志和追踪分离的世界------真正实现关联查询(join)的地方。
Top-N 和过滤
TS 查询返回的是一个普通的 ES|QL 表,因此后续可以直接使用 SORT 、LIMIT 和 WHERE 。Top-N 不需要任何特殊函数,也不需要 topk 。查找内存使用量最高的 10 个 pod,只需要一个 SORT 和一个 LIMIT:
markdown
``
1. TS metrics-node.prometheus-eks
2. | WHERE `labels.pod` IS NOT NULL
3. | STATS mem = SUM(metrics.container_memory_working_set_bytes) BY `labels.pod`
4. | SORT mem DESC
5. | LIMIT 10
``AI写代码
过滤也是同样的方式,对聚合后的列使用 WHERE 即可。例如,只显示内存超过 50 MB 的 pod:
markdown
``
1. TS metrics-node.prometheus-eks
2. | WHERE `labels.pod` IS NOT NULL
3. | STATS mem = SUM(metrics.container_memory_working_set_bytes) BY `labels.pod`
4. | WHERE mem > 50000000
5. | SORT mem DESC
``AI写代码

实际上,你也可以对 PROMQL 查询的结果继续使用管道(pipe),并通过普通的 ES|QL 进行后处理。
内存使用量与请求值的对比
在发生内存问题时,一个非常有用的问题是:哪些 pod 的内存使用量已经超过了它们申请的资源?超过了多少?
这个查询组合了两个指标,而 ES|QL 可以通过一次扫描和过滤聚合来表达,每个指标使用一个 MAX:
markdown
``
1. TS metrics-node.prometheus-eks
2. | WHERE `labels.pod` IS NOT NULL AND `labels.namespace` IS NOT NULL
3. | STATS
4. used_memory = MAX(metrics.container_memory_working_set_bytes),
5. requested_memory = MAX(metrics.kube_pod_container_resource_requests)
6. WHERE `labels.resource` == "memory"
7. BY `labels.pod`, `labels.namespace`, time_bucket = TBUCKET(5 minute)
8. | EVAL pct_of_request = 100 * used_memory / requested_memory
9. | WHERE pct_of_request > 80
10. | SORT pct_of_request DESC
11. | LIMIT 100
``AI写代码
附加在 requested_memory 上的 WHERE 是一个过滤聚合(filtered aggregation):kube_pod_container_resource_requests 在 labels.resource 维度下同时包含 CPU 和内存,因此该过滤条件仅保留内存相关的记录,从而使计算得到的比例是真正的"内存使用量 / 内存请求值"。
每个指标都存储在各自独立的文档中;共享的 BY 键会将两个聚合结果落到同一行中。

第 7 步:使用 ES|QL 同时查询 Prometheus 指标和日志
在前面的几个章节中,我们使用了 ES|QL 和 PromQL 来分析指标。ES|QL 同样可以读取日志。下面是一个针对运行在该集群上的 OpenTelemetry demo 的简单查询:
scss
`
1. FROM logs-*
2. | WHERE TRANGE(30m) AND kubernetes.pod.name == "checkout-9656cbd88-fsr9v"
3. | STATS events = COUNT(*) BY log.level, TBUCKET(1m)
4. | SORT events DESC
`AI写代码

同一个编辑器,同一个用于查询指标的时间选择器。唯一变化的是源命令,从 TS 变成了 FROM,现在你查看的是按分钟、按日志级别统计的日志数量。一个查询语言即可覆盖指标和日志,无需切换标签页,也无需使用第二个工具。
现在 Elastic Observability 中已经具备的能力
Prometheus 通过一个配置块即可将数据写入 Elastic。每个指标都会自动在 Discover 中渲染,无需构建仪表板。你现有的大多数 PromQL 查询都可以直接运行,而 ES|QL 则更进一步:支持 Top-N、过滤以及跨指标比率计算,并且可以继续通过管道传递给 ES|QL 的其他命令。指标和日志可以在同一个窗口中使用同一种查询语言进行查询。
整个过程中,你无需删除任何标签,也不会因为高基数(cardinality)而产生额外费用。
后续步骤:Grafana、仪表板迁移和 OpenTelemetry
-
如果你希望继续使用 Grafana,就继续使用。 Elasticsearch 提供了兼容 Prometheus 的读取 API,地址为
<endpoint>/_prometheus。将 Grafana 现有的 Prometheus 数据源指向该地址,并将数据源的httpMethod设置为GET,你的 PromQL 仪表板即可继续工作。保留 Grafana,替换 Mimir。 -
迁移你的 Grafana 仪表板。 当你准备完全迁移到 Kibana,而不是仅仅让 Grafana 连接 Elasticsearch 时,可以使用 Observability Migration Platform 。它能够将 Grafana 仪表板、面板和告警规则转换为 Kibana 原生格式。它是一个与数据源无关的 CLI 工具(
obs-migrate),能够自动转换可转换的内容,并标记需要人工处理的部分,同时生成迁移报告,展示哪些内容已成功转换,以及哪些地方仍存在语义差异,确保不会静默丢失任何内容。相关的迁移演练涵盖了从 Grafana 和 Datadog 到 Kibana 的完整迁移流程。 -
想要添加 OpenTelemetry? 如果你同时使用 OpenTelemetry,或者希望使用 OTel Collector 而不是 Prometheus 进行采集,请阅读第 2 部分。两种方式的数据都会写入同一个存储,并且可以使用相同的查询进行分析。
开始免费试用: cloud.elastic.co/registratio...
文档: Elastic Observability solution overview | Elastic Docs
常见问题
如何将 Prometheus 指标发送到 Elasticsearch?
在 Prometheus 配置中添加一个 remote_write 配置块,将其指向 https://<YOUR_ES_ENDPOINT>/_prometheus/metrics/{dataset}/{namespace}/api/v1/write ,并添加 Authorization: ApiKey <YOUR_KEY> 请求头即可。Elasticsearch 原生支持 Prometheus Remote Write v1 协议,无需任何 adapter 或 sidecar。
我可以在 Elasticsearch 中运行现有的 PromQL 查询吗?
大多数情况下可以。ES|QL 包含 PROMQL 源命令,可直接接受标准 PromQL 表达式。在热门 Grafana OSS 仪表板上的测试覆盖率超过 80%。该功能已在 Elastic Cloud Serverless 正式发布,并作为 Elastic Stack 9.4 的技术预览提供。
目前 histogram_quantile 、predict_linear 、label_join 和 label_replace 尚未实现;分组修饰符以及集合运算符 or 、and 和 unless 也暂不支持。
Elasticsearch 是否会根据 Prometheus 指标的 cardinality 收费?
不会。Elasticsearch 以每个数据点 3.75 字节的存储效率保存 Prometheus 指标,不会根据 cardinality 收费,也没有自定义指标费用,无论你的指标包含多少种唯一标签组合。
如何将 Prometheus 指标路由到 Elasticsearch 中不同的数据流?
Remote Write URL 中 /metrics/ 后面的两个路径段分别指定 dataset 和 namespace。例如,/metrics/node/eks/api/v1/write 会写入 metrics-node.prometheus-eks。
你也可以针对每个时间序列,通过 data_stream_dataset 和 data_stream_namespace 标签进行路由,它们的优先级高于 URL 路径。
Elasticsearch 支持哪些 Prometheus 指标类型?
Elasticsearch 支持 Remote Write v1,包括 counter、gauge、经典 histogram 和 summary。
counter 与 gauge 的分类会根据指标名称自动推断:以 _total 、_sum 、_count 或 _bucket 结尾的名称会被识别为 counter,其余则识别为 gauge。
原生 histogram 和 exemplars 需要 Remote Write v2,目前已在路线图中。
我可以在 Elasticsearch 中同时查询 Prometheus 指标和日志吗?
可以。ES|QL 可以在同一个查询编辑器、同一个时间选择器中同时读取时间序列指标和日志。只需将 TS metrics-node.prometheus-eks 改为 FROM logs-*,语法保持一致,窗口保持一致,也无需使用第二个工具。
相关阅读
本文中描述的任何特性或功能的发布时间和交付时间均由 Elastic 自行决定。当前尚未提供的任何特性或功能,可能无法按时交付,或者根本不会交付。