该文章主要是用来记录作者在用ES做RAG的BM25检索中的一些问题,主要还是聚焦kibana(ES可视化界面)与ES启动失败的问题,作者花费了整整半天的时间终于解决了,其中涉及到的一些思路与解决方案还是挺有用了,所以想分享一下
一:问题引入
这个问题就是我们该笔记重点讲解的内容,或取很多人看见这个标志还傻傻的等,以为kibana和es服务器还没启动,要等上几分钟,博主其实和你们也是一样想的,其实后面研究下来发现这种情况大部分还是因为你哪里出问题了导致服务连接不上,卡在这里了
通常出现这个标志,原因是: 后端初始化没完成,暂时不让你用界面。
1、本质原因
Kibana 启动要做几件关键事,全部完成才会变成 “Ready”:
- 连到 Elasticsearch(ES)
- 检查版本兼容(Kibana 与 ES 主版本必须一致,如 8.11.x)
- 读写自己的元数据索引
.kibana(保存仪表盘、可视化、配置) - 执行插件 / 系统升级或数据迁移
只要某一步卡住、超时或失败,就会一直显示 not ready。
2、最常见的 6 种原因
-
ES 没启动 / 连不上
- ES 没起来,或地址 / 端口写错(
elasticsearch.hosts) - 网络不通、防火墙拦截 9200 端口
- ES 开启认证,但 Kibana 用户名 / 密码错误(
elasticsearch.username/password)
- ES 没起来,或地址 / 端口写错(
-
版本不匹配
- Kibana 8.10 连 ES 8.11 → 直接拒绝启动
- 主版本必须完全一致(如都是 8.11.3)
-
资源不足(内存 / CPU / 磁盘)
- Kibana 默认堆内存小(
--max-old-space-size),大数据 / 插件多时不够用 - ES 或 Kibana 所在磁盘满、IO 高,导致读写超时
- Kibana 默认堆内存小(
-
.kibana 索引损坏 / 卡住
- 上次异常关机,
.kibana索引损坏 - 升级中途失败,迁移任务卡死
- 上次异常关机,
-
配置错误(kibana.yml)
- SSL 配置错误(ES 开了 HTTPS,Kibana 没配证书或验证)
- 超时时间设太短(
elasticsearch.requestTimeout默认 30s)
-
插件冲突或损坏
- 安装了不兼容的第三方插件
- 插件文件损坏导致初始化失败
这是博主结合ai生成的常见原因,这些原因实测下来基本能够解决我们的目前问题,博主就是出现了上面其中的一个原因,现在来解释一下我的问题
二:具体解决的流程(可能很长,主要提供思路)
1.首先判断是kibana服务问题还是es的问题,这里博主之前一直分不清,一直以为“kibana is not ready”就是kibana的服务配置哪里出问题了,但是实际并不是这样
博主这里演示一下:
(1)
可知如果kibana服务出问题了,那大概率是我们根本无法访问5601端口(我们自己设置的kibana容器对外端口),所以“kibana is not ready ”这个页面的出现很大概率就是因为ES服务器问题。这里我们用的是portainer容器来可视化我们的云服务器的各个容器
(2)
此时我们一定要去看kibana的日志,如果连接不上es,他这里会报connect Exception,对于这一块,直接把欸之丢给ai就可以了,重点看到底哪里出问题了,一般如果es连接不上,绝大概率会在kibana日志中显示
2.通过上面就可以推断是kibana还是是es的问题了,绝大部分情况就是es的问题,下面博主分享一下自己项目中es的问题
(1)首先博主遇到的是权限问题,就是说我们的ES的data文件夹(主要数es数据存放的地方)挂载了数据卷目录,但是启动项目是显示ES出问题了
核心错误解读
- 错误类型:
ElasticsearchException[failed to bind service] - 根本原因 (Root Cause) :
java.nio.file.AccessDeniedException: /usr/share/elasticsearch/data/nodes - 含义:Elasticsearch 试图在数据目录下创建节点文件夹,但操作系统拒绝了该操作。
为什么会出现这个问题?
这通常发生在 Docker 部署中,原因如下:
-
用户 ID (UID) 不匹配:Elasticsearch 官方镜像默认使用用户
elasticsearch(UID 1000) 运行。 -
挂载目录权限问题:你将宿主机的一个目录挂载到了容器的
/usr/share/elasticsearch/data。如果这个宿主机目录的所有者是root,或者其他没有写权限的用户,容器内的elasticsearch用户就无法在里面写数据。
解决方案,通过chmod指令赋予data文件权限,如果想要省事可以直接赋予全部权限
(2)随后,我有看到了我们es的模块一直在重复加载,一直在循环,很奇怪,第一次遇见这种情况,就很懵逼,这里一定要查看es的日志,我用的是portainer的log功能看日志,也可以通过docker log指令查看日志
这里的问题博主第一次遇见,直接就傻眼了,随后通过问ai,我有手动尝试替换官方的镜像,说国内镜像网站可能会有点问题,比如内置的基础镜像,像jdk版本不一样,导致es启动失败啥的啥的,然后博主替换为官网的后还是不行
发现这和镜像本身问题不大,肯定是ES服务启动过程哪里有问题了
然后博主又手动在宿主机测试ES的连接,curl http://localhost:9200/_cluster/health?pretty,检查 Elasticsearch 健康状态
这里可以看见是ES服务连接上了,但是又立马断开了,ES在启动过程有问题,导致没有启动成功
这里博主又尝试了几次,发现有的能够读取ES返回数据,但是大部分情况是ES断开连接,相当于ES在"连接"与“断开”之间反复横跳,这就更奇怪了,要连上就连上,连不上就连不上,哪有这种的
忽然间,博主脑子突然想到了,我们的docker-compose设置了ES容器自启动,会不会是因为什么原因导致ES启动失败,又因为重启机制,ES又活过来了,然后在不断的“重启”-“强制关闭”之间反复横跳在,期间ES会有机会连接成功,但是突然间有关闭了
(3)于是博主继续查,ai提到的一点是ES设置的可支配内存太小了,导致ES的内存不够用,而ES本身是个很吃内存的工具,所以因为这个原因导致上述的问题,就会关闭后又启动。博主突然间就感觉很有道理
于是博主继续扩大ES堆内存空间,设置为1GB,发现问题还是解决不了,这里因为修改后问题还是没有解决,就不放截图了,而且博主刚开始还以为是ES的空间还是不够用,导致的,但是转念一想不合理啊,博主ES根本没有什么数据,怎么可能就一个启动就直接吃掉1gb,非常不合理,所以博主又陷入了苦恼
(4)突然间,博主发现了问题的根源,为什么cpu和内存占用率这么高,结合上文提到了ES的堆内存分配,因为博主用的是腾讯云服务器,最大内存为4gb,原因不是ES的内存过少,而是云服务器的内存太少,或者被什么给占用了,会不会是因为内存不足导致 ES 崩溃 -> 容器重启 -> 再次因内存不足崩溃” 的死循环,导致系统瘫痪
“容器设置为自启动”是关键。Docker 默认的重启策略(Restart Policy)是always。
- 现象:你看到 ES 在“重复加载模块”。
- 真相:这并不是它在“死循环加载”,而是它刚启动还没来得及完全初始化,就被杀死了,然后 Docker 又立刻拉起一个新的进程。
- 日志佐证:Kibana 日志中的
ECONNREFUSED证明 ES 要么不存在,要么正处于“刚醒过来就被掐脖子”的瞬间,根本无法响应请求。
思路突然明朗了,于是博主赶紧用top指令查cpu占用情况
发现mysql吃掉了百分之143.9的内存,这非常不正常,于是博主用kill指令强制杀掉mysql的进程
sudo kill -9 685719
可以看见cpu使用率直接下降了
这里正常进入了kibana,说明ES服务器成功启动了
(5)这里还要说一下,我们的ES和kibana等docker容器的端口一定要开放,不然连接不到服务器,自然也用不了我们的容器服务了,每个人的容器映射端口不一样,要按自己的端口开放
这是博主租用的腾讯云服务器,用来给我们的智能体项目使用的,可以在“防火墙”一栏配置端口开放
3.一些其他问题
或许会有人问,问题不是解决了吗,还能有啥问题,但是对于博主特殊情况,我遇见的问题不是单纯的内存占用问题,还记得我们上面给你看见的一个mysql的进程吗,我们强制杀掉进程后,他又重新启动,而且重新吃内存,这绝对不是一个简单的问题
继续排查后,发现这个mysql根本不是我们的容器,换句话说,博主也不知道这个mysql是啥,既然我们的容器没有mysql,那很有可能我们的宿主机安装了mysql,让它成为我们的一个系统服务了,于是我们用
systemctl status mysql指令查证
发现也没有这个服务,这就奇怪了,这个mysql到底是从哪里蹦出来的,博主很确定博主在云服务器没有安装过任何mysql类的,因为博主的项目用的是自己的本地电脑的mysql,于是博主打算用
ps -fp mysql的进程ps指令来查找当前mysql的进程的父进程ID,层层溯源,来找到到底是谁启动了mysql,下面是ps指令的讲解
ps -fp 715376 命令完整解释
这是 Linux 系统查看进程信息 的核心命令,专门用来查 PID=715376 这个进程的详细状态。
- 命令整体作用
ps -fp 715376
意思:查看 进程 ID(PID)=715376 的完整详细信息。
结合刚才的 Kibana 问题,这个命令就是用来:✅ 看 Kibana 到底有没有在运行✅ 看它的启动命令、运行用户、状态✅ 判断它是不是卡住了(对应
server is not ready)
- 每个参数是什么意思?
| 参数 | 作用 |
|---|---|
ps | process status,查看进程的命令 |
-f | full format,显示完整详细信息(完整命令行、父进程等) |
-p | 指定 PID,只看这个进程 |
715376 | 要查询的进程 ID 号 |
- 执行后输出字段解释(最实用)
你会看到类似这样的结果:
UID PID PPID C STIME TTY TIME CMD
kibana 715376 1234 0 10:00 ? 00:02:12 /usr/share/kibana/bin/kibana
字段含义:
- UID:运行这个进程的用户(kibana)
- PID:进程 ID(715376)
- CMD:进程真正执行的命令(这里就是 Kibana)
- ? :表示后台运行(正常)
- TIME:已运行时间
# 查看所有 kibana 进程
ps -ef | grep kibana
# 实时看 kibana 进程状态
top -p 715376
但是实际用下来发现不行,每次一出现mysql进程,我们通过用他的进程ID的查询指令,mysql会占用cpu将近100%,该指令就会卡死,没有任何输出,等mysql进程被系统强制杀死,我们就无法通过该指令查找任何信息,因为这个进程已经被关闭了,于是我们打算采取查询宿主机的系统日志
journalctl -b | grep -Ei 'mysql|mariadb|mysqld|percona' | tail -n 50
命令完整拆解:journalctl -b | grep -Ei 'mysql|mariadb|mysqld|percona' | tail -n 50
这是一条Linux 排查数据库日志的组合命令,作用是:只看【本次开机以来】所有 MySQL / MariaDB 相关的【最后 50 行日志】 ,专门用来查数据库报错、启动失败、崩溃、连接问题。
- 逐段拆解
① journalctl
Linux 系统统一日志工具,几乎所有服务(MySQL、Kibana、ES、Nginx)的日志都能看。
② -b
= --boot意思:只看【本次开机以来】的日志(过滤掉之前重启、历史日志,只看当前运行环境的日志)
③ |
管道符:把前一个命令的输出,传给后一个命令处理
④ grep
过滤关键词,只保留包含指定内容的行
⑤ -Ei
-E:支持多关键词匹配(用|分隔)-i:忽略大小写(MYSQL、MySQL、mysql 都能匹配到)
⑥ 'mysql|mariadb|mysqld|percona'
要过滤的4 个数据库关键词,匹配所有常见 MySQL 系服务:
- mysql = MySQL 客户端 / 服务
- mariadb = MariaDB(MySQL 分支)
- mysqld = MySQL 守护进程(核心服务)
- percona = PerconaDB(MySQL 优化版)
⑦ tail -n 50
只显示最后 50 行日志(最新的报错永远在最后面,不用翻几百行)
- 整句翻译
journalctl -b | grep -Ei 'mysql|mariadb|mysqld|percona' | tail -n 50
大白话:
显示「本次开机以来」的系统日志,只过滤出 MySQL / MariaDB 相关日志,并且只保留最新的 50 行给我看。
- 这个命令能帮你查什么?
- MySQL 启动失败
- MySQL 崩溃、自动退出
- 数据库端口被占用
- 密码错误、权限错误
- 磁盘满、内存不足导致数据库挂掉
通过这个指令,将日志发给ai,我们分析出这个mysql不是系统服务,而是容器内启动的,最终定位在我们的vector_db容器,这个容器是我们项目中的postgres的向量数据库,按道理说他不应该启用mysql的进程,通过保险起见,我们用
docker stats --no-stream来看容器具体占用cpu的情况
这是 Docker 查看容器资源占用 的命令,专门用来一次性打印所有容器当前的 CPU、内存、网络、磁盘使用情况,然后自动退出。
- 逐段拆解
docker stats:查看正在运行的 Docker 容器的实时资源占用(默认会一直刷新,像任务管理器一样动个不停)--no-stream:禁用实时刷新,只输出当前这一刻的状态,然后立刻结束
- 它能告诉你什么?
执行后会显示类似这样的内容:
CONTAINER ID NAME CPU % MEM USAGE / LIMIT MEM %
05ef97831e01 kibana 150.3% 1.2GiB / 3.5GiB 34.2%
abc123456789 elasticsearch 200.5% 2.0GiB / 3.5GiB 57.1%
关键字段:
- CPU % :容器占用的 CPU 百分比(超过 100% 就是多核在跑)
- MEM USAGE:容器用了多少内存
- MEM % :内存使用率
- NET I/O:网络流量
- BLOCK I/O:磁盘读写
- 为什么要用
--no-stream?
- 默认
docker stats会一直刷屏,你没法复制、没法看静态结果 - 加了
--no-stream就是截一张图,方便你看哪个容器把服务器 CPU / 内存吃满了
结合目前情况
我们服务器 CPU 99%、内存 94% ,用这条命令能立刻定位元凶:
docker stats --no-stream
执行后你就能看到:✅ 哪个容器占 CPU 最高✅ 哪个容器占内存最高✅ 就是它导致 Kibana 起不来、系统卡死
可以看见我们的元凶就是vector_db这个向量数据库容器,他为什么会启动mysql进程,这不现实,于是博主立马查询他的日志
博主结合分析了一下,知道问题的根源了
攻击实录:恶意的 SQL 注入
日志中这一段非常长且包含 base64 编码的内容,是攻击的核心:
STATEMENT: DROP TABLE IF EXISTS tests; ... COPY tests FROM PROGRAM 'echo ... |base64 -d|bash'
手段:攻击者利用了 PostgreSQL 的 COPY ... FROM PROGRAM 功能。这是一个极其危险的功能,允许数据库执行操作系统命令。
目的:这段 Base64 解码后是一个 Shell 脚本,它做了两件事:
- 下载挖矿木马:它通过 curl 从 IP 181.214.147.108 下载了一个名为 bot 的文件到 /tmp/bot。
- 清理竞争对手:脚本中包含了一段 for pid in /proc/[0-9]* 的循环。它会扫描系统进程,如果发现有其他挖矿程序(如 kdevtmpfsi、xmr、watchdog 等),就使用 kill -9 将其杀死。这是典型的“黑吃黑”行为,为了保证它自己的木马能独占 CPU 资源。
通过ai的分析,博主发现是自己向量数据库的问题,可能泄露啥的
我们进入了内部发现确实给我们的vector_db内部添加了一个mysql和init脚本,这也印证了为什么这个进程中会出现mysql的问题,我们每次删除了他就自动下载,自动启动,占满我们的cpu和内存
现在,让我们回到 PostgreSQL 日志。攻击者能成功执行 COPY ... FROM PROGRAM 这种危险命令,通常意味着数据库的权限配置存在严重漏洞。 最常见的情况是,
- 配置文件 pg_hba.conf 中设置了 trust 认证。
- trust 认证:意味着“信任”所有连接,不需要密码就能直接登录数据库。这相当于你家大门敞开,任何人都能进来。
- md5 或 scram-sha-256 认证:这才是安全的模式,要求连接者必须提供正确的密码。
docker exec -it 05ef97831e01 bash进入我们的容器,cat /var/lib/postgresql/data/pg_hba.conf查找postgres向量库的配置文件
这是 **PostgreSQL 的权限配置文件 pg_hba.conf**作用:控制谁能连数据库、用什么方式连、需不需要密码
逐行解释(超级易懂)
# TYPE DATABASE USER ADDRESS METHOD
只是注释标题,不用管
local all all trust
本地(容器内)连接,全部免密码信任→ 本地连 PG 不用密码
host all all 127.0.0.1/32 trust
host all all ::1/128 trust
本机 IPv4/IPv6 连接,全部免密码信任→ 本机连 PG 不用密码
local replication all trust
host replication all 127.0.0.1/32 trust
host replication all ::1/128 trust
主从复制权限,也是本机免密
致命危险行(你被黑的真凶)
host all all 0.0.0.0/0 md5
翻译成人话:
允许 全世界任何 IP(0.0.0.0/0)连接 任何数据库用 任何用户只需要密码(md5)即可登录
为什么这等于 “开门揖盗”?
因为:
- 数据库端口暴露在公网
- 全世界任何人都能尝试连接
- 攻击者用弱口令爆破(比如 postgres /postgres )
- 一破成功,就能执行任意 SQL、任意系统命令
- 最终:被种挖矿木马 → 内存爆满 → Kibana 起不来
我们之前就是因为postgres没有设置密码验证功能,导致所有人都可以访问我们的向量数据库,出现了上面的漏洞风险,这里我们已经修复过了,使用了md5密码验证,可以快速通过
docker exec -it 05ef97831e01 bash(快速进入容器),cat /var/lib/postgresql/data/pg_hba.conf(快速查找标注为trust的权限项),sed -i 's/^host all all all trust$/host all all 0.0.0.0\/0 md5/' /var/lib/postgresql/data/pg_hba.conf(将他们设置为密码登录),之后重启容器即可 ,然后我们通过下面的指令来设置密码,用于我们的连接docker exec -it 05ef97831e01 psql -U postgres,
这是我们重新设置密码界面,具体密码就不展示了
通过datagrip成功用密码连接到数据库
云服务器cpu和内存成功回到正常值,至此解决了所有牵连的问题,算死累死博主了