Skip to content

15 | 健康检查与启动依赖

启动成功不代表服务可用 ​

前几课已经知道网络、数据和配置在哪里。现在要回答发布时最常见的问题:up -d 已经返回,数据库为什么还连不上?

本课继续使用本地 delivery-demo Compose 项目。先把环境变量恢复到第 12 课完整配置,确认 web 使用自己的镜像、db 保留原数据卷。

给依赖定义可检查的状态 ​

将以下字段合并到现有 web 和 db 服务。它是 局部补充,不要删除原来的镜像、环境变量、挂载和网络配置:

yaml
services:
  web:
    healthcheck:
      test: [CMD-SHELL, "wget -q -O - http://127.0.0.1/healthz | grep -qx ok"]
      interval: 5s
      timeout: 3s
      retries: 3
      start_period: 5s
    depends_on:
      db:
        condition: service_healthy
    restart: unless-stopped
  db:
    healthcheck:
      test: [CMD-SHELL, 'pg_isready -U "$${POSTGRES_USER}" -d "$${POSTGRES_DB}"']
      interval: 3s
      timeout: 3s
      retries: 10
      start_period: 10s
    restart: unless-stopped

$$ 阻止 Compose 提前插值,使变量留给容器内 shell 展开。CMD-SHELL 会调用容器内 shell;CMD 则直接执行参数,不自动展开管道和变量。探针工具必须存在于镜像中。

本例静态页面并不依赖数据库业务,增加依赖是为了演示等待机制;实际项目只声明真实依赖,不人为扩大故障影响范围。pg_isready 检查服务是否接受连接,不等于验证业务账号权限和 SQL 结果。

等待就绪,再记录成功 ​

需要支持 --wait 的 Compose v2;先用 docker compose up --help 核对当前版本。

bash
docker compose config --quiet
docker compose up -d --wait --wait-timeout 90
docker compose ps
curl --fail http://127.0.0.1:18080/healthz
docker inspect "$(docker compose ps -q web)" --format '{{json .State.Health}}'

成功条件是依赖健康、web 健康,并且入口返回 ok。这里检查的是容器内部与宿主机入口两条路径;远端发布还需从实际访问方检查公网入口、TLS 和业务接口。

start_period 是启动宽限期,不是固定睡眠;失败累计、超时和检查间隔共同决定判定时间。不要无限拉长参数来掩盖服务起不来的问题。

故意让健康检查失败 ​

临时将 web 的检查替换为始终失败的命令,其他配置保持不变:

yaml
healthcheck:
  test: [CMD, "false"]
  interval: 2s
  timeout: 1s
  retries: 2
  start_period: 0s
bash
docker compose up -d --wait --wait-timeout 20 web
docker compose ps
docker inspect "$(docker compose ps -q web)" --format '{{.RestartCount}} {{.State.Health.Status}}'

第一条应以非零退出码结束,但 web 的主进程仍可能运行。状态变为 unhealthy 不会仅因为 restart: unless-stopped 就自动重启;重启策略主要处理容器进程退出。

恢复原健康检查,再执行 up -d --wait。确认状态恢复,并保存失败和恢复的检查输出。

depends_on 的边界 ​

condition: service_healthy 在启动依赖时等待条件成立,不是长期的依赖守护器。数据库在运行途中故障,Compose 不会自动让应用具备重连、业务降级和事务补偿。

情况需要什么机制
数据库初始化较慢就绪探针与启动等待
应用运行中连接断开应用重试、退避和超时
进程异常退出合适的 restart 策略与日志排查
进程存活但业务错误业务探测、告警与恢复流程

手动停止与进程意外退出的处理也不同;不要用“stop 后没自动重启”证明策略失效。

进入之前的验收 ​

让一次健康检查失败产生非零退出码,同时保留日志;恢复正确配置后再次验证成功。后续流水线只需调用这些可检查的步骤,而不靠固定 sleep 30 或“命令已经执行完”判断发布成功。

下一课从制品仓库的交接关系出发解释 CI/CD 分离,再分别实现构建与发布流水线。

参考:Compose 启动依赖、重启策略。