搜索中...
🔍

未找到相关结果

Akemi

VictoriaMetrics从零到告警邮件实战

字数统计: 1.8k阅读时长: 8 min
2026/06/01

为什么要搞这个

手上有套 kube-prometheus-stack 跑在 kind 集群里,Prometheus v3.9.1。一直听说 VictoriaMetrics 压缩率比 Prometheus 高 7 倍,内存占用也低不少,正好有空从零搭一套,顺便把告警链路跑通。

因为是学习用,最终目标是替代现有的 Prometheus,所以直接上 k8s-stack 全家桶。不过先从最简单的单机版开始,一步步来。

单机版部署

clone helm chart:

1
2
3
4
5
6
7
8
9
10
11
# 国内 clone GitHub 需要代理
export http_proxy="http://192.168.10.238:7897"
export https_proxy="http://192.168.10.238:7897"

git clone https://github.com/VictoriaMetrics/helm-charts.git

unset http_proxy
unset https_proxy

mv helm-charts victoria-metrics
cd victoria-metrics/charts/victoria-metrics-single/

进 chart 目录,只改一个字段试水:

1
2
3
4
# values.yaml
server:
scrape:
enabled: true # 开启自监控抓取
1
2
kubectl create namespace victoria-metrics
helm upgrade --install victoria-metrics-single . -f values.yaml -n victoria-metrics

然后就报错了:

1
Error: found in Chart.yaml, but missing in charts/ directory: victoria-metrics-common

git clone 只拉源码,不会自动下载 helm chart 的依赖包。又是一个”我以为clone就够了”的教训。

1
2
3
4
5
# 先拉取依赖
helm dependency build

# 再安装
helm upgrade --install victoria-metrics-single . -f values.yaml -n victoria-metrics

这次成功了:

1
2
3
4
5
NAME: victoria-metrics-single
LAST DEPLOYED: Mon Jun 1 10:08:44 2026
NAMESPACE: victoria-metrics
STATUS: deployed
REVISION: 1

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 的查询界面差不多。

VMUI查询界面

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

Targets页面

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

8428端口入口

接入现有监控栈

单机版跑起来了,下一步让它接 Prometheus 的数据。思路很简单:Prometheus 继续负责采集,通过 remote_write 把数据写一份到 VM,Grafana 查 VM 的数据。

kube-prometheus-stack 的 values.yaml 加一行:

1
2
3
4
prometheus:
prometheusSpec:
remoteWrite:
- url: http://victoria-metrics-single-server.victoria-metrics.svc.cluster.local:8428/api/v1/write

Grafana 里加个新数据源,类型选 Prometheus,URL 指向 VM。

1
2
3
Prometheus (v3.9.1) ──remote_write──→ VM (8428)

Grafana (12.3.1) ──────────────────────┘

数据链路通了,Grafana 查 VM 数据源已经有数据:

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
2
3
4
5
WITH (
errors = sum(rate(http_requests_total{status=~"5.."})),
total = sum(rate(http_requests_total))
)
errors / total * 100

默认 range selector——rate(http_requests_total) 不用写 [5m],自动用 Grafana 的 $__interval,切时间范围时自动适配。

rollup 函数族——一个函数搞定多种聚合:

1
2
rollup(metric, "max")    # 区间最大值
rollup(metric, "avg") # 区间平均值

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
2
3
4
5
# 删掉单机版
helm delete victoria-metrics-single -n victoria-metrics

cd /root/victoria-metrics/charts/victoria-metrics-k8s-stack/
helm dependency build

values.yaml 的关键改动:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
# 关单机,开集群
vmsingle:
enabled: false
vmcluster:
enabled: true
spec:
replicationFactor: 1 # 学习环境不需要副本
vmstorage:
replicaCount: 1
vmselect:
replicaCount: 1
vminsert:
replicaCount: 1

# 关 node-exporter(端口跟 Prometheus 冲突,9100被占了)
prometheus-node-exporter:
enabled: false

集群版的三组件:vminsert 负责写入路由,vmstorage 负责存储,vmselect 负责查询。三者可以独立扩缩容。学习环境各一个副本够了。

1
helm upgrade --install victoria-metrics-k8s-stack ./ -f values.yaml -n victoria-metrics

