杜郎俊赏 - dujun.io

开源实例之Docker健康检查

前言

本篇介绍通过 Docker 健康检查(HEALTHCHECK)来实现严格顺序启动,以及可用性判断。

应用场景

假设一个 web 应用需要运行多个容器,容器之间存在依赖关系。这就有两个问题,一是如何保证容器的启动顺序,二是如何监控 web 应用已经整体完成启动。

举例来说,MongoDB 管理工具mongo-express实例需要运行两个容器:MongoDB 容器和 Node.js 容器。需要先启动 MongoDB(含数据),再启动 Node.js(含项目程序),最终 web 暴露在 8081 端口。

一般解决方案

按照一般方案,用depends_on来控制容器启动顺序,根据 http 请求端口返回状态来判断是否启动完成。docker-compose.yml 如下:

version: '2.4'

services:
  mongodb:
    image: dujunio/mongodb:4.4
    expose:
      - "27017"
    entrypoint: sh /init/mongodb.sh
    privileged: true
    tty: true

  app:
    image: dujunio/mongoexpress
    ports:
      - "10101:8081"
    depends_on:
      - mongodb
    working_dir: /wwwroot/app/node_modules/mongo-express
    entrypoint: node app.js
    privileged: true
    tty: true
    container_name: mongoexpress

当所有服务都在很短的时间内启动,是察觉不到问题的。但如果某个服务启动时间过长,就会导致服务启动顺序打乱。因为depends_on只判断容器启动,并不判断容器内的程序是否完成启动。可能出现的情况是,对外暴露的 http 端口返回 200 了,但内部的服务还未启动,导致报错。

这时候就需要 Docker 健康检查(HEALTHCHECK)。

Docker健康检查

Docker在v1.12版本之后增加了HEALTHCHECK功能,该功能可以自定义容器健康状态的检测标准,弥补了Docker默认的判断方法的不精准的不足。

HEALTHCHECK 支持下列参数:

参数描述
interval两次健康检查的间隔,默认为 30 秒
timeout健康检查命令运行超时时间,如果超过这个时间,本次健康检查就被视为失败,默认 30 秒
retries当连续失败指定次数后,则将容器状态视为 unhealthy,默认 3 次
start-period应用启动的初始化时间,在启动过程中的健康检查失效不会计入,默认 0 秒

返回三种状态:

状态描述
starting正在启动
healthy启动完成
unhealthy发生异常

优化解决方案

加入健康检查后的 docker-compose.yml 如下:

version: '2.4'

services:
  mongodb:
    image: dujunio/mongodb:4.4
    expose:
      - "27017"
    entrypoint: sh /init/mongodb.sh
    healthcheck:
      test: ps axu | grep /usr/bin/[m]ongod
      interval: 1s
      timeout: 5s
      retries: 3
    privileged: true
    tty: true

  app:
    image: dujunio/mongoexpress
    ports:
      - "10101:8081"
    working_dir: /wwwroot/app/node_modules/mongo-express
    entrypoint: node app.js
    depends_on:
      mongodb:
        condition: service_healthy
    healthcheck:
      test: curl -f http://localhost:8081
      interval: 1s
      timeout: 10s
      retries: 10
    restart: on-failure
    privileged: true
    tty: true
    container_name: mongoexpress

healthcheck test 是在容器内部执行的检查命令。

如本例所示,MongoDB 容器启动完成后,才会启动 Node.js 容器。然后通过 docker inspect --format '{{.State.Health.Status}}' mongoexpress 来判断 web 整体启动完成。

特别注意:version 3 之后不支持 depends_on condition。本系列使用 version 2.4。

后记

体验更多开源实例

标签: 开源实例
日期:2023-02-21