milvus-standalone启动失败unhealthy,错误日志context deadline exceeded
目录
- 前言
- 问题现象
- 排查过程
- 更新docker-compose
- 排查standalone unhealthy问题
前言
最近公司有个项目,需要安装向量数据库milvus,但是安装过程不太顺利,连续出现了容器134异常退出和容器和容器之间网络调不通的问题,这篇博客主要讲述排查思路,最后怎么解决的,出现类似的问题,都可以按照这篇博客的思路向下逐步排查,原因可能跟我的不一样,但是思路是一样的,顺着这个思路排查就一定可以解决你们的问题,还有一点就是这篇博客的部分截图是解决好之后的截图,着重看我的文字说明,希望 能解决你们的问题。
问题现象
- standalone服务出现134异常退出
- 容器可以启动,但是standalone服务的状态是unhealthy
# docker-compose psName Command State Ports
----------------------------------------------------------------------------------------------------------------------
milvus-etcd etcd -advertise-client-url ... Up (healthy) 2379/tcp, 2380/tcp
milvus-minio /usr/bin/docker-entrypoint ... Up (healthy) 0.0.0.0:9000->9000/tcp, 0.0.0.0:9001->9001/tcp
milvus-standalone /tini -- milvus run standalone Up (unhealthy) 0.0.0.0:19530->19530/tcp, 0.0.0.0:9091->9091/tcp
排查过程
如果你的milvus部署完成后,没有出现容器异常退出的问题,说明你的docker-compose版本是没有问题的,直接看排查standalone unhealthy问题这个目录就可以了
更新docker-compose
- 如果standalone直接错误码134退出,这种情况我们想看容器内部日志都没法看,原因就是docker-compose版本过低,我们需要更新docker-compose工具的版本,先升级到v2.5以上,低版本的docker-compose遇到网络、依赖问题等会直接退出,而较新的版本失败后会自动重试,这时候我们可以进入容器,查看日志,以便更好的排查问题
- 更新docker-compose的过程也比较简单,docker-compose就是一个Linux可执行文件,直接下载好新的版本后,放到Linux宿主机指定目录即可
# 先检查版本
docker-compose --version
# 删除旧的docker-compose二进制文件
sudo rm /usr/local/bin/docker-compose
# 下载指定版本的docker-compose,放到/usr/local目录,替换掉旧的,也可以手动下载放进去
sudo curl -L https://github.com/docker/compose/releases/download/v2.39.2/docker-compose-linux-x86_64 -o /usr/local/bin/docker-compose
# 赋予文件权限
sudo chmod +x /usr/local/bin/docker-compose
# 检查下是否安装成功
docker-compose --version
排查standalone unhealthy问题
- 第一步永远是看日志,看下standalone 容器的运行日志,着重看一下最后几十行,如果看不出来,就要全篇看下,也可以根据error等异常关键字,利用grep 管道符过滤一下日志。
- 通过命令
sudo docker-compose logs standalone
查看容器日志,如果是容器间网络问题,你就会看到下面这样的日志片段,因为standalone主服务依赖etcd服务,连接不上etcd服务,standalone就会一直尝试重新建立连接,最后的运行状态就是unhealthy
milvus-standalone | {"level":"warn","ts":"2025-09-01T08:06:06.879Z","logger":"etcd-client","caller":"v3@v3.5.5/retry_interceptor.go:62","msg":"retrying of unary invoker failed","target":"etcd-endpoints://0xc001c00000/etcd:2379","attempt":0,"error":"rpc error: code = DeadlineExceeded desc = latest balancer error: last connection error: connection error: desc = \"transport: Error while dialing: dial tcp 192.168.96.3:2379: i/o timeout\""}milvus-standalone | [2025/09/01 08:06:09.780 +00:00] [DEBUG] [sessionutil/session_util.go:246] ["Session try to connect to etcd"]
milvus-standalone | [2025/09/01 08:06:09.880 +00:00] [DEBUG] [sessionutil/session_util.go:246] ["Session try to connect to etcd"]
- 确定是网络问题之后,首先看下这三个容器是不是在一个网桥上,这个是通信的基础,在standalone 的docker-compose.yaml配置文件末尾一般会创建公共的虚拟网桥milvus,创建的三个容器会连接在这个网桥上,一般问题不会出现在这,但是还是要首先排除掉这个因素
- 通过docker network ls 查看是否有milvus这个网桥,然后通过docker network inspect milvus 查看milvus网桥上是否连接了standalone 的三个容器
- 如果看到milvus网桥上正常挂载了这三个容器,就说明没有问题,继续向下排查
- 下一步我们要排查etcd服务是否正常启动,是否在正常监听2379端口,因为standalone 连接不上etcd,可能是容器间网络不通,也可能是etcd没有正常运行或者没有正常监听自己的2379端口
- 首先通过
docker-compose ps
看下etcd服务的运行状态是不是healthy,是的话继续排查有没有正常监听2379端口,不是的话要进入etcd容器,看下日志,具体问题具体分析。一般情况下如果etcd服务的状态是healthy的话,是会正常监听2379端口的,但是以防万一还是要继续排除掉这个因素。 - 通过etcd自带的etcdctl工具就可以确定其是否正常监听2379端口,查看
docker exec milvus-etcd etcdctl endpoint health
命令,出现下面的结果就说明etcd服务是没有问题的。
- 不放心的话,也可以查到容器的内网ip,在宿主机上直接ping,看能不能ping通。通过命令
docker inspect -f '{{range .NetworkSettings.Networks}}{{.IPAddress}}{{end}}' milvus-etcd
找到etcd容器的真实ip,然后通过telnet命令测试容器端口是否正常监听,出现connectd to…就说明是没有问题的
- 那现在基本可以确定就是容器间网络不通的原因,所以很自然的想到要进入standalone 容器,看是否能ping通etcd容器,大概率问题出在这
- 但是有个棘手的问题,standalone 镜像中的系统镜像是一个非常精简Ubuntu的镜像,没有安装ping工具,此时,我们可以进入容器通过apt工具安装ping,但是一般这种方式会因为网络的问题失败,有兴趣的道友可以试试,反正我没成功过,这里主要讲下一种方式,为 standalone 服务创建自定义镜像,在standalone 的Dockerfile镜像文件中指定安装ping
- 在milvus的docker-compose.yml文件的同级目录中创建package目录,在宿主机上将ping的工具包下载到package目录中
# 创建目录并下载 iputils-ping 及其直接依赖,注意你此时的目录应该是milvus的工作目录,目录中应该包含docker-compose.yml
mkdir -p ./packages
cd ./packages
apt-get download iputils-ping libcap2-bin libcap2 libc6
- 在宿主机上下载好ping的安装包后,继续在同级目录中创建Dockerfile文件,文件内容如下所示,直接复制进去
FROM milvusdb/milvus:v2.3.3RUN mkdir -p /tmp/package
# 只拷贝所需的包
COPY package/*.deb /tmp/package/
# 按顺序安装,先安装依赖库,再安装主包
RUN dpkg -i /tmp/package/libc6_*.deb && \dpkg -i /tmp/package/libcap2_*.deb && \dpkg -i /tmp/package/libcap2-bin_*.deb && \dpkg -i /tmp/package/iputils-ping_*.deb || \(apt-get update && apt-get install -f -y)
- 然后修改docker-compose.yml文件内容,只修改standalone 服务的镜像内容即可,其他内容都不需要修改
standalone:container_name: milvus-standalone# 只修改下面这两行,注释掉image这一行,加上build这一行build: .# image: milvusdb/milvus:v2.3.3command: ["milvus", "run", "standalone"]security_opt:- seccomp:unconfinedenvironment:ETCD_ENDPOINTS: etcd:2379MINIO_ADDRESS: minio:9000
-
执行sudo docker-compose down 先删除所有容器,再执行sudo docker-compose up -d 重建容器,此时再进入standalone容器,就会发现可以执行ping命令了,说明ping工具包已经正确安装到容器内部了
-
现在我们可以正式排查 容器间的网络连通性了,逻辑上只要能在standalone容器中ping通etcd容器,就彻底解决问题,因为etcd已经确定是在正确监听2379端口。
-
进入standalone容器内部,然后ping etcd,如果ping不通,100%丢包,那问题就在容器间的网络连通性上,下面的截图是解决后的结果,可以看到etcd有持续的数据响应。
-
docker容器之间的数据传输是需要宿主机转发的,准确的说是需要宿主机的iptables的 FORWARD 链路进行转发,可以把iptables理解成 门卫+路由器 合体。它根据你设定好的规则,决定哪些网络数据包可以进来、可以出去,或者需要他帮助转发
-
FORWARD 链 是 iptables 内置的五个核心“链”之一,它专门负责处理那些需要经过本机转发的数据包,docker网络间的数据传输默认就走的这个链路,FORWARD 链的默认策略是DROP,也就是丢包,也就是说如果你想让这个链路能够正常转发数据包,就得需要你明确配置规则允许转发,否则所有转发流量都会被拒绝
-
而docker容器启动的时候会自动创建FORWARD 链的规则,以允许docker容器间的数据包通信,因此,此时我们可以看下FORWARD 链的规则,看看有没有docker启动时创建的转发规则。
-
执行
sudo iptables -L -n -v
查看filter表规则,这个filter 表主要负责网络流量的过滤,决定数据包是放行、丢弃还是拒绝,这是最常用的表,通过下图可以看到FORWARD 链路上有docker创建的规则,如果没有,就找到问题所在了
-
再执行
sudo iptables -t nat -L -n -v
查看nat表规则,可以把这个表理解成 支撑docker容器端口映射的,正常来说,这两张表都会有docker创建的规则,如果没有,问题一般出现在docker的配置文件、或者iptable规则混乱
- 我的就出现在docker的daemon.json配置文件上了,不知道之前谁配置的,把创建iptables规则这个功能给关闭了,所以就导致宿主机不能正常转发docker容器间的数据包,因此,去掉这个配置或者把false改成true,然后执行sudo systemctl restart docker 重启docker服务就可以了
- 再执行sudo docker-compose up -d 重新部署milvus服务,就可以了
- 如果配置文件没有问题,没有iptables这个选项,那一般刷新下iptables规则,一般就可以了
sudo systemctl stop firewalld
sudo systemctl stop docker
sudo iptables -F
sudo systemctl start docker