部署完之后 port-forward 几个关键端口:

1
2
3
4
5
6
7
8
# vmselect — 查询界面(VMUI)
kubectl port-forward --address 0.0.0.0 -n victoria-metrics svc/vmselect-victoria-metrics-k8s-stack 8481:8481 &

# vmalert — 告警规则界面
kubectl port-forward --address 0.0.0.0 -n victoria-metrics svc/vmalert-victoria-metrics-k8s-stack 8080:8080 &

# vmagent — 采集目标界面
kubectl port-forward --address 0.0.0.0 -n victoria-metrics svc/vmagent-victoria-metrics-k8s-stack 8429:8429 &

集群版的 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
2
3
4
5
6
7
8
9
10
11
# process-exporter-scrape.yaml
apiVersion: operator.victoriametrics.com/v1beta1
kind: VMStaticScrape
metadata:
name: process-exporter
namespace: victoria-metrics
spec:
jobName: process-exporter
targetEndpoints:
- targets:
- "192.168.10.100:9256"
1
kubectl apply -f process-exporter-scrape.yaml

去 vmagent 的 targets 页面确认状态是 UP:

vmagent targets页面

写 VMRule

查了一下 process-exporter 的指标,关键的是 namedprocess_namegroup_memory_bytes,标签 memtype="resident" 是实际内存占用。

机器上内存最高的是 milvus(约 5.3GB),阈值设在 5GB:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
# process-memory-alert.yaml
apiVersion: operator.victoriametrics.com/v1beta1
kind: VMRule
metadata:
name: process-memory-alert
namespace: victoria-metrics
spec:
groups:
- name: process-memory
rules:
- alert: ProcessHighMemory
expr: namedprocess_namegroup_memory_bytes{memtype="resident"} > 5000000000
for: 1m
labels:
severity: warning
annotations:
summary: "进程 {{ $labels.groupname }} 内存占用过高"
description: "进程 {{ $labels.groupname }} 的 resident 内存为 {{ $value | humanize1024 }},超过 5GB 阈值"
1
kubectl apply -f process-memory-alert.yaml

stress 压测触发告警

1
stress --vm 1 --vm-bytes 6500M --timeout 600s

等了一两分钟,vmalert 页面上 ProcessHighMemory 变成 firing 了:

vmalert 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
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
alertmanager:
config:
global:
smtp_smarthost: 'smtp.163.com:25'
smtp_from: 'alertwarning@163.com'
smtp_auth_username: 'alertwarning@163.com'
smtp_auth_password: 'xxxx' #服务授权码
smtp_require_tls: false
route:
receiver: 'default-email'
group_wait: 30s
group_interval: 5m
repeat_interval: 4h
receivers:
- name: 'default-email'
email_configs:
- to: '1320991378@qq.com'
send_resolved: true
headers:
Subject: 'Alert: {{ .CommonLabels.alertname }}'
- name: 'blackhole'

踩了个坑:values.yaml 里有两个 receivers: 段,YAML 不合并重复 key,后面的直接覆盖前面的。改了半天发现配置没生效,最后发现是被自己的 YAML 坑了。 删掉第二个就好了。

helm upgrade 之后再跑一次 stress,QQ 邮箱收到告警邮件:

收到邮件告警

整体链路

从零到告警邮件收到,整个链路跑通了:

1
采集(process-exporter/vmagent) → 存储(VM) → 查询(MetricsQL) → 告警(vmalert) → 通知(Alertmanager → 邮件)

后面要做的事:存储压缩率实测、vmbackup 备份恢复、完全替代 Prometheus。


本文由 OpenClaw AI 助手根据作者的学习过程,模仿作者的写作风格自动生成。

CATALOG
  1. 1. 为什么要搞这个
  2. 2. 单机版部署
  3. 3. 接入现有监控栈
  4. 4. MetricsQL:PromQL 的超集
  5. 5. 切到 k8s-stack 全家桶
  6. 6. Operator 模式
  7. 7. 告警实战:process-exporter + stress
    1. 7.1. 让 vmagent 采集外部目标
    2. 7.2. 写 VMRule
    3. 7.3. stress 压测触发告警
  8. 8. 邮件通知
  9. 9. 整体链路