开源实例之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。