Press "Enter" to skip to content

群晖 container 的healthcheck 不工作

群晖 DSM 的 Container Manager(原 Docker 套件)有一个容易误解的地方:Healthcheck 检测失败,并不会自动触发容器重启。

这通常不是群晖的 Bug,而是 Docker 本身的机制。

一、为什么 Healthcheck 失败不重启?

Docker 将容器运行状态和健康状态分开管理:

容器状态Healthcheck 状态是否自动重启
Runninghealthy否,正常运行
Runningunhealthy不会自动重启
Exited—根据重启策略决定
Runningstarting不会自动重启

即使你配置了:

services:
  myapp:
    image: nginx:latest
    restart: always
    healthcheck:
      test: ["CMD", "curl", "-f", "http://127.0.0.1:80/"]
      interval: 30s
      timeout: 10s
      retries: 3
      start_period: 30s

当连续 3 次健康检查失败,容器只会被标记为 unhealthy,并不会退出或重启。

原因是:

  • healthcheck 负责检测应用是否健康。
  • restart: always 负责容器主进程退出后的自动重启。
  • Docker Engine 默认不会把 unhealthy 视为容器退出。

因此,即使在群晖 Container Manager 中启用了自动重新启动,也无法解决这个问题。

二、推荐解决方案:部署 Autoheal

可以在群晖 Container Manager 中额外部署一个 Autoheal 容器,专门监控其他容器的健康状态。

1. 在群晖中创建项目

打开 Container Manager → 项目 → 新增项目,使用以下 Docker Compose:

services:
  autoheal:
    image: willfarrell/autoheal:latest
    container_name: autoheal
    restart: always
    network_mode: none
    environment:
      AUTOHEAL_CONTAINER_LABEL: all
      AUTOHEAL_INTERVAL: 10
      AUTOHEAL_START_PERIOD: 30
    volumes:
      - /var/run/docker.sock:/var/run/docker.sock
      - /etc/localtime:/etc/localtime:ro

参数说明:

参数作用
AUTOHEAL_CONTAINER_LABEL=all监控所有容器
AUTOHEAL_INTERVAL=10每 10 秒检查一次健康状态
AUTOHEAL_START_PERIOD=30Autoheal 启动后等待 30 秒
restart: alwaysAutoheal 自身退出后自动重启
docker.sock允许 Autoheal 操作 Docker 容器

2. 只监控指定容器(更推荐)

如果你的群晖运行了多个容器,我更建议只针对关键业务容器开启自动恢复,避免其他容器因短暂异常被误重启。

例如:

services:
  myapp:
    image: nginx:latest
    restart: unless-stopped

    labels:
      autoheal: "true"

    healthcheck:
      test:
        - CMD-SHELL
        - "wget -q --spider http://127.0.0.1:80/ || exit 1"
      interval: 30s
      timeout: 10s
      retries: 3
      start_period: 60s

  autoheal:
    image: willfarrell/autoheal:latest
    container_name: autoheal
    restart: always
    network_mode: none

    environment:
      AUTOHEAL_CONTAINER_LABEL: autoheal
      AUTOHEAL_INTERVAL: 10

    volumes:
      - /var/run/docker.sock:/var/run/docker.sock

这里使用 wget 检测,前提是目标镜像内包含该命令。

发表回复

您的邮箱地址不会被公开。 必填项已用 * 标注