四个容器都 running 了,API 连得上吗?一个只查连通性的 ready 接口,和三个数据库各自的就绪问法。
这一阶段先不做页面,把启动步骤走通。项目用 API、Postgres、Qdrant 和 Neo4j 四个容器;后面要比较文本检索和图检索,两套数据服务都先留下。
启动入口尽量短
README 里的第一步:
cp .env.example .env复制后还得编辑模型 key 和连接配置,再启动:
docker compose up -d --buildcurl http://localhost:8000/health/readyrunning 之后,再问一句连得上吗
docker compose ps 里看到 running,我还想再问一步:API 能连上这几个服务吗?端口开始监听和数据库可用并不总是同时发生,地址也可能配错。于是保留一个只检查连通性的 ready 接口,先把问题缩小到连接这一层。
Compose 文档也是这么写的:启动时它只等容器在跑,不等容器可用(Compose 启动顺序)。docker compose ps 默认也只列正在运行的容器,退出过的不加 -a 根本看不到,健康状态也不在默认表格里(compose ps 参考)。
九月整理代码时,backend/main.py 里的检查就三项:
- Postgres 执行
SELECT 1 - Qdrant 请求
/collections - Neo4j 执行
RETURN 1 as ok
返回里分别列三项结果,有一项失败,整体状态就是 degraded。这些是整理时的实现细节,方便对照接口读代码。
postgres = trueqdrant = falseneo4j = true→ status = degraded这是一个说明用的返回。示例里只有 Qdrant 那项失败:整体状态看不出是哪一条没连上,分项结果能指出来,但不能由此认定问答流程已经部分可用。
遇到这种情况,我会先查 API 配的 Qdrant 地址和服务响应,不急着换 embedding 模型。连通性恢复以后,再查 collection 有没有资料、向量维度对不对。ready 不调用问答模型,也不验证资料是否入库,绿色结果只说明到这一层。
三个数据库,三种就绪问法
为什么三项检查各写各的?因为三家官方给的东西本来就不一样:
| 服务 | 官方提供的检查 | 它回答的问题 |
|---|---|---|
| Postgres | pg_isready,退出码 0 正常、1 拒绝连接(如启动中)、2 无响应 |
服务器收不收连接;不要求正确的用户名、密码和库名(pg_isready 文档) |
| Qdrant | /healthz 和 /readyz 两个端点 |
实例活着,以及能不能开始接流量(Qdrant readyz 参考) |
| Neo4j | Docker 文档里没有现成探针,只建议浏览器打开 7474 试连 | 只能自己发一条 Cypher(Neo4j Docker 文档) |
对照这张表,SELECT 1 比 pg_isready 多查了一层:用这套凭据能连上,库也在。端口通了而密码错了,恰好落在 ready 要覆盖的那段窗口里。Neo4j 那条 RETURN 1 as ok 也是官方工具 cypher-shell 的正常用法,走一次真实的 Bolt 连接再执行一次查询(cypher-shell 文档)。
查 Qdrant 地址时还有个小坑:它默认 REST 走 6333、gRPC 走 6334,两个端口写混是另一类故障;默认也不开认证,所以连不上一般不是权限问题(Qdrant Quickstart)。等连上之后查维度,依据也很硬:同一个 collection 里所有向量维度必须一致(Qdrant Collections)。
按 Kubernetes 的分法,这个接口属于 readiness,不是 liveness:readiness 失败只是不接流量,liveness 失败才重启,后端依赖是否可用应该放在 readiness 里查(Kubernetes 探针文档)。ready 变红时,该做的是停下来查连接,重启容器帮不上忙。
配置在哪儿被读,最容易混
配置集中交给 pydantic-settings,变量名列在 .env.example。容易混的是文件在哪儿被读:Compose 先用变量处理部署配置,API 进程再读取自己的环境。宿主机里的一份 .env,不会因为放在目录里就自动成为所有容器的配置。Compose 文档的说法是:容器的环境变量必须在服务配置里显式写上才会进去,项目目录里的 .env 只用于插值(Compose 环境变量)。
pydantic-settings 这边也有两条容易踩:环境变量永远比 dotenv 文件优先;只给文件名时,它只在当前工作目录找 .env,不往上层目录找(pydantic-settings 的 dotenv 一节)。文件放在哪个目录,和进程从哪个目录启动,是两件事。Pydantic Settings 文档可以对照读取规则,实际路径还要按启动方式看。
哪一步没过,就停在哪一步
项目用 .dockerignore 把不用的文件挡在构建上下文外。这个文件只在构建上下文的根目录生效,挪了目录会悄悄失效(Docker 构建上下文)。新环境按顺序检查:
- 启动
- 请求 ready
- 导入数据
哪一步没过就停在哪一步查,比等最终问答报错再回头查四个服务省事。这三步有依赖:连接配置或模型 key 在启动那一步写错,导入数据多半也会失败,那时看到的位置和真正的原因往往已经不在一处。
如果不想自己写 ready,Compose 也有一套:给服务配 healthcheck,依赖方用 depends_on 的 condition: service_healthy 等它通过(Compose services 参考),或者直接 docker compose up --wait,等所有服务 running 或 healthy 再返回(compose up 参考)。代价是检查命令跑在容器里,要求镜像里有对应的客户端工具,而且查的是服务自己好不好,不是 API 用自己的配置连不连得上。我更看重后一个问题,所以 ready 留在应用里。
留下几句话 读者来信
读到这里,有什么想法?欢迎留下你的看法。