Docker 容器健康检查配置指南:实现自动故障恢复

Docker 容器健康检查配置指南:实现自动故障恢复

在实际项目中,我发现很多团队用 Docker 部署服务,但很少有人注意到健康检查这个功能。容器显示"running"不等于服务可用——这是一个很常见的坑。

背景

Docker 监控的是进程是否存活,不是应用是否健康。进程启动了,容器就是 running 状态,哪怕应用已经挂死。这是一个设计取舍,但确实带来了麻烦:服务明明不可用了,容器还显示一切正常。

问题

用一个具体例子说明。你运行了这样一个容器:

docker run -d --name my-api myregistry/my-api:latest

容器在运行,但以下几种情况都会导致服务实际不可用:

  • Node.js 进程没退出,但事件循环被阻塞死了
  • 应用内存耗尽,无法响应请求
  • 依赖的数据库挂了,但进程还活着

默认情况下,你只能手动发现问题,或者写外部脚本定时探测。

配置步骤

Docker 提供了 HEALTHCHECK 指令解决这个问题。

参数说明

HEALTHCHECK 支持几个参数:

  • INTERVAL:两次检查之间的间隔,默认 30 秒
  • TIMEOUT:单次检查的超时时间,默认 30 秒
  • RETRIES:连续失败多少次算不健康,默认 3 次
  • START_PERIOD:容器启动后多久开始第一次检查,默认 0 秒

检测方式选择

不同应用用不同方式检测:

  • HTTP 服务:访问一个专门的健康检查端点
  • 数据库:用客户端执行测试查询
  • Redis:发送 PING 命令
  • 命令行应用:检查端口或某个文件

Dockerfile 配置

以 Flask 应用为例:

FROM python:3.11-slim

WORKDIR /app

COPY requirements.txt .
RUN pip install --no-cache-dir -r requirements.txt

COPY . .

HEALTHCHECK --interval=30s --timeout=10s --start-period=40s --retries=3 \
    CMD python healthcheck.py

CMD ["python", "app.py"]

healthcheck.py 可以这样写:

#!/usr/bin/env python3
import sys
import urllib.request
import urllib.error

def check_health():
    try:
        url = "http://localhost:5000/health"
        req = urllib.request.Request(url)
        with urllib.request.urlopen(req, timeout=5) as response:
            if response.status == 200:
                print("Health check passed")
                sys.exit(0)
            else:
                print(f"Health check failed: status {response.status}")
                sys.exit(1)
    except urllib.error.URLError as e:
        print(f"Health check failed: {e}")
        sys.exit(1)
    except Exception as e:
        print(f"Health check error: {e}")
        sys.exit(1)

if __name__ == "__main__":
    check_health()

docker-compose 配置

version: '3.8'

services:
  api:
    build: .
    ports:
      - "5000:5000"
    healthcheck:
      test: ["CMD", "python", "healthcheck.py"]
      interval: 30s
      timeout: 10s
      retries: 3
      start_period: 40s
    restart: unless-stopped

  nginx:
    image: nginx:latest
    ports:
      - "80:80"
    depends_on:
      api:
        condition: service_healthy
    restart: unless-stopped

depends_oncondition: service_healthy 很有用——它确保 Nginx 只有在 API 容器通过健康检查后才会启动。

查看状态

docker ps

STATUS 列会显示健康检查结果:

CONTAINER ID   IMAGE          STATUS                     PORTS                    NAMES
abc123def456   my-api:latest  Up 2 minutes (healthy)    0.0.0.0:5000->5000/tcp   my-api

不健康时会显示 (unhealthy)

查看详细日志:

docker inspect --format='{{json .State.Health}}' my-api

完整示例

完整代码如下:

# app.py
from flask import Flask, jsonify
import time
import random

app = Flask(__name__)

@app.route('/')
def index():
    return jsonify({"status": "ok", "message": "API is running"})

@app.route('/health')
def health():
    return jsonify({"status": "healthy"})

