RustFS 容器健康检查问题排查文档
1. 问题描述
RustFS 容器启动后,Docker Compose 显示容器状态为 (unhealthy):

容器虽然正常运行(9001、9002 端口均正常监听),但健康检查持续失败,导致 Docker 认为容器不健康。
在通过 Docker Compose 部署 RAG 系统的底层向量数据库(Milvus-stack)时,对象存储组件 rustfs 启动后,Docker 容器状态持续显示为 (unhealthy)。该异常可能导致上层 milvus-standalone 服务由于等待底层存储就绪超时而启动失败,进而影响整个问答助手系统的向量检索功能。
2. 环境与配置信息
组件角色:Milvus 向量数据库的底层对象存储(替代 MinIO)
镜像版本:
rustfs/rustfs:1.0.0-alpha.72网络环境:Docker 自定义网络
milvus-net核心端口:
9002(S3 兼容 API),9001(Console WebUI)初始探针配置:
YAML
healthcheck: test: ["CMD", "sh", "-c", "wget -qO- http://localhost:9002/ || exit 1"] interval: 30s timeout: 10s retries: 5
3. 排查过程
3.1 现象确认与初步收集
在执行 docker-compose up -d 启动基础组件栈后,通过 Portainer 面板及 docker ps 命令观察到 rustfs 容器的状态呈现为持续的 (unhealthy)。然而,上层依赖它的 standalone (Milvus) 尚未出现由于存储组件缺失导致的严重崩溃。
随即提取容器运行日志进行比对:
Bash
docker logs --tail 50 rustfs
日志分析结果:日志显示 RustFS API: http://172.22.0.5:9002 与 Console WebUI available at: http://172.22.0.5:9001... 均已成功启动,无任何 panic、Error 或网络绑定失败(如 address already in use)的报错。服务本身处于绝对健康的运行状态。
3.2 聚焦健康检查机制 (Healthcheck 探针分析)
既然服务本身正常,问题必定出在 Docker 的监控探针上。为了获取 Docker 探针视角的真实报错,提取了容器的详细健康检查审计日志:
Bash
docker inspect --format='{{json .State.Health.Log}}' rustfs
排查发现:探针历史记录中充斥着非 0 的退出码(Exit Code)。Docker 一旦捕获到非零退出码,即判定服务处于异常状态。
3.3 深入容器环境验证 (极简镜像黑盒探测)
探针命令执行失败,通常有两个原因:一是网络不通或页面返回 404;二是执行探针命令的环境本身存在缺失。为了验证后者,尝试进入容器内部手动执行诊断命令:
Bash
# 测试 1:尝试进入容器的 shell 环境
docker exec -it rustfs sh
# 实际结果:报错 "executable file not found in $PATH" (找不到 sh 命令)
# 测试 2:尝试直接调用网络工具
docker exec -it rustfs wget --help
# 实际结果:报错 "executable file not found in $PATH" (找不到 wget 命令)
推断验证:rustfs:1.0.0-alpha.72 采用了极致精简的构建策略(Distroless 或 Scratch 基础镜像)。整个容器内除了由 Rust 编译出的单一二进制可执行文件 /usr/bin/rustfs 之外,没有任何基础 Linux 核心工具集(无 sh、bash、curl、wget)。Docker 按照 YAML 指令去寻找 sh 准备执行 wget 时,直接吃了个闭门羹。
3.4 替代方案的尝试与阻碍 (API 探测碰壁)
在确认无法使用常规 Shell 工具后,团队尝试利用外部网络探测其原生 API 接口,模拟 MinIO 的标准健康检查流程:
Bash
# 尝试请求 S3 兼容的存活端点
curl -I http://localhost:9002/minio/health/live
阻碍:返回状态码为 HTTP/1.1 403 Forbidden。 原因剖析:RustFS 严格遵循 S3 规范。直接裸调接口会被安全机制拦截,要求必须附带复杂的 AWS Signature V4 签名(涉及 HMAC-SHA256 加密计算)。在不依赖外部脚本且无 Shell 环境的前提下,极难在简短的探针配置中完成动态签名构造。
3.5 最终排查定论
服务运行态:完全健康,端口监听正常。
异常根因:极简镜像环境与基于 Shell 的常规网络探针存在硬性不兼容。
API 限制:严格的 S3 签名校验阻断了无状态的 HTTP 状态码探测。
4. 解决方案与实施部署
基于“容器内无 Shell 环境”这一硬性客观条件,最优解是调整容器编排层面的依赖逻辑,摒弃无效的内部探针。
4.1 移除无效探针
修改 docker-compose.yaml,将 rustfs 服务下方的 healthcheck 配置块完全删除,避免 Docker 引擎持续发起无效探测并产生误报。
4.2 降级编排依赖条件
修改 Milvus 主服务(standalone)的 depends_on 逻辑。将对 rustfs 的依赖条件从“等待健康检查通过”放宽为“等待容器启动完成”。因为 Rust 程序的启动速度极快(通常为毫秒级),放宽此条件不会造成级联启动失败。
配置修改如下:
YAML
standalone:
# ... (其他配置保持不变)
depends_on:
etcd:
condition: service_healthy # etcd 镜像包含 shell,保留健康检查
rustfs:
condition: service_started # 适配极简镜像,仅等待容器启动
4.3 平滑更新验证
在服务器对应目录下执行以下命令,无损应用新配置:
Bash
docker-compose -f milvus-stack-2.6.6.compose.yaml up -d
验证结果:rustfs 容器重置后不再显示 unhealthy 标签,状态恢复正常。standalone 顺利挂载对象存储并建立连接,向量数据库集群成功拉起。

5. 总结与最佳实践
在进行大模型周边基础设施的容器化部署时,不可盲目照搬常规的 Healthcheck 配置。特别是针对使用 Golang、Rust 等编译型语言打包的 Distroless/Scratch 极简镜像,必须预先确认其内部是否包含基础 Shell 工具链。灵活运用 Docker Compose 的 service_started 依赖条件,是解决此类架构兼容性问题的标准途径。