Docker容器和K8s添加Health Check

docker容器启动后,怎么确认容器运行正常,怎么确认可以对外提供服务了,这就需要health check功能了。

之前对health check的功能不在意,因为只要镜像跑起来了就是健康的,如果有问题就会运行失败。在连续两次收到两个启动失败的issue之后,我决定修正一下。

遇到的问题是,一个web服务依赖mongo容器启动,通过docker-compose启动,虽然设置了depends on, 但有时候还是会遇到mongo容器中db实例还没有完全初始化,web服务已经启动连接了,然后返回连接失败。

version: '3.1' services: mongo: image: mongo:4 restart: always environment: MONGO_INITDB_ROOT_USERNAME: root MONGO_INITDB_ROOT_PASSWORD: example MONGO_INITDB_DATABASE: yapi volumes: - ./mongo-conf:/docker-entrypoint-initdb.d - ./mongo/etc:/etc/mongo - ./mongo/data/db:/data/db yapi: build: context: ./ dockerfile: Dockerfile image: yapi # 第一次启动使用 # command: "yapi server" # 之后使用下面的命令 command: "node /my-yapi/vendors/server/app.js" depends_on: - mongo

理论上,只有mongo服务启动后,status变成up,yapi这个服务才会启动。但确实有人遇到这个问题了。那就看看解决方案。

官方文档说depends_on并不会等待db ready, emmm 也没说depends on的标准是什么,是依赖service的status up?

Docker容器和K8s添加Health Check

官方说depends on依赖service是running状态,如果启动中的状态也算running的话,确实有可能db没有ready。官方的说法是,服务依赖和db依赖是一个分布式系统的话题,服务应该自己解决各种网络问题,毕竟db随时都有可能断开,服务应该自己配置重联策略。

官方推荐是服务启动前检查db是否已经启动了,通过ping的形式等待。搞一个wait-for-it.sh脚本 前置检查依赖。

docker-compose.yml

version: "2" services: web: build: . ports: - "80:8000" depends_on: - "db" command: ["./wait-for-it.sh", "db:5432", "--", "python", "app.py"] db: image: postgres

wait-for-it.sh

#!/bin/sh # wait-for-postgres.sh set -e host="$1" shift cmd="$@" until PGPASSWORD=$POSTGRES_PASSWORD psql -h "$host" -U "postgres" -c '\q'; do >&2 echo "Postgres is unavailable - sleeping" sleep 1 done >&2 echo "Postgres is up - executing command" exec $cmd Dockerfile中添加Health Check

回归标题,上面这个问题让我想起了健康检查这个东西。于是有了本文总结。那还是记录下使用容器镜像的时候怎么作健康检查吧。

Docker容器和K8s添加Health Check

在dockerfile中可以添加HEALTHCHECK指令,检查后面的cmd是否执行成功,成功则表示容器运行健康。

HEALTHCHECK [OPTIONS] CMD command 在容器中执行cmd,返回0表示成功,返回1表示失败 HEALTHCHECK NONE 取消base镜像到当前镜像之间所有的health check

options

--interval=DURATION (default: 30s) healthcheck检查时间间隔

--timeout=DURATION (default: 30s) 执行cmd超时时间

--start-period=DURATION (default: 0s) 容器启动后多久开始执行health check

--retries=N (default: 3) 连续n次失败则认为失败

一个检查80端口的示例

HEALTHCHECK --interval=5m --timeout=3s \ CMD curl -f || exit 1 Health check在docker-compose.yml中的配置

在docker-compose.yml中添加healthcheck节点,内容和dockerfile类似。

version: '3.1' services: mongo: image: mongo:4 healthcheck: test: ["CMD", "netstat -anp | grep 27017"] interval: 2m timeout: 10s retries: 3 Docker lib官方health check示例

在github上发现了docker library下的healthcheck项目, 比如mongo的健康检查可以这么做:

Dockerfile

FROM mongo COPY docker-healthcheck /usr/local/bin/ HEALTHCHECK CMD ["docker-healthcheck"]

docker-healthcheck

#!/bin/bash set -eo pipefail host="$(hostname --ip-address || echo '127.0.0.1')" if mongo --quiet "$host/test" --eval 'quit(db.runCommand({ ping: 1 }).ok ? 0 : 2)'; then exit 0 fi exit 1

类色的, mysql

#!/bin/bash set -eo pipefail if [ "$MYSQL_RANDOM_ROOT_PASSWORD" ] && [ -z "$MYSQL_USER" ] && [ -z "$MYSQL_PASSWORD" ]; then # there's no way we can guess what the random MySQL password was echo >&2 'healthcheck error: cannot determine random root password (and MYSQL_USER and MYSQL_PASSWORD were not set)' exit 0 fi host="$(hostname --ip-address || echo '127.0.0.1')" user="${MYSQL_USER:-root}" export MYSQL_PWD="${MYSQL_PASSWORD:-$MYSQL_ROOT_PASSWORD}" args=( # force mysql to not use the local "mysqld.sock" (test "external" connectibility) -h"$host" -u"$user" --silent ) if command -v mysqladmin &> /dev/null; then if mysqladmin "${args[@]}" ping > /dev/null; then exit 0 fi else if select="$(echo 'SELECT 1' | mysql "${args[@]}")" && [ "$select" = '1' ]; then exit 0 fi fi exit 1

内容版权声明:除非注明,否则皆为本站原创文章。

转载注明出处:https://www.heiqu.com/wppydd.html