由于 Elasticsearch 索引问题导致 SonarQube Pod 启动失败
目录
问题描述根本原因故障排查步骤 1 — 区分“恢复过慢”和“索引损坏”步骤 2 — 检查失败组件对应的 Pod 日志解决方案选项 A — 给恢复更多时间(恢复过慢)选项 B — 重置 Elasticsearch 索引(索引损坏)B.1 — 从正在运行的 Pod 内部执行(PVC 或临时存储)B.2 — 使用localpath 存储时步骤 3 — 验证恢复注意事项问题描述
SonarQube Pod 无法变为 Ready,并且会反复重启。常见症状包括:
-
Pod 处于
CrashLoopBackOff状态,重启次数每隔几分钟就会增加。 -
Pod 日志在启动期间包含从
org.sonar.server.es.IndexCreator抛出的NullPointerException。 -
Pod 日志显示启动卡在 Elasticsearch 数据恢复阶段,例如:
最终 Pod 会被 liveness 或 readiness 探针杀死。
在这些情况下,PostgreSQL 是健康的(其 Pod 处于 Running 且未重启);只有 SonarQube Pod 处于不健康状态。
根本原因
SonarQube 在 /opt/sonarqube/data/es8 下嵌入了一个 Elasticsearch 实例(该目录与嵌入式 Elasticsearch 的主版本匹配;较旧的 SonarQube 版本使用 es7)。以下两种相关情况都可能导致启动失败:
- Elasticsearch 索引损坏。 索引文件处于不一致状态——通常是由于非正常关机、存储故障,或磁盘空间耗尽。SonarQube 无法打开索引,web 进程会中止。对于全新实例,这会表现为
IndexCreator的NullPointerException;对于已有实例,则会表现为启动循环。 - 恢复过慢被探针终止。 Elasticsearch 能够恢复索引,但恢复时间超过了 liveness 或 readiness 探针允许的时长,因此 Pod 在恢复过程中被杀死,循环不断重复。
SonarQube 中的 Elasticsearch 数据属于派生状态。它会在下次启动时从 PostgreSQL 自动重建,因此删除索引不会丢失用户数据——只是会在首次启动时多花一些时间来重新创建索引。
故障排查
步骤 1 — 区分“恢复过慢”和“索引损坏”
检查最近的重启历史以及每次重启的原因:
- 如果你看到
Last State: Terminated,并且在探针失败后立即出现Reason: Error(例如Liveness probe failed),同时日志最后还在输出恢复进度,则说明 Pod 正在恢复过程中被杀死。应将其视为恢复过慢。 - 如果日志以堆栈跟踪结尾(例如来自
IndexCreator的NullPointerException,或IndexNotFoundException),并且 Pod 重启时没有任何探针失败事件,则应将其视为索引损坏。
步骤 2 — 检查失败组件对应的 Pod 日志
确认故障源自 SonarQube 进程(而不是 PostgreSQL)。相关行通常会引用 IndexCreator、ElasticSearch,或 es7/es8 路径。
解决方案
选择与步骤 1 相匹配的选项。
选项 A — 给恢复更多时间(恢复过慢)
如果 Pod 在恢复过程中被杀死,可临时放宽或移除 liveness 和 readiness 探针,这样 Pod 就不会在较长的首次恢复期间被重启。编辑 SonarQube Deployment(你可能需要在 Deployment 上设置 skip-sync: "true" 注解,以防 operator 回滚你的更改):
移除或显著增大 livenessProbe 和 readinessProbe 中的 initialDelaySeconds / failureThreshold,然后等待 Pod 完成恢复并变为 Ready。一旦稳定,再移除 skip-sync 注解,以便在下一次 reconcile 时恢复原始探针配置。
选项 B — 重置 Elasticsearch 索引(索引损坏)
删除磁盘上的索引,使 SonarQube 在下次启动时重新构建它。具体操作取决于数据卷的供应方式:
B.1 — 从正在运行的 Pod 内部执行(PVC 或临时存储)
如果 Pod 无法持续运行到足以执行 exec,则先将 Deployment 缩容,把 PVC 挂载到一个调试 Pod 中(kubectl debug,或者使用挂载相同 PVC 的小型 Pod 清单),在其中执行重命名操作,然后再将原始 Deployment 扩容回来。
B.2 — 使用 localpath 存储时
登录到承载 SonarQube Pod 的节点,找到节点 localpath 根目录下的 SonarQube 数据目录,并重命名或删除 es* 目录:
然后触发 Pod 重启:
步骤 3 — 验证恢复
等待 Pod 变为 Ready,然后在 SonarQube UI 中确认项目、问题和规则能够正常渲染。重新索引后的首次扫描可能会比平时更久,因为索引正在重新填充。
如果索引已重置但 Pod 仍然无法启动,则故障并非 Elasticsearch 问题——在重试之前,请重新检查 Pod 日志以确认底层错误。
注意事项
- 存储空间。 这两种失败模式通常都由数据卷磁盘空间耗尽引发。在判断索引损坏之前,请在 Pod 内(或节点上的对应路径)检查
df -h /opt/sonarqube/data,如果已满则增大卷大小。 - 备份。 选项 B 中创建的
es8.bak目录可在 SonarQube 再次稳定后删除。在此之前请保留它,以便需要回滚时使用。 - 官方指导。 SonarQube 文档中关于强制执行 Elasticsearch 重新索引的操作步骤,是该场景的上游参考:参见 重新索引。