处于虚拟化运维一线的人,应该都有过这种经历:机房一台 ESXi 宿主机的 CPU 跑到了 90%,但你是第二天看监控面板才发现的。ESXi 自带的 Web 管理端只能看实时曲线,历史趋势、多主机对比基本靠临时截图,vCenter 的授权费用对小机房又不太友好。我自己在管着一批基于 VMware ESXi 8.0u3 的宿主机时,干脆把目光转向了 Prometheus 这套开源组合,用 vmware_exporter 抓取虚拟化层指标,再用 Grafana 出图、Alertmanager 推送告警。这套方案的工作量和成本都压得很低,效果却完全不输商业监控。
这篇文章会把“Prometheus 监控 ESXi”从零到落地讲透,包括账号权限怎么开、采集器怎么部署、Prometheus 怎么配置、告警阈值怎么算,以及我实际踩过的那些坑。适合手里有 ESXi 裸金属、但没有 vCenter 完整授权的运维同学,也适合刚接触 Prometheus、想拿虚拟化环境练手的监控新人。
1. 为什么需要一套独立的 ESXi 监控体系
先说说我为什么放着好好的 ESXi 界面不用,非要自己搭一套 Prometheus。
1.1 自带监控的局限
ESXi 的 Web Client 看单台宿主机,确实能直观看到 CPU、内存、存储、网络。但这里面有几个很现实的问题:
- 历史数据保留时间非常有限,想看一周前的负载趋势,基本找不到;想看一个月内的容量增长,只能靠手工记录。
- 多台宿主机之间没有横向对比,无法一眼看出哪台机器是瓶颈。如果机房有 5 台、10 台宿主机,每次巡检都要逐台登录。
- 告警能力弱,ESXi 本身的事件通知更多是配合 vCenter 使用,免费授权下的裸 ESXi 很难做精细的阈值告警。
- 没有统一的 API 对外暴露时序指标,第三方系统想消费这些数据,只能通过 vSphere API 自己实现,而直接对接 SOAP/XML 接口的开发成本并不低。
很多人把 Prometheus 理解成“容器监控工具”,其实它监控的边界是“任何能暴露 metrics 接口的东西”。只要我能把一个 ESXi 的指标转换成 Prometheus 文本格式,后面所有存储、查询、告警、可视化都交给 Prometheus 生态来收尾。这个思路才是整套方案的核心:不改变 ESXi 本身,而是做一个适配层。
1.2 技术选型的逻辑
在 Prometheus 生态里,监控 vSphere/ESXi 的 exporter 不止一个。我最后选的是 vmware_exporter,原因是它对独立的 ESXi 宿主机支持比较干脆,只需要一个账号密码就能通过 vSphere API 拉取数据,不需要额外部署代理。它的底层是基于 pyvmomi 实现的,通过 ESXi 暴露的 SDK 接口读取主机和虚拟机信息,然后把数据转换成标准的 Prometheus metrics。
有人会问:vCenter 也有 API,是不是只有装了 vCenter 才能用这套?其实不是。ESXi 裸机本身就保留了 vSphere API 的兼容端点,vmware_exporter 直接指向单台 ESXi 的地址也是可以工作的。区别在于,如果你有 vCenter,可以一次拉取整个集群所有主机的数据;没有 vCenter,就得多配置几个 target,让 Prometheus 分别抓取。
这个方案的总体链路是这样的:
ESXi 宿主机(多台) ↓ vSphere API 只读调用 vmware_exporter(每台或每集群一个) ↓ Prometheus metrics 文本 Prometheus Server(抓取、存储、告警规则) ↓ PromQL Grafana 面板 / Alertmanager 告警从维护角度看,这套东西最省心的点是 exporter 无状态,Prometheus 挂了重拉就是;ESXi 侧只做一个只读账号,不影响任何生产虚拟机。
1.3 几个前置条件
在动手之前,我建议你把这几件事先确认掉:
- ESXi 版本:8.0u3、7.0、6.7 我都实测过,API 层面基本没差异。如果是定制过的“8.0u3 集成驱动版”,只要账号权限正常,采集方式完全一样。
- 网络连通性:Prometheus 服务器和 ESXi 之间必须能访问 443 端口,因为 vSphere API 默认走 HTTPS。
- 许可证:即便 ESXi 用的是免费许可证,也不影响通过 API 读取指标,只是拿不到 vCenter 的聚合能力而已。所以这篇文章的监控方案,对免费授权用户同样适用。
- 时间同步:ESXi 和 Prometheus 服务器之间的时间偏差过大,会出现数据断点或告警误判,建议两边都配好 NTP。
2. 准备工作:账号、权限与采集器部署
监控一切的前提是让采集器能安全地拿到数据,所以我会从账号边界讲起。
2.1 在 ESXi 上创建只读监控账号
我不建议拿 root 账号去喂采集器,尤其是多个人共用的生产环境,root 的凭证一旦泄露到配置文件里,风险面太大。正确姿势是创建一个专用账号,权限收缩到最小。
在 ESXi 的 Web Client 里,操作路径是:菜单 -> 管理 -> 用户 -> 用户,然后添加一个用户,例如prom-monitor,密码单独生成一串,不要复用其他系统密码。
创建完用户后,还需要给这个账号授权。ESXi 的权限模型是基于角色的,具体步骤如下:
- 进入主机的“操作”菜单,选择“权限”。
- 添加权限,选择刚才创建的
prom-monitor用户。 - 角色这里,搜索“只读”(ReadOnly),这是内置角色,足够采集指标用了。
- 确认之后,系统会提示这个角色只能查看,不能修改,这正是我们要的效果。
如果你管理多台 ESXi,而且每一台都是独立的,那么每台主机都要做一遍同样操作。这个过程并不复杂,一台机器一分钟左右。如果后续接入了 vCenter,则是在 vCenter 的数据中心或集群层级授一遍权,下面所有主机都会继承。
注意:vmware_exporter 虽然只需要只读角色,但如果某些自定义视图权限缺失,它会拿不到部分性能计数器。表现在 metrics 上就是某些指标没有值,或者 scrape 时直接 timeout。所以如果你的环境里自定义过角色,请确保“系统管理 -> 查看”和“性能 -> 查看”这类基本读取权限也在里面。
2.2 部署 vmware_exporter
vmware_exporter 的部署方式有很多,我最习惯的是 Docker,因为依赖都打包好了,不用折腾 Python 版本。你可以直接用官方镜像pryorda/vmware-exporter,也可以自己拉源码构建。考虑到找镜像可能遇到网络问题,建议有条件的话提前拉到本地,或者用 Dockerfile 自己构建一份。
用 docker run 方式启动的话,命令大概长这样:
docker run -d --name vmware-exporter \ -e VSPHERE_USER='prom-monitor' \ -e VSPHERE_PASSWORD='你的强密码' \ -e VSPHERE_HOST='192.168.10.10' \ -e VSPHERE_IGNORE_SSL_WARNINGS='True' \ -p 9272:9272 \ pryorda/vmware-exporter这里有几个参数值得说明:
VSPHERE_HOST是 ESXi 的 IP 或域名。如果你有多台 ESXi,最简单的方式是起多个容器,每个容器指向一台。VSPHERE_IGNORE_SSL_WARNINGS要设为True,因为 ESXi 默认是自签名证书,不忽略 SSL 校验的话 exporter 会连不上。这部分仅发生在采集链路上,实际抓到 Prometheus 的指标数据已经和 SSL 无关了。- 默认服务端口是 9272,你可以把它映射到宿主机的任意空闲端口。
如果你不喜欢 Docker,也可以用 systemd 直接跑 Python 进程:建一个虚拟环境,pip install vmware_exporter,然后写一个 systemd unit 文件设置环境变量和启动命令。效果一样,只是多了一些手工步骤。
2.3 验证采集器的输出
容器起来之后,先别急着接 Prometheus,先手工验证一下。在部署机上执行:
curl http://127.0.0.1:9272/metrics | head -n 20正常情况下,你应该能看到以vmware_开头的指标。比如:
vmware_host_cpu_usage_average 12.5 vmware_vm_mem_usage_average 35.2 vmware_host_uptime_seconds 1024000如果返回空或者报 401/500,优先检查账号密码和环境变量。这一步花两分钟排掉,后面 Prometheus 接入会非常顺。
这里我还习惯做一件额外的事:看看 exporter 日志里有没有大量 timeout 或soap error。ESXi 在首次拉取大量虚拟机数据时,可能因为性能计数器要实时计算而变慢,如果超时,就调整 Prometheus 侧的scrape_timeout或者在 exporter 侧加缓存采集间隔。这个细节后面还会展开。
3. Prometheus 接入与告警规则配置
采集器已经能把 ESXi 的指标吐出来了,下面把它接进 Prometheus,然后写一些真正会炸的告警规则。
3.1 配置 scrape 任务与理解指标模型
在 Prometheus 的主配置文件prometheus.yml里,增加一个 job,指向 vmware_exporter 的 metrics 地址:
scrape_configs: - job_name: 'vmware_exporter' scrape_interval: 60s scrape_timeout: 55s static_configs: - targets: ['192.168.10.10:9272', '192.168.10.11:9272']这里scrape_interval我刻意设置成了 60 秒,而不是默认的 15 秒。原因是虚拟化层的性能指标本身更新频率不高,60 秒足以反映负载趋势,又能减少对 ESXi API 的压力。如果你起多个 exporter 实例,可以通过static_configs里的targets数组一次列出所有地址,Prometheus 会自动调度抓取。
关于指标模型,vmware_exporter 导出的指标是有规律的:
vmware_host_*:宿主机层面的指标,包括 CPU、内存、网络、存储、功耗等。vmware_vm_*:虚拟机层面的指标,包括各虚拟机的 CPU 使用率、内存使用率、磁盘读写下限等。vmware_datastore_*:存储相关指标。- 每个指标上都挂着一堆 label,比如
esxi_hostname、vm_name、datastore_name,这些 label 是实现多维监控的关键。
有一个容易忽略的点:这些指标名后面往往带有_average或带统计粒度的后缀,比如vmware_host_cpu_usage_average。这表示采集侧已经做了平均聚合,不需要你在 PromQL 里再做一次avg_over_time的粗粒度处理。
3.2 核心指标与查询语句
在实际监控面板里,我常驻的指标有这么几个,按使用频率排:
| 监控对象 | 指标名 | 常见用途 |
|---|---|---|
| 宿主机 CPU | vmware_host_cpu_usage_average | 看宿主机整体 CPU 负载 |
| 宿主机内存 | vmware_host_mem_usage_average | 看物理内存占用比例 |
| 宿主机网络 | vmware_host_net_usage_average | 看网卡收发数据吞吐趋势 |
| 虚拟机 CPU | vmware_vm_cpu_usage_average | 定位单个 VM 的 CPU 瓶颈 |
| 虚拟机内存 | vmware_vm_mem_usage_average | 定位 VM 的内存压力 |
| 数据存储 | vmware_datastore_usage_average | 关注存储容量水位 |
比如我要查某台宿主机的 CPU 使用率:
vmware_host_cpu_usage_average{esxi_hostname="esxi-01"}如果要画一张整个集群所有主机 CPU 的排行图:
topk(10, vmware_host_cpu_usage_average)另一个非常实用的查询是判断某台虚拟机的内存是否已经触发超分配风险。ESXi 的 VMware Tools 会给出 guestOS 内可回收内存的估算,vmware_exporter 会通过vmware_vm_mem_usage_average暴露出来。当这个值一直高于 90%,且宿主机本身的内存压力也不低,基本就能判断这台 VM 需要扩容或优化了。
3.3 告警规则的阈值设定与计算过程
Prometheus 的告警规则写在独立的 rule 文件中。我先分享一组在生产环境验证过的规则:
groups: - name: esxi-alerts rules: - alert: ESXiHostCPUHigh expr: vmware_host_cpu_usage_average > 90 for: 15m labels: severity: warning annotations: summary: "宿主机 {{ $labels.esxi_hostname }} CPU 使用率超过 90%" - alert: ESXiHostMemoryHigh expr: vmware_host_mem_usage_average > 90 for: 15m labels: severity: warning annotations: summary: "宿主机 {{ $labels.esxi_hostname }} 内存使用率超过 90%" - alert: ESXiVMHighMemory expr: vmware_vm_mem_usage_average > 95 for: 10m labels: severity: warning annotations: summary: "虚拟机 {{ $labels.vm_name }} 内存使用率超过 95%"阈值的选取,我是这么算的:
先拿 CPU 来说。虚拟化场景下,宿主机 CPU 达到 90% 意味着可能有 CPU ready 时间上升,VM 开始出现调度等待。但你不想让告警去打扰凌晨值班的人,所以时间窗口设定为 15 分钟,也就是只有持续超过 90% 才触发。这样既过滤了瞬时峰值,又不会错过持续过载。
内存的阈值比 CPU 低一点,90% 是一个相对安全的心理线。ESXi 本身有内存回收机制,短期的 90% 并不致命,但如果超过 15 分钟还在 90% 以上,撞击交换分区的概率就很高了,该告警。
这里要特别说明:告警不是“越高越好”,也不是“越低越好”,而是要和你的资源水位、业务容忍度匹配。先观察一周基线数据,再定阈值,千万不要一上来就套用网上的参数。我自己就吃过这个亏,一开始 CPU 告警设成 85%,结果每周都被误报磨掉耐心,最后改成 90% 并且加上了for: 15m,误报基本清零了。
Prometheus 配置好 rule 文件之后,别忘了在启动参数里加载:
rule_files: - "/etc/prometheus/alert_rules.yml"重载配置可以直接用接口curl -X POST http://localhost:9090/-/reload,前提是启动时加了--web.enable-lifecycle。如果是 docker 启动,也可以用docker restart重启容器,效果一样。
3.4 Alertmanager 的推送链路
告警规则是骨架,推送消息才是触达。Alertmanager 在这里承担了去重、分组和路由的角色。docker 部署 Alertmanager 比较简单:
docker run -d --name alertmanager \ -p 9093:9093 \ -v /path/to/alertmanager.yml:/etc/alertmanager/alertmanager.yml \ prom/alertmanageralertmanager.yml里配置接收人,比如企业微信、钉钉或邮件。一个最小化的邮件示例:
route: group_by: ['alertname'] group_wait: 10s group_interval: 2m repeat_interval: 4h receiver: 'email' receivers: - name: 'email' email_configs: - to: 'ops@example.com' from: 'monitor@example.com' smarthost: 'smtp.example.com:465' auth_username: 'monitor@example.com' auth_password: 'password'Prometheus 要对接 Alertmanager,只需要在配置里加上:
alerting: alertmanagers: - static_configs: - targets: ['192.168.10.99:9093']这套链路跑通后,ESXi 一旦真的出问题,你能在 15 分钟内在手机里看到推送,而不是隔天被业务侧通知“机器卡了”。对运维而言,及时性和准确性都要比“事后复盘”重要得多。
4. Grafana 可视化与仪表板调优
数据都进了 Prometheus,缺的是“一眼看懂”的展示层。Grafana 的价值在这里体现得很直接。
4.1 数据源与面板选择
Grafana 部署同样推荐 docker。数据源类型选择 Prometheus,URL 填 Prometheus 的地址,例如http://192.168.10.99:9090,保存即可。
面板方面,社区里的 vSphere 仪表板模板很多,但直接用别人的模板往往有几个问题:
- 模板里的变量名和自己环境不一样,比如 label 名是
esxi_hostname还是hostname,版本不同,写法就不同。 - 模板覆盖的指标版本较老,面对 ESXi 8.0u3 这样较新的版本,部分指标采集不到,面板会一直出现 empty query。
我的习惯是,导入一个模板作为起点,然后按自己的指标清单逐个核对。具体到 dashboard 的 query 写法,可以看下面这几点。
4.2 常用面板的 query 写法
宿主机的 CPU 使用率折线图,最基础的写法:
vmware_host_cpu_usage_average{esxi_hostname=~"$host"}如果我想同时展示多台主机,还可以把esxi_hostname定义成 Grafana 的 Dashboard 变量。在设置里的 Variables 添加查询:
label_values(vmware_host_cpu_usage_average, esxi_hostname)这样顶部就能下拉框选主机,不用每次改 query。
虚拟机内存面板,我习惯同时展示两行:一行是使用率,一行是虚拟机数量。结合宿主机的维度一起看,能分辨出某台宿主机上的内存是不是被某个大户给吃满了。query 可以这样:
vmware_vm_mem_usage_average{esxi_hostname=~"$host"} > 90配合$__from、$__to时间范围变量,Grafana 会自动处理时间区间,不需要额外写时间条件。
存储面板我偏爱采取表格形式:
vmware_datastore_size_byte{} - vmware_datastore_free_size_byte{}这样能算出已使用容量,并把 datastore 名称保留成表格的行,再配合百分比计算,谁快满了,谁还有余量,一目了然。
4.3 尝试加一点红色
Grafana 的面板不只是在画“好看的图”,更重要的是通过颜色和阈值把风险放大。拿宿主机内存面板来说,我把阈值设为:
0 - 80:绿色,表示健康80 - 90:黄色,表示观察90 - 100:红色,表示告警
这样值班同事扫一眼 Dashboard,颜色基本能说明当前压力。毕竟凌晨被叫起来看监控,没人愿意去细究一串数字。
5. 常见问题与排查实录
这套东西在实际跑的过程中,总会出现一些“文档里没写”的情况。这部分我把自己踩过的坑整理一下,也算给后人铺路。
5.1 采集超时和指标缺失
现象:Prometheus 的 target 页面显示context deadline exceeded,或者有些指标有数值、有些指标一直是空。
排查路径是这样的:
- 先手动 curl exporter 的
/metrics,确认 exporter 本身是否能正常输出。如果 curl 都慢,说明问题出在 ESXi 侧或 exporter 处理逻辑。 - 看 exporter 日志。常见报错是
SOAP Error或object reference not set。出现这种情况,多半和你 ESXi 上的虚拟机数量多、性能计数器多有关。 - 延长 Prometheus 的
scrape_timeout,我一般从默认的 10s 调到 55s。注意scrape_timeout不能大于scrape_interval,所以间隔也要一起调大。 - 如果单台 ESXi 上的 VM 数量超过二三百台,建议把 vmware_exporter 的采集线程数或缓存时间调大,否则每次全量拉取都会很吃力。
5.2 权限和 SSL 相关报错
现象:exporter 启动后日志一直报 500 或permission to perform this operation was denied。
这种问题通常不是密码错了,而是角色权限不够。我在 2.1 节里已经提醒过,这里再强调一点:如果 ESXi 里启用了“锁定模式”,只读账号也可能会被拦截,建议先在主机的安全配置里,把锁定模式关掉或把监控账号加入例外列表。
另一个被问得特别多的是 SSL 告警:
urllib3.exceptions.MaxRetryError: HTTPSConnectionPool ... SSL: CERTIFICATE_VERIFY_FAILED这就是没有正确设置VSPHERE_IGNORE_SSL_WARNINGS=True。还有人不愿意忽略 SSL,非要用自定义 CA 签一个证书给 ESXi,其实没必要,一套内部监控没有必要为自签名证书做那么多额外工作。
5.3 我独踩过的坑:VM 重名、vMotion 与版本差异
有几个坑是网上教程很少提到的。如果我不写下来,估计你遇上了要折腾半天。
第一,是虚拟机重名。vmware_exporter 拉取 VM 指标时,label 上的vm_name直接来自 ESXi 显示名。如果你的环境里不同文件夹下存在同名 VM,Grafana 里就会出现两条 name 相同但内容不同的数据。解决思路有两个:一是从命名规范上硬性避免重名,二是用 VM 的moid(管理对象 ID)作为辅助 label,做区分。查询里可以用vmware_vm_cpu_usage_average{moid=~"vm-123"}来精确区分。
第二,vMotion 导致的数据错位。有 vCenter 的环境里,VM 在迁移前后,它所在宿主机 label 是会发生变化的。如果你的告警规则按宿主机分组,那么在迁移窗口期,数据看上去就像“虚拟机和宿主机对不上”。解决方法是不要用宿主机 label 直接关联 VM 指标做精确断言,指标分析时以 VM 自身维度为主。
第三,ESXi 版本差异。6.7 和 8.0 在部分性能计数器名称上并不一致。比如某些存储延迟指标,在 8.0 里采集到的 label 可能是空的。我的处理方式是:先针对每个版本环境导出一份指标清单,标记哪些指标可用,哪些不可用,再写面板只展示可用部分。这样至少不会出现大面积空白。
第四,ESXi 的定制驱动 ISO 问题。你是否遇到过安装 ESXi 时发现网卡不识别、找不到存储,需要制作“集成驱动版”安装盘?这种情况通常发生在一些新网卡或白牌服务器上,需要把对应厂商驱动打包进 ISO。如果你在用这类定制版 ESXi 做监控,注意它的版本号里可能带u3k这类 build 标识,而 vmware_exporter 只依赖 API,不关心驱动差异,所以采集不受影响。但安装和升级驱动的过程可能会降低业务可用性,建议维护窗口操作。
第五,Prometheus 版本升级。Prometheus 2.53.0 及之后的版本在配置格式、告警模板语法上做了一些演进。旧版本配置里的$labels写法在新版里依然是可用的,但你要注意标签转义和转义字符的处理。升级前最好先备份配置文件,并临时验证一下规则文件是否能通过promtool check rules检查。
5.4 常见问题速查表
顺手整理一个表格,省得每次排障都翻半天记录:
| 现象 | 可能原因 | 快速处理 |
|---|---|---|
| scrape timeout | VM 数量过多/采集间隔太小 | 把 scrape_interval 调到 60s,timeout 调到 55s |
| 指标全是空值 | 只读账号权限不足 | 确认角色包含“只读”和“性能”查看权限 |
| 报 SSL 错误 | 自签名证书校验失败 | 设置 VSPHERE_IGNORE_SSL_WARNINGS=True |
| 告警一直不触发 | for 时间窗口太长 | 确认持续时长是否真的满足条件,或调低 for |
| Grafana 显示 empty query | label 名不匹配 | 用 label_values 重新确认指标 key |
| 虚拟机有数据显示不出来 | VM 显示名冲突 | 改用 moid 作为辅助 label |
| ESXi 版本差异导致指标缺失 | API 版本差异 | 按版本输出指标清单,面板只展示可用项 |
这套“Prometheus + vmware_exporter + Grafana + Alertmanager”的组合,我已经在多个 ESXi 8.0u3 环境跑了一段时间,稳定性是经过了业务高峰验证的。它最吸引我的地方在于,所有组件都是无状态或低耦合的,想加主机就加 exporter,想加告警就写规则,扩容成本几乎为零。相比那些按 CPU/VM 数量收费的商业监控工具,它的确更适合预算有限但要求不低的运维团队。
最后再分享一个小技巧:在部署完之后,记得把 exporter 的指标也纳入 Prometheus 自身的监控,比如up{job="vmware_exporter"}、scrape_duration_seconds。这样当 exporter 挂了或抓取变慢时,你第一时间看到的是“监控本身也出问题了”,而不是等业务卡死之后才反过来查为什么没告警。监控这套东西,自己首先得被监控,这个习惯会帮你省下很多被动救火的夜晚。