Prometheus 切换到 VictoriaMetrics 统一告警的部署记录

Prometheus 切换到 VictoriaMetrics 统一告警的部署记录

记录时间:2026-08-27
环境:RKE 信创 ARM64 双生产集群(clusterA / clusterB)+ 公司测试集群 / victoria-metrics-cluster 0.42.0(v1.143.0-cluster)/ victoria-metrics-operator 0.67.2(v0.74.0)/ kube-prometheus-stack 58.7.2 / PrometheusAlert v4.9.2

一、事情的由头

起因是一条 Swap 告警风暴。clusterA 有台主机的 Swap 使用率 critical 告警,10 分钟内恢复一次又触发一次,消息刷得人心烦。我查下去,发现规则写的是瞬时值直接比 80%,恢复侧没有任何滞后,指标贴着 80% 上下穿插,就变成 firing、resolved、再 firing 的循环。修好这条规则之后,更大的想法摆到桌面上:两个集群的 Prometheus 数据反正都写进 VictoriaMetrics(VM)了,告警为什么不也统一到 VM 侧来评估,一处发,省得各集群各搞一套。

目标拆开就三个:

目标 起始状态 完成状态
数据汇聚 两集群 Prometheus 已写 VM 集群 不变,沿用
统一告警引擎 各集群 PrometheusRule 各自评估 vmalert + VMRule 一处评估
告警分发与通知 clusterA 的 Alertmanager + PrometheusAlert 复用现有 PAC,不新增跨集群依赖

1.1 参考文章的要点与我的选择对照

后来我又翻到一篇”百万级指标切 VM 集群版”的部署文章(WAKE UP技术),里面几个要点跟我的实际选择有差异也有重合,摆一起看:

文章的做法 我的选择 差异原因
vmagent 替换 Prometheus 采集,内存只要 1/5 Prometheus 继续采集,remoteWrite 进 VM 我停在九阶段的第 4 步稳态,采集、短期本地存储、旧告警兜底都留在 Prometheus
replicationFactor: 2,生产起码两副本 replicationFactor 1,分片无副本 存储是集中式 SSD NFS,两份副本写同一个阵列买不到独立故障域,翻倍不划算
集群版四角色:vminsert 哈希路由、vmstorage 存分片、vmselect 广播聚合 同款 2+2+2 集群 原理一致:扩容加 vmstorage 副本,新节点空盘入群,旧数据留在原节点,查询时 vmselect 并行拼结果
用 k8s-stack chart 全套装,坑是 vmsingle 必须显式关 裸 operator chart 加 CR 逐步搭建 我没走全家桶(不动现有 Prometheus 体系),踩的是另一边的坑:prometheus-converter 自动转换
UI 进不去就手写 NodePort Service Ingress 加域名,AM 加 hostAliases 跨集群解析 我多一个跨集群访问 dyck PAC 的需求,NodePort 解决不了域名路由
Grafana 数据源 URL 填 /select/0/prometheus/,中间 /0/ 是默认租户 同款路径 一致

文章里扩容原理那段(vminsert 按标签哈希分片、vmselect 向所有 storage 广播再拼结果)正好解释了查半年前的曲线为什么快:每个 vmstorage 只查自己那部分,并行聚合。

二、方案我前后翻了三版

这段是整个部署里最值得记的,方案翻了三版,每一版被否掉的理由都是实打实的体验问题。

2.1 第一版:victoria-metrics-alert 裸 chart,被否

我起手用的是官方 victoria-metrics-alert chart(0.40.0,appVersion v1.143.0),一次装出 vmalert 加内置 Alertmanager,规则写进 chart 的 server.config.alerts。这版的第一个问题就让它站不住:改一条规则要 helm upgrade 整个 release,而日常习惯是 PrometheusRule 那种独立 yaml 文件、apply 即生效。

我又改成独立 ConfigMap 挂载加 -configCheckInterval 热加载,规则脱离 values。第二个问题也跟着来了:所有规则堆一个 yaml 会膨胀,要的是每个业务域一个文件。K8s 的 ConfigMap 卷只能点名挂载,做不到自动收集所有规则文件,加一个新业务域文件还是得回来改 values。到这里我看明白了,绕 ConfigMap 模拟 CRD 的体验,总归有缺口。

2.2 第二版:全 operator

