Docker Compose容器健康检查

2026-06-15 20
Docker

类型:虚拟化技术

简介:基于操作系统层级的虚拟化技术,将软件与其依赖项打包为容器。

在使用 Docker Compose 编排多服务应用时,健康检查(healthcheck)是保证服务依赖关系稳定的重要机制。但在实际项目中,经常会遇到容器状态显示 unhealthy,甚至导致整个项目无法启动的问题。

docker compose ps
NAME    STATUS
db      unhealthy
app     unhealthy

当数据库、应用等核心服务处于 unhealthy 状态时,依赖它们的容器将无法正常启动,从而导致整个系统启动失败。

一、问题根源:健康检查依赖容器内部环境

健康检查命令是在容器内部执行的,因此必须依赖镜像中已有的工具和命令。

不同基础镜像差异较大,尤其是 Alpine 系列镜像,通常非常精简,默认不会包含 curl、bash、wget 等工具。

二、常见错误写法

错误1:字符串形式未使用 CMD-SHELL

healthcheck:
  test: "pg_isready -U postgres"

该写法不会正确解析 shell 语法,可能导致执行失败。

错误2:镜像中不存在 curl

healthcheck:
  test: ["CMD", "curl", "http://localhost:8080/health"]

如果镜像未安装 curl,会直接失败。

错误3:命令未验证

healthcheck:
  test: ["CMD-SHELL", "mysql -u root -p${MYSQL_PASSWORD} -e 'SELECT 1'"]

常见问题包括环境变量未传递、客户端不存在或引号解析错误。

三、正确的 Healthcheck 配置

PostgreSQL

db:
  image: postgres:16-alpine
  healthcheck:
    test: ["CMD-SHELL", "pg_isready -U ${POSTGRES_USER:-postgres} -d ${POSTGRES_DB:-postgres}"]
    interval: 10s
    timeout: 5s
    retries: 5
    start_period: 30s

MySQL

mysql:
  image: mysql:8.0
  healthcheck:
    test: ["CMD", "mysqladmin", "ping", "-h", "localhost", "-u", "root", "-p${MYSQL_ROOT_PASSWORD}"]
    interval: 10s
    timeout: 5s
    retries: 5
    start_period: 30s

Redis

redis:
  image: redis:7-alpine
  healthcheck:
    test: ["CMD", "redis-cli", "ping"]
    interval: 10s
    timeout: 3s
    retries: 5

Nginx

nginx:
  image: nginx:alpine
  healthcheck:
    test: ["CMD-SHELL", "wget -qO- http://localhost/health || exit 1"]
    interval: 30s
    timeout: 5s
    retries: 3

Node.js 应用

app:
  image: myapp:latest
  healthcheck:
    test: ["CMD-SHELL", "curl -f http://localhost:3000/health || exit 1"]
    interval: 30s
    timeout: 10s
    retries: 3
    start_period: 40s

四、健康检查排查方法

查看健康检查状态:

docker inspect --format='{{json .State.Health}}' container_name | jq .

手动测试命令:

docker compose exec db pg_isready -U postgres
docker compose exec redis redis-cli ping

五、健康检查通过但服务不可用

健康检查通过并不代表服务完全可用,它只代表进程存活。

常见问题包括:

PostgreSQL 返回成功但初始化未完成

MySQL 可连接但主从未同步

应用接口返回200但依赖未就绪

六、正确做法:真实业务健康检查

Node.js 示例

app.get('/health', async (req, res) => {
  const checks = {}

  try {
    await db.query('SELECT 1')
    checks.database = 'ok'
  } catch (err) {
    checks.database = 'error'
  }

  try {
    await redis.ping()
    checks.redis = 'ok'
  } catch (err) {
    checks.redis = 'error'
  }

  const allOk = Object.values(checks).every(v => v === 'ok')

  res.status(allOk ? 200 : 503).json({
    status: allOk ? 'ok' : 'degraded',
    checks
  })
})

Python Flask 示例

@app.route('/health')
def health():
    try:
        db.session.execute('SELECT 1')
        redis_client.ping()
        return jsonify({'status': 'ok'}), 200
    except Exception as e:
        return jsonify({'status': 'error'}), 503

七、总结

Docker Compose healthcheck 常见问题主要包括:

  • 镜像缺少工具
  • 命令写法错误
  • 仅检测进程未检测业务
  • 依赖服务未真正就绪

正确思路是:健康检查不仅要判断“进程存活”,还要验证“关键依赖可用”和“业务是否真正可用”。

  • 广告合作

  • QQ群号:4114653

温馨提示:
1、本网站发布的内容(图片、视频和文字)以原创、转载和分享网络内容为主,如果涉及侵权请尽快告知,我们将会在第一时间删除。邮箱:2942802716#qq.com(#改为@)。 2、本站原创内容未经允许不得转裁,转载请注明出处“站长百科”和原文地址。