15.8.3 服务定义与依赖编排(depends_on、healthcheck)

本节聚焦 Compose 中服务定义与依赖编排,核心在于明确服务启动顺序、健康状态与可用性保障。通过 depends_on 管理依赖关系,通过 healthcheck 判断服务是否真正就绪,避免上游服务因下游未就绪而启动失败或异常。

原理草图:依赖与健康检查流程#

文章图片

1. 服务定义关键字段与最小可运行示例#

以下示例演示 MySQL + Redis + 应用 + Nginx 的依赖编排,含健康检查与启动顺序控制。

文件: ./compose/docker-compose.yml

version: "3.9"
services:
  db:
    image: mysql:8.0
    container_name: demo-db
    environment:
      MYSQL_ROOT_PASSWORD: rootpass
      MYSQL_DATABASE: appdb
    ports:
      - "3306:3306"
    volumes:
      - dbdata:/var/lib/mysql
    healthcheck:
      test: ["CMD", "mysqladmin", "ping", "-h", "127.0.0.1", "-prootpass"]
      interval: 10s
      timeout: 5s
      retries: 5
      start_period: 20s
    restart: unless-stopped

  redis:
    image: redis:7
    container_name: demo-redis
    ports:
      - "6379:6379"
    healthcheck:
      test: ["CMD", "redis-cli", "ping"]
      interval: 10s
      timeout: 3s
      retries: 5
    restart: unless-stopped

  app:
    image: nginx:1.25
    container_name: demo-app
    depends_on:
      db:
        condition: service_healthy
      redis:
        condition: service_healthy
    ports:
      - "8080:80"
    environment:
      APP_ENV: "prod"
    restart: on-failure

  nginx:
    image: nginx:1.25
    container_name: demo-nginx
    depends_on:
      app:
        condition: service_started
    ports:
      - "80:80"
    restart: unless-stopped

volumes:
  dbdata:

启动命令与预期效果

# 进入目录
cd ./compose

# 启动
docker compose up -d

# 预期:db/redis 先启动并通过 healthcheck,app 随后启动
docker compose ps

2. depends_on 语义与健康依赖#

  • service_started:仅保证容器进程启动
  • service_healthy:要求 healthcheck 通过后再启动依赖服务
    注意condition 需要 Compose 版本支持(docker compose v2+)。

验证依赖状态

# 查看服务健康状态
docker inspect -f '{{.State.Health.Status}}' demo-db
docker inspect -f '{{.State.Health.Status}}' demo-redis

# 预期:healthy

3. healthcheck 设计与命令解释#

健康检查应轻量、稳定、低副作用,避免复杂 SQL 或长耗时操作。

典型命令解释
- mysqladmin ping:检查 MySQL 是否接受连接
- redis-cli ping:检查 Redis 是否可响应
- curl -f:HTTP 健康探针,非 2xx 退出码

示例:应用健康检查

healthcheck:
  test: ["CMD-SHELL", "curl -f http://localhost/health || exit 1"]
  interval: 10s
  timeout: 3s
  retries: 3
  start_period: 15s

4. 常用命令清单(含解释)#

# 查看 compose 版本
docker compose version

# 查看配置解析结果(排错用)
docker compose config

# 查看容器日志
docker compose logs -f app

# 查看健康状态变更
docker events --filter 'event=health_status'

5. 排错场景与定位方法#

问题1:app 仍然先于 db 启动
- 检查 depends_on 是否包含 condition: service_healthy
- 确认 db 容器存在 healthcheck

docker compose config | grep -A5 depends_on

问题2:db 一直 unhealthy
- 容器内命令是否可用(mysqladmin 是否存在)
- 密码或连接地址是否正确

docker exec -it demo-db mysqladmin ping -h 127.0.0.1 -prootpass

问题3:healthcheck 过重导致性能抖动
- 缩短探针逻辑,减少频率
- 对数据库使用轻量 ping 而非复杂 SQL

6. 练习#

  1. app 增加 healthcheck,并让 nginx 依赖 appservice_healthy
  2. redisinterval 改为 5s,观察健康状态变化频率。
  3. 故意配置错误的 MYSQL_ROOT_PASSWORD,观察 db 状态并修复。

7. 小结#

合理设置 depends_onhealthcheck,可显著提高多容器应用启动稳定性与可用性。生产实践中仍需结合应用层重试、熔断与监控告警,避免单点依赖判定失效。