“把现有 VM 都改造成 operator 行不行?”我把收编路径过了一遍,觉得可以,正式转向 vm-operator:VMAlert、VMAlertmanager、VMRule 全部 CR 化。VMRule 的 groups 语法跟 PrometheusRule 完全兼容,迁移几乎是改个 kind,规则按业务域一个文件、apply 秒级热加载,正是想要的体验。

2.3 第三版(终态):存储层不动,只上告警链

生产阶段二(把 helm 版 VM 集群收编成 VMCluster CR)眼看要动手了,动手前夜我重新掂量了一句:”helm 版跑了这么久不是更好更稳定吗,为什么一定要收编?”算完账认账:收编是零功能收益的形态统一,代价却是没演练过的 PVC 重绑加生产数据面前的停机窗口。没坏的东西别动它。终态定格:告警链走 operator,存储层留 helm。

中间还有个我亲自验证过的岔路:中途想过一个组合,裸 chart 装 vmalert,规则仍用 VMRule。我推演后否了。operator 对 VMRule 的动作链是 watch 规则、渲染配置、挂到它自己创建的 vmalert、触发 reload,野生 vmalert 不在这个流程里,两者拆开任一侧就失去意义。要 VMRule 的爽,就必须让 operator 建 vmalert,二选一,没有中间态。

三、测试环境从零部署

生产是双集群,动手前先在测试集群完整跑一遍。目录按环境分组:xc-test/ 下分 operator/(operator 本体)、cluster/(VMCluster 加 VMAuth)、alerting/(告警链三件加规则)。

3.1 组件清单

组件 形态 关键配置
victoria-metrics-operator helm chart 0.67.2 disable_prometheus_converter: true
VMCluster CR 2+2+2,retention 180d
VMAuth CR + Secret 统一入口,/select 与 /insert 分发,basic auth
VMAlert(vmalert) CR datasource 指 vmselect,selectAllByDefault: true
VMAlertmanager CR + Secret configSecret 模式,webhook 指测试 PAC
VMRule CR 每业务域一个文件

3.2 部署命令

# operator
helm upgrade --install victoria-metrics-operator victoria-metrics-operator-0.67.2.tgz \
  -n monitoring -f operator/values.yaml

# 集群与入口
kubectl apply -f cluster/vmcluster.yaml
kubectl apply -f cluster/vmauth.yaml

# 告警链
kubectl apply -f alerting/vmalertmanager.yaml
kubectl apply -f alerting/vmalert.yaml
kubectl apply -f alerting/vmrule-node-exporter.yaml

3.3 测试环境踩的六个坑

  1. operator 一启动就批量转换规则。日志里大片 failed to reconcile VMRule from Rule 重试,我一开始以为部署挂了,细看发现是 prometheus-converter 在干活:测试集群装着 kube-prometheus-stack,它把里面的 PrometheusRule 和 ServiceMonitor 全量转成 VMRule 和 VMServiceScrape。配合 selectAllByDefault 这些规则会被 vmalert 全加载,测试群告警风暴是迟早的事。处理:operator.disable_prometheus_converter: true,再删掉已转换的 48 个对象,日志马上安静。
  2. operator 命名是前缀式。svc 名是 vmauth-vmauthvmselect-victoria-metrics-cluster,跟 helm chart 的后缀式(victoria-metrics-cluster-vmselect)正好相反。我第一版所有后端地址按 helm 习惯写了后缀式,vmauth 转发报 backend unavailable。从那以后 operator 系资源名一律记 组件名-<CR名>
  3. VMAuth 的 Secret key 必须是 config.yaml。我按 VMAlertmanager 的习惯写了 auth.yaml,Pod 报 references non-existent secret key: config.yaml 卡在 ContainerCreating。我第一反应是镜像问题,还在节点上 docker pull 验证了一遍,结果就是 key 名。两个 CR 的 configSecret key 约定不一样,各记各的。
  4. Alertmanager 不认 loggerTimezone。这是 VM 组件专属 flag,我顺手配给了 prom/alertmanager,启动即退出报 unknown long flag。AM 的时区靠 TZ 环境变量就够了。
  5. StatefulSet 的 volumeClaimTemplates 不可变。中途想换 storageClassName,apply 显示 configured 就是不生效。K8s 硬限制,换存储类只能删 CR 加 PVC 重建。测试环境无数据,直接重来。
  6. Prometheus 的 remoteWrite 配置变更走热加载。加完 remoteWrite 后 Prometheus Pod 没滚动,我一度以为没生效,实际 config-reloader 检测到配置变化直接 reload 进程,Pod AGE 不变是正常行为。