@app.route('/simulate-failure')
def simulate_failure():
    # 模拟故障:长时间阻塞
    time.sleep(300)
    return jsonify({"status": "ok"})

if __name__ == '__main__':
    app.run(host='0.0.0.0', port=5000)
# Dockerfile
FROM python:3.11-slim

WORKDIR /app

RUN pip install --no-cache-dir flask

COPY app.py healthcheck.py ./

EXPOSE 5000

HEALTHCHECK --interval=30s --timeout=5s --start-period=10s --retries=3 \
    CMD python healthcheck.py

CMD ["python", "app.py"]
# docker-compose.yml
version: '3.8'

services:
  api:
    build: .
    ports:
      - "5000:5000"
    environment:
      - FLASK_ENV=production
    healthcheck:
      test: ["CMD", "python", "healthcheck.py"]
      interval: 30s
      timeout: 5s
      retries: 3
      start_period: 10s
    restart: unless-stopped
    networks:
      - api-network

networks:
  api-network:
    driver: bridge

运行结果

启动服务:

docker-compose up -d
docker ps

初始状态是 (starting)

CONTAINER ID   IMAGE     STATUS                   PORTS                    NAMES
abc123         my-api    Up 5 seconds (starting)  0.0.0.0:5000->5000/tcp   myapi-api-1

等待 start_period 后,变成 (healthy)

abc123         my-api    Up 35 seconds (healthy)  0.0.0.0:5000->5000/tcp   myapi-api-1

模拟故障:

curl http://localhost:5000/simulate-failure

应用被阻塞后,健康检查会连续失败。检查状态:

docker inspect --format='{{.State.Health.Status}}' myapi-api-1

会返回 unhealthy。如果配置了 restart: unless-stopped,Docker 会自动重启容器:

docker events --filter 'event=restart'

容器重启后会重新经历 (starting)(healthy) 的过程。

总结

健康检查解决几个实际问题:

  • 故障自动发现——不用靠用户投诉才知道服务挂了
  • 自动恢复——结合 restart 策略,容器可以自己重启
  • 服务依赖管理——用 condition: service_healthy 确保依赖就绪再启动下游
  • 状态可见——容器状态一目了然,便于接入监控系统

配置时注意几点:根据应用类型选检测方式,HTTP 服务直接检测端点最靠谱。有数据库依赖的,在健康检查里包含连接测试。intervaltimeoutretries 这些参数要结合应用的实际启动时间和响应时间来调整。

这个功能会增加一点资源开销,但换来的可靠性提升很值得。花几分钟配置一下,关键时刻能救命。

暂无评论

发送评论 编辑评论


				
|´・ω・)ノ
ヾ(≧∇≦*)ゝ
(☆ω☆)
(╯‵□′)╯︵┴─┴
 ̄﹃ ̄
(/ω\)
∠( ᐛ 」∠)_
(๑•̀ㅁ•́ฅ)
→_→
୧(๑•̀⌄•́๑)૭
٩(ˊᗜˋ*)و
(ノ°ο°)ノ
(´இ皿இ`)
⌇●﹏●⌇
(ฅ´ω`ฅ)
(╯°A°)╯︵○○○
φ( ̄∇ ̄o)
ヾ(´・ ・`。)ノ"
( ง ᵒ̌皿ᵒ̌)ง⁼³₌₃
(ó﹏ò。)
Σ(っ °Д °;)っ
( ,,´・ω・)ノ"(´っω・`。)
╮(╯▽╰)╭
o(*////▽////*)q
>﹏<
( ๑´•ω•) "(ㆆᴗㆆ)
😂
😀
😅
😊
🙂
🙃
😌
😍
😘
😜
😝
😏
😒
🙄
😳
😡
😔
😫
😱
😭
💩
👻
🙌
🖕
👍
👫
👬
👭
🌚
🌝
🙈
💊
😶
🙏
🍦
🍉
😣
Source: github.com/k4yt3x/flowerhd
颜文字
Emoji
小恐龙
花!
上一篇