先说个结论:vCenter 登录弹出 500,提示“获取身份提供程序时出错”,同时后端日志里能看到 no healthy upstream,这俩信息放一起,基本可以确定问题出在 vCenter 自身的 Web 前端和 SSO 服务这一条链路上,而不是你输错了账号密码。
最近我处理了一台 vCenter 7 的登录故障,现象和你遇到的一模一样:浏览器打开 vSphere Client 首页能出来,但输入账号密码点登录后直接报 500,界面上写着“获取身份提供程序时出错”,后台日志里反复出现 no healthy upstream。坦白讲,这个组合报错第一次遇到确实容易懵,因为它把前端反代、后端服务健康检查、身份提供程序三个层面的事情全糅在一起了。这篇文章就把整个排查过程、背后原理和最终解决办法完整记录下来,给同行走个参考。
1. 这个报错到底卡在哪一层
1.1 先理清 vSphere 登录链路
vCenter 的登录流程不是简单的“浏览器发请求到 Web 服务端”,中间至少经过了三层:
浏览器请求到 vCenter 的 nginx 反向代理,nginx 再转发给 vsphere-ui 服务,vsphere-ui 收到请求后向本地 Lookup Service 和 STS(Security Token Service,安全令牌服务)要身份提供程序信息,然后做 SAML 断言、令牌校验,最后才完成登录。
所以“获取身份提供程序时出错”这个提示,字面上看是 vsphere-ui 在向身份提供程序要配置或验证令牌时失败了。而身份提供程序的信息来源,又是 vCenter 内置的单点登录组件,在 7.0 及以后版本中,这套逻辑已经集成到 vmafd(VMware Authentication Framework Daemon)和 STS 服务里。换句话说,你的账号是 AD 账号也好,vSphere 本地账号也好,登录时都要经过这套身份源发现机制。如果 vmafd 状态不正常,或者 STS 返回不了令牌,前端就只会丢给你一句含糊的“获取身份提供程序时出错”。
1.2 no healthy upstream 是哪里报出来的
no healthy upstream 这行字眼,通常不是 vSphere 页面上的报错,而是 nginx 反向代理在转发请求时发现后端 upstream 不可用后打的日志。在 vCenter 里,nginx 的 upstream 主要是 vsphere-ui 服务。nginx 会定期向后端服务发起健康检查请求,如果连续多次没有收到预期的响应,它就会把该 upstream 标记为不健康。
这时候你要是刷新页面,nginx 直接返回 502/503,页面再经过 vsphere-ui 的错误处理逻辑,最终就渲染成了“500 获取身份提供程序时出错”。简单理解就是:前端想找后端拿身份提供程序配置,结果后端在 nginx 眼里已经“半死不活”,请求根本没被正常处理,自然拿不到任何有用的身份配置信息。
这里有个容易误判的地方:no healthy upstream 是表象,不代表一定是 vsphere-ui 进程挂了,很多时候进程还活着,只是它内部依赖的其他组件(比如 vmafd、Lookup Service 或者数据库连接池)出了问题,导致健康检查接口响应变慢或者返回异常,nginx 才把它标记为不健康。所以排查的核心,是搞清楚 vsphere-ui 为什么不“健康”。
2. 定位问题的完整排查流程
2.1 从 vCenter 的日志入手
遇到这种登录类问题,最好不要凭感觉去到处点,先看日志。vCenter Appliance 可以通过 SSH 登录到后台,日志路径我已经帮你们踩清楚了:
- nginx 日志:
/var/log/vmware/nginx/error.log和/var/log/vmware/nginx/access.log - vsphere-ui 日志:
/var/log/vmware/vsphere-ui/logs/目录下的vsphere_client_vmon.log和vsphere-ui.log - vmon 进程管理日志:
/var/log/vmware/vmon/vmon.log - 身份相关组件日志:
/var/log/vmware/vmafd/vmafd.log、/var/log/vmware/sso/ssoAdminServer.log、/var/log/vmware/lookup/lookupServer.log
我先看的是 nginx 的 error.log,命令很简单:
tail -n 100 /var/log/vmware/nginx/error.log日志里刷了大量类似的记录:connect() failed (111: Connection refused) while connecting to upstream,后面跟着的是 vsphere-ui 对应的 socket 地址。这已经能说明问题:nginx 想连 vsphere-ui,但连接被拒绝。连接被拒绝有两种可能,一是 vsphere-ui 进程确实死了,二是它监听的端口根本没起。
然后我又看了 vsphere-ui 自己的日志:
tail -n 200 /var/log/vmware/vsphere-ui/logs/vsphere_client_vmon.log发现里面有大量线程池满、连接超时、无法与 vmafd 通信之类的异常。这说明 vsphere-ui 进程本身活着,但它依赖的下游服务出了问题。
2.2 检查 vCenter 服务健康状态
看服务状态,用 vmon 的管理命令比用 systemctl 更靠谱,因为 vCenter 里很多关键服务是由 vmon 进程托管,service-control 才是正规入口。我习惯一次性把所有服务状态列出来:
service-control --status --all正常环境下,所有服务应该显示为 Running。我当时看到的实际情况是:vsphere-ui 显示 Running,vmafd 显示 Running,lookup-service 显示 Running,但 sts、sso 相关服务状态在 Running 和 Degraded 之间反复跳。这个 Degraded 状态很关键,说明服务进程没退出,但健康检查不通过。
再用 vmon 的命令看下具体组件的详情:
vmon-cli -l输出里会列出每个组件的 PID、运行时长、健康检查结果。我当时注意到 vsphere-ui 的 health check 结果不是正常值,而是显示成 UNKNOWN 或 FAILED,这就和 nginx 报 no healthy upstream 对上了。
2.3 磁盘、内存、时间,一个都不能少
服务状态乱跳,很多时候不是服务本身代码有 bug,而是底层资源不满足了。我先检查的是磁盘空间:
df -h发现/storage/log分区已经用了 95%,/storage/archive也快满了。这个信息非常关键,因为 vmafd 和 sso 这类服务在写日志或临时文件时如果失败,整个服务就会变得不稳定。尤其是/storage/log,它存的是所有 vmware 组件的日志,一旦写满,服务启动和运行都会出问题。
再查一下内存:
free -hvCenter 虚拟机如果内存分配不足,vsphere-ui 这种 Java 系服务很容易出现堆内存不足,进而导致健康检查线程无法正常响应。
时间同步同样不能忽视。vCenter 登录涉及 Kerberos 令牌和 SAML 断言,对时间偏差非常敏感。我用下面的命令检查:
chronyc tracking如果 vCenter 和 AD 域控的时间偏差超过 5 分钟,STS 服务签发的令牌在验证时直接判失败,登录界面表现就是 500 获取身份提供程序时出错。你可以先手动对时,再观察服务是否恢复正常,但长期还是得配好 NTP。
2.4 证书和身份提供程序之间的关联
还有一个被很多人忽略的点:vCenter 7 的 vsphere-ui 和 nginx 之间走的是 HTTPS 通信,如果 vCenter 的机器证书过期或者没有被 vmafd 正确注册,nginx 到 vsphere-ui 的健康检查请求就会因 TLS 握手失败而失败,nginx 自然就报 no healthy upstream。
检查证书的方法:
/usr/lib/vmware-vmafd/bin/dir-cli cert --list这个命令能列出 vmafd 数据库中注册的机器证书信息,重点看有效期。如果证书快过期或已过期,即使服务都显示 Running,nginx 和 vsphere-ui 之间的通信也会断断续续。
另外,也要检查 vCenter 的系统时间是否在证书有效期范围内。证书的 notBefore 时间如果比当前时间晚,那就属于典型的“证书未生效”问题,通常是因为设备断电后时间跳变导致的。这种情况不需要重新申请证书,把时间修正后重启服务即可。
3. 实操解决:vsphere-ui 与 vmon 的调整
3.1 vmon 健康检查机制
vmon 是 vCenter Appliance 核心的进程管理守护程序,所有 vmware 组件都由它负责拉起和监控。每个组件在/usr/lib/vmware/vmon/vmon.d/目录下都有一个 JSON 配置文件,里面定义了服务的启动命令、停止命令、健康检查命令和超时时间。
vsphere-ui 的配置路径是/usr/lib/vmware/vmon/vmon.d/vsphere-ui.json。默认的健康检查逻辑是 vmon 周期性执行一个探测命令,检查 vsphere-ui 是否响应。如果健康检查命令本身因为环境问题卡住,或者超时时间设置太短,vmon 就会把健康状态标记为不健康。
很多实际的故障案例里,vsphere-ui 并没有真正挂掉,而是健康检查命令在执行时需要访问 vmafd,而 vmafd 恰好因为磁盘空间或网络问题响应慢,导致健康检查结果迟迟不返回,最后被判定为不健康。这里就有两种处理思路:一种是解决 vmafd 的响应慢问题,另一种是在确认服务本身正常的前提下,适当放宽健康检查参数。
3.2 修改 vsphere-ui 健康检查参数的完整步骤
我当时在确认磁盘清理后服务仍不稳定,决定调整 vsphere-ui 的健康检查参数。这个操作在 VMware 的 KB 里是有据可循的,我实际操作下来也确实有效。
先备份原配置:
cp /usr/lib/vmware/vmon/vmon.d/vsphere-ui.json /root/vsphere-ui.json.bak用 vi 打开配置文件:
vi /usr/lib/vmware/vmon/vmon.d/vsphere-ui.json找到 HealthCheck 字段,默认结构大致是:
"HealthCheck": { "TimeoutMs": 30000, "IntervalMs": 60000, "Command": "..." }我需要把健康检查的超时时间从 30 秒调大到 60 秒,同时把健康检查的执行间隔从 60 秒调到 90 秒。这么做的目的是避免因为偶发的高负载或慢 IO 导致健康检查误判。具体的调整依据是:在服务功能正常的情况下,健康检查超时时间过短是最常见的误判原因。
修改完保存后,关键一步是让 vmon 重新加载配置。直接重启 vsphere-ui 是不够的,需要执行:
/usr/lib/vmware/vmon/bin/update-vmon-config.py --component vsphere-ui --update这个命令会把 JSON 中的新配置同步到 vmon 维护的运行时配置中。然后依次重启 vmon 和 vsphere-ui:
service-control --restart vmon service-control --restart vsphere-ui注意顺序不要反。先重启 vmon 再重启 vsphere-ui,因为 vsphere-ui 的拉起和健康检查都依赖 vmon。
3.3 重启服务的正确姿势
如果服务状态已经很乱,我建议直接重启全部 vCenter 服务,而不是单独重启某几个:
service-control --stop --all等所有服务停止后,再统一启动:
service-control --start --all这个操作时间会比较长,一般需要 10 到 20 分钟,取决于 vCenter 配置和底层存储性能。有些人是直接重启整个 vCenter 虚拟机,这当然也可以,但如果你正在远程操作,重启虚拟机的风险更大,因为 vCenter 虚拟机起不来的时候你连管理入口都没有。所以我的习惯是优先用 service-control 重启服务,而不是直接重启虚拟机。
还有一个细节:重启服务后,要确认服务的实际监听端口起来了。vsphere-ui 默认监听的是 5096 端口左右,具体可以在 vsphere-ui 配置里查。用下面的命令确认端口:
netstat -tlnp | grep 5096端口存在且状态为 LISTEN,说明 vsphere-ui 确实起来了。这时候再回到 nginx 的日志,已经能看到健康检查请求恢复正常,no healthy upstream 不再刷屏。
4. 其他常见原因与暴力恢复方案
4.1 常见问题速查表
排查完这一整轮,我整理了 vCenter 登录 500 和 no healthy upstream 的常见原因对照表,方便大家按图索骥。
| 现象 | 可能原因 | 验证命令 | 解决方式 |
|---|---|---|---|
| 页面提示获取身份提供程序时出错 | vmafd 服务异常或身份源配置丢失 | service-control --status --all | 重启 vmafd,检查 /etc/hosts 与 DNS 解析 |
| nginx 日志报 no healthy upstream | vsphere-ui 健康检查不通过 | vmon-cli -l | 调整 vsphere-ui 健康检查参数或重启服务 |
| 服务状态反复 Degraded | 磁盘空间不足或 inode 耗尽 | df -h 和 df -i | 清理 /storage/log 和 /storage/archive 下日志 |
| 登录后长时间转圈然后 500 | STS 服务超时或证书异常 | dir-cli cert --list | 检查证书有效期,重启 sso 服务 |
| 重启服务后仍然报错 | vmon 配置与运行时不一致 | update-vmon-config.py --help | 重新同步 vmon 配置,再重启 vmon |
| 多台 vCenter 做了身份联合 | 身份提供程序本身不可达 | curl -k https://vcenter/websso/ | 检查对端 IdP 的健康状态和网络连通性 |
这个表格不是让你每行都试一遍,而是教你按优先级排除。我的实际顺序是:先确认服务状态和磁盘空间,再看日志定位具体是哪个 upstream 不健康,然后针对性地处理时间、证书等底座问题。
4.2 最后手段:证书修复与重置
如果磁盘、内存、时间、健康检查参数都调整了,问题还在,那就得考虑证书层面的修复。
vCenter 的机器证书出现问题时,最直接的表现就是各个组件之间互相 TLS 握手失败,但日志里不会直接写“证书过期”,而是表现为各种连接重置或握手超时。如果你在 nginx 日志里看到SSL certificate verify failed或handshake failed这类信息,基本就是证书问题没跑了。
证书修复的一个可行思路是重新生成机器证书,操作之前一定记得把现有证书备份好。我的操作是:
service-control --stop --all然后使用certool相关命令重新初始化证书相关配置。这块操作比较复杂,而且不同 vCenter 版本的命令细节有差异,我的建议是优先参考官方文档中关于“重置 vCenter 机器证书”的部分,不要自己凭记忆写命令。
不过在实际运维中,证书问题并不是登录 500 的第一嫌疑。因为证书问题往往会在重启服务后立即暴露,而不会只表现为偶发的不健康。所以如果你们的问题断断续续出现,先把证书这条线放一放。
4.3 后续整改建议
问题解决后,不能只是高兴一下,我建议你顺手做几件事,避免下次再踩坑:
给 vCenter 做一次完整快照。这听起来像废话,但很多人在 vCenter 出问题后才后悔没有快照。尤其在调整 vmon 配置、执行服务重启前,快照是最后的后悔药。
把/storage/log分区的日志轮转策略检查一遍。vCenter 默认的日志轮转在某些版本里配置得不够激进,大日志文件一旦累积到 GB 级别,非常容易把分区塞满。你可以部署一个简单的定时任务,定期清理/storage/archive下的旧日志,只保留最近 30 天。
监控 vCenter 虚拟机的磁盘 IOPS 和延迟。vCenter 对底层存储性能非常敏感,尤其是 vmafd 和 vsphere-ui 依赖的元数据写入。如果存储延迟过高,服务健康检查就会超时,和这次的问题表现完全一样。
还要养成定期检查证书有效期的习惯。vCenter 7 的生命周期里,机器证书默认有效期是两年左右,如果你很久没有更新 vCenter,证书过期引发的登录问题非常隐蔽。
5. 我再提醒几个容易被忽略的操作细节
最后补充一些我在排查过程中总结的操作细节,这些内容不一定在官方文档里写得明确,但对于快速定位问题有很大帮助。
第一,vCenter 的 SSH 端口默认不是 22,而是 22 端口没错,但 root 用户登录默认会被禁用,如果你没有在 vCenter 里手动启用 SSH 和 root 访问权限,遇到登录故障时会非常被动。我的习惯是在 vCenter 部署完成后就开启 SSH 服务,但严格控制访问来源,只允许管理网段的地址连接。
第二,vmon 配置文件的修改不要乱来。/usr/lib/vmware/vmon/vmon.d/下的 JSON 如果修改不当,会导致 vmon 直接启动失败,变成更大的事故。我修改前一定先备份,并且只修改确认过体积的参数,比如 HealthCheck 的 TimeoutMs 和 IntervalMs,其他字段看不懂就不要动。
第三,定期检查/etc/hosts文件。vCenter 对于主机名的解析方式很挑剔,如果/etc/hosts里主机名解析记录被改写,或者 DNS 里 vCenter 的解析结果指向了错误 IP,所有依赖本机身份的组件都会异常。这个原因在很多时候是坑中之坑,因为 vCenter 本身能 ping 通,表面看网络没问题,但身份组件就是起不来。
第四,不要在登录故障时反复刷新浏览器页面。这不是说浏览器会弄坏 vCenter,而是大量并发请求会加重已经处于亚健康状态的 vsphere-ui 和 nginx 的负担,导致问题更加复杂。我一般建议先停一停,在 SSH 命令行把服务状态弄清楚,再打开浏览器验证。
根据我自己的操作经验,这种“500 获取身份提供程序时出错”加 no healthy upstream 的组合报错,八成以上都和服务健康检查有关,而深层原因又离不开磁盘、内存、时间、证书这几个底座因素。只要按照日志驱动的思路,先确认 no healthy upstream 具体指向哪个服务,再逐层检查依赖,通常能在半小时内定位到根本原因。调试过程中别急着改配置,多看一眼日志,很多答案就写在里面。