根据健康检查重新启动不健康的 docker 容器

Restarting an unhealthy docker container based on healthcheck

我正在使用 Docker version 17.09.0-ce,我看到容器被标记为不健康。是否有一个选项可以让容器重新启动而不是让容器保持不健康状态?

Docker 有几种方法可以获取有关容器运行状况的详细信息。您可以配置健康检查及其频率 运行。此外,健康检查可以 运行 在容器内的应用程序 运行 上进行,例如 http(这将使用 curl --fail 选项。)您可以查看 health_status 事件以获取详细信息.

有关不健康容器的详细信息,检查命令会派上用场,docker inspect --format='{{json .State.Health}}' container-name(有关详细信息,请参阅 https://blog.newrelic.com/2016/08/24/docker-health-check-instruction/。)

您应该首先解决导致 "unhealthy" 标记的错误条件(任何时候运行状况检查命令 运行s 并获得退出代码 1)。这可能需要也可能不需要 Docker 重新启动容器,具体取决于错误。如果您是 starting/restarting 您的 containers automatically,那么捕获启动错误或记录它们以及健康检查状态可以帮助快速解决错误。如果您对自动启动感兴趣,请勾选 link。

重新启动不健康的容器功能在原始 PR (https://github.com/moby/moby/pull/22719) 中,但在讨论后被删除,并考虑稍后作为 RestartPolicy 的增强来完成。

此时您可以使用此解决方法自动重启不健康的容器:https://hub.docker.com/r/willfarrell/autoheal/

这是一个示例撰写文件:

version: '2'
services:
  autoheal:
    restart: always
    image: willfarrell/autoheal
    environment:
      - AUTOHEAL_CONTAINER_LABEL=all
    volumes:
      - /var/run/docker.sock:/var/run/docker.sock

只需在此

上执行docker-compose up -d

根据https://codeblog.dotsandbrackets.com/docker-health-check/

创建容器并添加“restart: always”。

在healthcheck的使用中,需要注意以下几点:

对于独立容器,Docker 没有本地集成来在运行状况检查失败时重启容器,尽管我们可以使用 Docker 事件和脚本实现相同的目的。健康检查更好地与 Swarm 集成。将健康检查集成到 Swarm 后,当服务中的容器不健康时,Swarm 会自动关闭不健康的容器并启动一个新容器以维持服务副本数中指定的容器数。

对于独立容器,Docker 没有本地集成来在运行状况检查失败时重新启动容器,尽管我们可以使用 Docker 事件和脚本实现相同的目的。健康检查更好地与 Swarm 集成。将健康检查集成到 Swarm 后,当服务中的容器不健康时,Swarm 会自动关闭不健康的容器并启动一个新容器以维持服务副本数中指定的容器数。

您可以尝试将这样的内容放入您的 Dockerfile 中:

HEALTHCHECK --interval=5s --timeout=2s CMD curl --fail http://localhost || kill 1

不要忘记 --restart always 选项。

kill 1 将终止容器中 pid 为 1 的进程并强制容器退出。通常CMD或ENTRYPOINT启动的进程pid为1.

不幸的是,此方法可能不会将容器的状态更改为不健康,因此请谨慎使用。

您可以通过设置智能 HEALTHCHECK 和适当的重启策略来自动重启不健康的容器。

Docker 重启策略应该是 alwaysunless-stopped 之一。

HEALTHCHECK 应该实施一种逻辑,在容器不健康时将其杀死。

在下面的示例中,我使用了 curl 及其内部重试机制并将其通过管道(在 failure/service 不健康的情况下)传输到 kill 命令。

HEALTHCHECK --interval=5m --timeout=2m --start-period=45s \
   CMD curl -f --retry 6 --max-time 5 --retry-delay 10 --retry-max-time 60 "http://localhost:8080/health" || bash -c 'kill -s 15 -1 && (sleep 10; kill -s 9 -1)'

这里要理解的重要步骤是curl命令中的重试逻辑是self-contained,这里的Docker重试实际上是强制性的但没有用。那么如果curl HTTP请求失败3次,则执行kill。首先它向容器中的所有进程发送一个 SIGTERM,让它们正常停止,然后在 10 秒后它发送一个 SIGKILL 以完全杀死容器中的所有进程。必须注意的是,当一个容器的PID1死亡时,容器本身也死亡并调用重启策略。

陷阱:kill 在 bash 中的行为与在 sh 中不同。在 bash 中,您可以使用 -1 来通知所有 PID 大于 1 的进程终止。