为什么要搞这个
手上有套 kube-prometheus-stack 跑在 kind 集群里,Prometheus v3.9.1。一直听说 VictoriaMetrics 压缩率比 Prometheus 高 7 倍,内存占用也低不少,正好有空从零搭一套,顺便把告警链路跑通。
因为是学习用,最终目标是替代现有的 Prometheus,所以直接上 k8s-stack 全家桶。不过先从最简单的单机版开始,一步步来。
单机版部署
clone helm chart:
1 | # 国内 clone GitHub 需要代理 |
进 chart 目录,只改一个字段试水:
1 | # values.yaml |
1 | kubectl create namespace victoria-metrics |
然后就报错了:
1 | Error: found in Chart.yaml, but missing in charts/ directory: victoria-metrics-common |
git clone 只拉源码,不会自动下载 helm chart 的依赖包。又是一个”我以为clone就够了”的教训。
1 | # 先拉取依赖 |
这次成功了:
1 | NAME: victoria-metrics-single |
kind 集群需要 port-forward 才能从外部访问:
1 | kubectl port-forward --address 0.0.0.0 -n victoria-metrics svc/victoria-metrics-single-server 8428:8428 & |
访问 http://192.168.10.100:8428/vmui,VMUI 出来了,长得跟 Prometheus 的查询界面差不多。

Targets 页面也类似 Prometheus 的 target 界面:

其他入口直接访问 8428 端口就能看到:

接入现有监控栈
单机版跑起来了,下一步让它接 Prometheus 的数据。思路很简单:Prometheus 继续负责采集,通过 remote_write 把数据写一份到 VM,Grafana 查 VM 的数据。
kube-prometheus-stack 的 values.yaml 加一行:
1 | prometheus: |
Grafana 里加个新数据源,类型选 Prometheus,URL 指向 VM。
1 | Prometheus (v3.9.1) ──remote_write──→ VM (8428) |
数据链路通了,Grafana 查 VM 数据源已经有数据:

这里有个坑:VM 的 scrape.enabled 和 Prometheus 的 remote_write 不能同时开。开了 scrape,VM 自己也采集一遍,加上 remote_write 过来的数据,同一批指标写两遍,浪费存储。别问我怎么知道的。 正确做法是二选一:
| 模式 | scrape.enabled | remote_write |
|---|---|---|
| VM 自己采集 | ✅ 开 | ❌ 不需要 |
| Prometheus 采集 → VM 存储 | ❌ 关 | ✅ 开 |
MetricsQL:PromQL 的超集
VM 的查询语言叫 MetricsQL,兼容 PromQL 但加了不少好东西。挑几个实用的:
WITH 表达式——相当于 SQL 的 CTE,复杂查询不用复制粘贴:
1 | WITH ( |
默认 range selector——rate(http_requests_total) 不用写 [5m],自动用 Grafana 的 $__interval,切时间范围时自动适配。
rollup 函数族——一个函数搞定多种聚合:
1 | rollup(metric, "max") # 区间最大值 |
keep_last_value——采集丢点时用前一个有效值填充,图表没有锯齿。
管道语法——从左到右读,逻辑更清晰:
1 | sum by (instance) (rate(node_cpu_seconds_total{mode!="idle"})) | topk(5) |
| 特性 | PromQL | MetricsQL |
|---|---|---|
| 默认 range | ❌ 必须写[5m] | ✅ 自动$__interval |
| WITH 表达式 | ❌ | ✅ |
| rollup 函数族 | ❌ | ✅ |
| keep_last_value | ❌ | ✅ |
| 管道语法 | ❌ | ✅ |
切到 k8s-stack 全家桶
单机版用够了,想上 vmalert 告警。k8s-stack 一个 chart 全搞定:Operator + vmcluster + vmagent + vmalert + Grafana。
1 | # 删掉单机版 |
values.yaml 的关键改动:
1 | # 关单机,开集群 |
集群版的三组件:vminsert 负责写入路由,vmstorage 负责存储,vmselect 负责查询。三者可以独立扩缩容。学习环境各一个副本够了。
1 | helm upgrade --install victoria-metrics-k8s-stack ./ -f values.yaml -n victoria-metrics |
部署完之后 port-forward 几个关键端口:
1 | # vmselect — 查询界面(VMUI) |
集群版的 VMUI 路径跟单机版不一样,要带租户 ID:http://192.168.10.100:8481/select/0/vmui。第一次访问直接 404,看了报错才明白。
Operator 模式
k8s-stack 用的是 Operator 模式,跟 kube-prometheus-stack 的套路一模一样:
| kube-prometheus-stack | victoria-metrics-k8s-stack | |
|---|---|---|
| 添加监控目标 | ServiceMonitor | VMServiceScrape |
| 配置告警规则 | PrometheusRule | VMRule |
而且 Operator 自动兼容 Prometheus Operator 的 CRD,从 kube-prometheus-stack 迁移过来基本不用改。也就是说你已有的 ServiceMonitor 和 PrometheusRule,Operator 会自动转成 VM 对应的 CRD。
告警实战:process-exporter + stress
我的宿主机上跑着 process-exporter(systemd 方式,端口 9256),采集所有进程的内存、CPU 等指标。现在要把它接入 VM,然后写一条内存告警规则。
让 vmagent 采集外部目标
k8s-stack 用 Operator 模式,加外部目标不能用 extraScrapeConfigs,得创建 VMStaticScrape CRD:
1 | # process-exporter-scrape.yaml |
1 | kubectl apply -f process-exporter-scrape.yaml |
去 vmagent 的 targets 页面确认状态是 UP:

写 VMRule
查了一下 process-exporter 的指标,关键的是 namedprocess_namegroup_memory_bytes,标签 memtype="resident" 是实际内存占用。
机器上内存最高的是 milvus(约 5.3GB),阈值设在 5GB:
1 | # process-memory-alert.yaml |
1 | kubectl apply -f process-memory-alert.yaml |
stress 压测触发告警
1 | stress --vm 1 --vm-bytes 6500M --timeout 600s |
等了一两分钟,vmalert 页面上 ProcessHighMemory 变成 firing 了:

触发的是 milvus(5.3GB),stress 也在 pending 状态(resident 在 5-6GB 之间波动)。
告警链路验证通过:
1 | process-exporter(宿主机) → vmagent(K8s) → VM(vmstorage) → vmalert → firing ✅ |
邮件通知
告警触发了但没通知等于白搭。vmalert 会把 firing 的告警推给 Alertmanager,Alertmanager 负责发通知。
在 values.yaml 的 alertmanager.config 下配 SMTP:
1 | alertmanager: |
踩了个坑:values.yaml 里有两个 receivers: 段,YAML 不合并重复 key,后面的直接覆盖前面的。改了半天发现配置没生效,最后发现是被自己的 YAML 坑了。 删掉第二个就好了。
helm upgrade 之后再跑一次 stress,QQ 邮箱收到告警邮件:

整体链路
从零到告警邮件收到,整个链路跑通了:
1 | 采集(process-exporter/vmagent) → 存储(VM) → 查询(MetricsQL) → 告警(vmalert) → 通知(Alertmanager → 邮件) |
后面要做的事:存储压缩率实测、vmbackup 备份恢复、完全替代 Prometheus。
本文由 OpenClaw AI 助手根据作者的学习过程,模仿作者的写作风格自动生成。