熟悉使用过kubernetes的人应该知道,kubernetes支持对pod进行健康检查的功能,这对生产业务来说其实是非常有用处的,能快速发现服务不可用,并进行快速重启恢复。其实不使用kubernetes这种容器管理工具,docker自身也能实现对容器的健康检查。
从docker 1.12 版本之后,Docker 实现了原生的健康检查实现。对于容器而言,最简单的健康检查是进程级的健康检查,即检验进程是否存活。Docker Daemon 会自动监控容器中的 PID1 进程,如果 docker run 命令中指明了 restart policy,可以根据重启策略自动重启已结束的容器。但是在很多实际应用中,仅使用进程级健康检查方式还远远不够。比如,容器中进程虽然还在运行却由于其他种种原因无法继续响应用户请求(如应用死锁),这样的问题是无法通过进程级监控发现的。
容器启动之后,初始状态会为 starting (启动中)。Docker Engine 会等待 interval 时间,开始执行健康检查命令,并周期性执行。如果单次检查返回值非 0 或者运行需要比指定 timeout 时间还长,则本次检查被认为失败;如果健康检查连续失败超过了 retries 重试次数,状态就会变为 unhealthy (不健康)。
1) 过程中有一次健康检查成功,Docker 会将容器标记为healthy (健康)状态
2) 当容器的健康状态发生变化时,Docker Engine 会发出一个 health_status 事件。通过检查容器监控状态这里介绍以下三种方式
这种方式是在 docker run 命令中,直接指明 healthcheck 相关设置,该方法修改起来比较方便快捷,但是要求使用者对命令行使用比较熟练。
[root@k8s-m1 ~]# docker ps -l
CONTAINER ID IMAGE COMMAND CREATED STATUS PORTS NAMES
80726f760696 nginx "/docker-entrypoint.…" About a minute ago Up About a minute (healthy) 80/tcp nginx-test
[root@k8s-m1 ~]# docker run -d --name=nginx-test --health-cmd="curl http://localhost/ || exit 1" --health-interval=5s --health-retries=6 --health-timeout=3s nginx
对命令行不熟悉的,可以通过执行docker run --help | grep health
命令查看相关的参数及解释如下:
– health-cmd string 运行检查健康状况的命令
–health-interval duration 运行间隔时间(ms|s|m|h)(缺省为 0s)
–health-retries int 需要报告不健康的连续失败次数
–health-start-period duration 容器在开始健康之前初始化的起始周期(ms|s|m|h)(默认 0)
–health-timeout duration 允许一次检查运行的最大时间(ms|s|m|h)(默认为 0s)
–no-healthcheck 禁用任何容器指定的HEALTHCHECK
,会使 Dockerfile 构建设置的HEALTHCHECK
功能失效
可以在 Dockerfile 中通过使用HEALTHCHECK
声明应用自身的健康检测配置。HEALTHCHECK配置了健康检测命令,用这个命令来判断容器主进程的服务状态是否正常,从而比较真实的反应容器实际运行状况。
HEALTHCHECK
指令格式:
HEALTHCHECK [选项] CMD <命令>
HEALTHCHECK NONE
注 :和cmd、entrypoint一样,在 Dockerfile 中HEALTHCHECK只可以出现一次,如果写了多个,只有最后一个生效。
HEALTHCHECK 返回值,决定了该次健康检查的成功与否:0:成功;1:失败;2:保留(不要使用这个值)
使用包含HEALTHCHECK
指令的 Dockerfile 构建出来的镜像,在实例化 Docker 容器的时候,就具备了健康状态检查的功能。启动容器后会自动进行健康检查。
参数说明:
HEALTHCHECK 支持下列选项:
假设有个镜像是个最简单的 nginx 服务,我们希望增加健康检查来判断其 nginx服务是否在正常工作,我们可以使用 curl 来帮助检查测试, Dockerfile 的HEALTHCHECK
可以简单这么写:
[root@k8s-m1 ~]vim Dockerfile
FROM nginx
HEALTHCHECK --interval=5s --timeout=3s CMD curl http://localhost/ || exit 1
[root@k8s-m1 ~]docker build -t nginx:v1 .
[root@k8s-m1 ~]docker run -d --name webtest -p 80:80 nginx:v1
[root@k8s-m1 ~]# docker ps -l
CONTAINER ID IMAGE COMMAND CREATED STATUS PORTS NAMES
c4dcff064e99 nginx:v1 "/docker-entrypoint.…" 5 seconds ago Up 4 seconds (health: starting) 0.0.0.0:80->80/tcp webtest
[root@k8s-m1 ~]# docker ps -l
CONTAINER ID IMAGE COMMAND CREATED STATUS PORTS NAMES
c4dcff064e99 nginx:v1 "/docker-entrypoint.…" 10 seconds ago Up 9 seconds (healthy) 0.0.0.0:80->80/tcp webtest
[root@k8s-m1 ~]#
这里设置了每 5 秒检查一次,如果健康检查命令超过 3 秒没响应,并且重试 3 次都没响应就视为失败,并且使用curl http://localhost/ || exit 1
,可以根据自己的业务自行调整检查命令。构建好后启动一个容器实例,看到最初的状态为(health: starting)
,在等待几秒钟后,再次docker ps -l
,就可以看到健康状态变化为了(healthy)
。
当然如果健康检查连续失败超过了重试次数,状态就会变为(unhealthy)
为了帮助排障,健康检查命令的输出(包括stdout
以及stderr
)都会被存储于健康状态里,可以用 docker inspect
来查看。
[root@k8s-m1 ~]# docker inspect --format '{{json .State.Health}}' webtest | python -m json.tool
{
"Status": "healthy",
"FailingStreak": 0,
"Log": [
{
"Start": "2023-06-12T10:33:48.163431699+08:00",
"End": "2023-06-12T10:33:48.303906069+08:00",
"ExitCode": 0,
"Output": " % Total % Received % Xferd Average Speed Time Time Time Current\n Dload Upload Total Spent Left Speed\n\r 0 0 0 0 0 0 0 0 --:--:-- --:--:-- --:--:-- 0\r100 615 100 615 0 0 600k 0 --:--:-- --:--:-- --:--:-- 600k\n\n\n\nWelcome to nginx! \n\n\n\nWelcome to nginx!
\nIf you see this page, the nginx web server is successfully installed and\nworking. Further configuration is required.
\n\nFor online documentation and support please refer to\n\"
http://nginx.org/\">nginx.org.
\nCommercial support is available at\n\"http://nginx.com/\">nginx.com.\n\nThank you for using nginx.
\n\n\n"
在 docker-compose 中,可以使用以下方式来实现对容器的健康状况检查(下面以nginx为例,也可以参考Harbor的docker-compose文件):
version: '3'
services:
myapp:
image: nginx
container_name: healthcheck
healthcheck:
test: ["CMD", "curl", "-fs", "http://localhost/"]
interval: 6s
timeout: 3s
retries: 3
#设置初次检查等待6s,每次检查超时设置为3s,总共检查3次,如果3次都失败则判断为健康检查不通过。过程中有一次检查通过则判断为健康。
执行成功后,等待数秒查询容器的状态:
[root@k8s-m1 hewei]# docker ps -l
CONTAINER ID IMAGE COMMAND CREATED STATUS PORTS NAMES
46e1d11e2431 nginx "/docker-entrypoint.…" 3 seconds ago Up 3 seconds (health: starting) 80/tcp healthcheck
[root@k8s-m1 hewei]# docker ps -l
CONTAINER ID IMAGE COMMAND CREATED STATUS PORTS NAMES
46e1d11e2431 nginx "/docker-entrypoint.…" 6 seconds ago Up 8 seconds (health: starting) 80/tcp healthcheck
[root@k8s-m1 hewei]# docker-compose ps
Name Command State Ports
--------------------------------------------------------------------
healthcheck /docker-entrypoint.sh ngin ... Up (healthy) 80/tcp
更复杂的使用请自行探索,一般也很少单独使用。更多docker容器和运维方面的知识请前往博客主页。