验收方式:vmrule 里放一条永真规则(expr: vector(1)),1 到 2 分钟内测试企业微信群收到通知,从 vmalert 到 AM 到 PAC 到微信全部打通。

四、生产阶段一投产

生产分两阶段设计:阶段一只上告警链,datasource 直接指向现有 helm 版 vmselect,VM 集群本体一根手指头不碰,零风险;阶段二才是集群收编(后来挂起,见 2.3)。

4.1 通知出口,来回最多的一块

第一版我想的是 clusterB 本地部署一套新 PrometheusAlert。再一查 dyck 的 PAC 配置,才发现它是写 ES 的(alert_to_es=1),我初版把它关成了 0,这不是平移,是降级。我接着提启用 dyck ES 的 NodePort 让 clusterB 直连写 ES,又把自己否了:为一个记录功能把 ES 暴露出去,不值。最后定下来:PAC 就用 dyck 的。落到复用 dyck 现役 PAC,AM 跨集群 webhook 指向它。

4.2 hostAliases 查证,我错了三次

复用 dyck PAC 需要 clusterB 的 AM 解析 dyck 的 ingress 域名。那就用 hostAliases 试试。我一开始是不信的,还查了三个地方:chart 里的 crd.yaml 没有、集群 CRD grep 没有、主 types 文件没有。三个地方都没有,我就下了结论不支持。结果翻官网文档一看,明明白白写着支持。我再翻源码,字段藏在嵌入的共享结构 CommonAppsParams 里,CRD 对它是 schemaless 处理不显式列出。schema 里查不到不等于不支持。测试集群 patch 一下,hostAliases 立刻出现在生成的 StatefulSet 里,当场打脸。这条教训我记死了:CR 字段要查嵌入结构,静态查证永远留余量,实测才是金标准。

4.3 生产专属的两个集群级坑

测试环境没暴露的,生产全现形了:

  1. ResourceQuota 强制所有容器带 limits。operator 注入的 config-init 和 config-reloader 边车没配资源,vmalert Pod 直接 FailedCreate(must specify limits.cpu for: config-init,config-reloader)。解法是 CR 的 configReloaderResources 字段,同样藏在共享结构里。
  2. 边车镜像默认走 Docker Hub。config-reloader 的镜像名没有 registry 前缀,信创环境拉不下来。解法是 operator chart 的 global.image.registry。注意这个 chart 的 global 对边车生效,跟 victoria-metrics-alert chart 的 global 不生效是两回事,各自验证,别想当然。

4.4 两个配置字段错误

  • AM webhook 的 TLS 配置层级。我把 tls_config 直接挂在 webhook 条目下,operator 拒绝创建 AM,报 field tls_config not found in type webhook.plain。正确层级是 http_config.tls_config,六处全改。
  • vmalert remoteWrite 的 URL 双路径。日志一打开全是 400,请求路径居然是 /insert/0/prometheus/api/v1/write/api/v1/write,我一看就明白了:vmalert 自己会拼 /api/v1/write,我 URL 里又写了一遍。删掉重写的那截,400 消失。这个错直接导致 ALERTS 序列写不进 VM,Grafana 里查不到新链的告警历史。

4.5 端到端验收

生产 vmalert 加永真测试规则后,企业微信收到”告警链路连通性测试”通知,时间戳 +08:00 正确。整条路径:vmalert(clusterB,读 VM 汇聚数据)到 VMAlertmanager(hostAliases 跨集群解析加 https)到 dyck PAC 到企业微信。

五、告警怎么看,收尾怎么收

5.1 告警查看入口

vmalert UI 的 Alerts 页有个坑:API(/api/v1/alerts)明明有 firing 数据,页面点 Alerts 就是空的,F12 的 Network 和 Console 都干净。我定性为这个版本的前端渲染问题,归档待升级镜像。日常看告警用三个入口:AM UI(当前告警正解)、Grafana 大屏(ALERTS{alertstate="firing"} 六面板,含按严重级别和业务域分布)、API 直查。

告警触发时间有两处来源:ALERTS_FOR_STATE 序列的样本值就是进入状态的 Unix 时间戳,time() - ALERTS_FOR_STATE 直接得持续时长;Grafana 里乘 1000 配 Datetime 单位显示可读时间。

5.2 收尾动作

  1. 删除测试规则组。
  2. run.sh 定稿为终态运维手册:日常巡检、规则迁移四步铁律、告警链运维、helm 集群运维。
  3. 目录整理:cluster/ 放现行 helm 版集群配置,阶段二收编 CR 改名 cluster.后续/ 挂起,废弃的裸 chart 目录删除。
  4. 规则迁移铁律:每条规则先在 dyck 侧 PrometheusRule 下线再在本侧 VMRule 启用,绝不允许两条链同时发。

六、踩坑速查表

现象 根因 解法
operator 启动大量转换日志 prometheus-converter 默认开启 disable_prometheus_converter: true
vmauth 转发 backend unavailable svc 名写成 helm 后缀式 全部改前缀式 组件-<CR名>
vmauth Pod 卡 ContainerCreating Secret key 错 key 必须是 config.yaml
AM 启动即退出 配了 VM 专属的 loggerTimezone 删掉,TZ env 足够
换存储类不生效 sts volumeClaimTemplates 不可变 删 CR 加 PVC 重建
Prometheus 加 remoteWrite 后 Pod 没滚 配置变更走热加载 正常现象,直接验证数据
vmalert Pod FailedCreate ResourceQuota 要求边车带 limits configReloaderResources
边车镜像拉不下来 默认 Docker Hub 无前缀 operator chart 配 global.image.registry
AM 创建被拒 unmarshal error tls_config 层级错 http_config.tls_config
remoteWrite 报 400 双路径 URL 写全了 api/v1/write 写到 /insert/0/prometheus 为止
Grafana 查不到新链告警 上一个问题导致 ALERTS 没入库 同上修复后即恢复
vmalert UI Alerts 页空 该版本前端渲染问题 用 AM UI 或 Grafana 大屏,待升级

七、注意事项

  • 迁移规则防双发是最高优先级纪律。同一告警两条链同时发,值班群被打扰两遍,还会掩盖”到底哪条链在报”。
  • vector(1) 测试规则是字面量,不查数据源。它只能验收”评估到通知”这一段,datasource 连通性和 remoteWrite 入库要单独验证(看 Rules 页 lastError、查 VM 里 ALERTS 序列)。
  • 同一个 global 字段,换 chart 先实测。victoria-metrics-alert 的 global 不生效要组件级显式配,victoria-metrics-operator 的 global 对边车生效。
  • 测试与生产的存储层是两种管理形态(测试 operator、生产 helm),存储层变更不能两边照搬,告警链同构可以先行。

八、参考资料

暂无评论

发送评论 编辑评论


				
|´・ω・)ノ
ヾ(≧∇≦*)ゝ
(☆ω☆)
(╯‵□′)╯︵┴─┴
 ̄﹃ ̄
(/ω\)
∠( ᐛ 」∠)_
(๑•̀ㅁ•́ฅ)
→_→
୧(๑•̀⌄•́๑)૭
٩(ˊᗜˋ*)و
(ノ°ο°)ノ
(´இ皿இ`)
⌇●﹏●⌇
(ฅ´ω`ฅ)
(╯°A°)╯︵○○○
φ( ̄∇ ̄o)
ヾ(´・ ・`。)ノ"
( ง ᵒ̌皿ᵒ̌)ง⁼³₌₃
(ó﹏ò。)
Σ(っ °Д °;)っ
( ,,´・ω・)ノ"(´っω・`。)
╮(╯▽╰)╭
o(*////▽////*)q
>﹏<
( ๑´•ω•) "(ㆆᴗㆆ)
😂
😀
😅
😊
🙂
🙃
😌
😍
😘
😜
😝
😏
😒
🙄
😳
😡
😔
😫
😱
😭
💩
👻
🙌
🖕
👍
👫
👬
👭
🌚
🌝
🙈
💊
😶
🙏
🍦
🍉
😣
Source: github.com/k4yt3x/flowerhd
颜文字
Emoji
小恐龙
花!
上一篇