docker compose 服务依赖和健康检查

Dockerfile healthcheck https://docs.docker.com/engine/reference/builder/#healthcheck

docker compose https://docs.docker.com/compose/compose-file/compose-file-v3/#healthcheck

健康检查是容器运行状态的高级检查,主要是检查容器所运行的进程是否能正常的对外提供“服务”,比如一个数据库容器,我们不光 需要这个容器是up的状态,我们还要求这个容器的数据库进程能够正常对外提供服务,这就是所谓的健康检查。

容器的健康检查

容器本身有一个健康检查的功能,但是需要在Dockerfile里定义,或者在执行docker container run 的时候,通过下面的一些参数指定

  1. --health-cmd string Command to run to check health
  2. --health-interval duration Time between running the check
  3. (ms|s|m|h) (default 0s)
  4. --health-retries int Consecutive failures needed to
  5. report unhealthy
  6. --health-start-period duration Start period for the container to
  7. initialize before starting
  8. health-retries countdown
  9. (ms|s|m|h) (default 0s)
  10. --health-timeout duration Maximum time to allow one check to

示例源码

我们以下面的这个flask容器为例,相关的代码如下

  1. PS C:\Users\Peng Xiao\code-demo\compose-env\flask> dir
  2. 目录: C:\Users\Peng Xiao\code-demo\compose-env\flask
  3. Mode LastWriteTime Length Name
  4. ---- ------------- ------ ----
  5. -a---- 2021/7/13 15:52 448 app.py
  6. -a---- 2021/7/14 0:32 471 Dockerfile
  7. PS C:\Users\Peng Xiao\code-demo\compose-env\flask> more .\app.py
  8. from flask import Flask
  9. from redis import StrictRedis
  10. import os
  11. import socket
  12. app = Flask(__name__)
  13. redis = StrictRedis(host=os.environ.get('REDIS_HOST', '127.0.0.1'),
  14. port=6379, password=os.environ.get('REDIS_PASS'))
  15. @app.route('/')
  16. def hello():
  17. redis.incr('hits')
  18. return f"Hello Container World! I have been seen {redis.get('hits').decode('utf-8')} times and my hostname is {socket.gethostname()}.\n"
  19. PS C:\Users\Peng Xiao\code-demo\compose-env\flask> more .\Dockerfile
  20. FROM python:3.9.5-slim
  21. RUN pip install flask redis && \
  22. apt-get update && \
  23. apt-get install -y curl && \
  24. groupadd -r flask && useradd -r -g flask flask && \
  25. mkdir /src && \
  26. chown -R flask:flask /src
  27. USER flask
  28. COPY app.py /src/app.py
  29. WORKDIR /src
  30. ENV FLASK_APP=app.py REDIS_HOST=redis
  31. EXPOSE 5000
  32. HEALTHCHECK --interval=30s --timeout=3s \
  33. CMD curl -f http://localhost:5000/ || exit 1
  34. CMD ["flask", "run", "-h", "0.0.0.0"]

上面Dockerfili里的HEALTHCHECK 就是定义了一个健康检查。 会每隔30秒检查一次,如果失败就会退出,退出代码是1

构建镜像和创建容器

构建镜像,创建一个bridge网络,然后启动容器连到bridge网络

  1. $ docker image build -t flask-demo .
  2. $ docker network create mybridge
  3. $ docker container run -d --network mybridge --env REDIS_PASS=abc123 flask-demo

查看容器状态

  1. $ docker container ls
  2. CONTAINER ID IMAGE COMMAND CREATED STATUS PORTS NAMES
  3. 059c12486019 flask-demo "flask run -h 0.0.0.0" 4 hours ago Up 8 seconds (health: starting) 5000/tcp dazzling_tereshkova

也可以通过docker container inspect 059 查看详情, 其中有有关health的

  1. "Health": {
  2. "Status": "starting",
  3. "FailingStreak": 1,
  4. "Log": [
  5. {
  6. "Start": "2021-07-14T19:04:46.4054004Z",
  7. "End": "2021-07-14T19:04:49.4055393Z",
  8. "ExitCode": -1,
  9. "Output": "Health check exceeded timeout (3s)"
  10. }
  11. ]
  12. }

经过3次检查,一直是不通的,然后health的状态会从starting变为 unhealthy

  1. docker container ls
  2. CONTAINER ID IMAGE COMMAND CREATED STATUS PORTS NAMES
  3. 059c12486019 flask-demo "flask run -h 0.0.0.0" 4 hours ago Up 2 minutes (unhealthy) 5000/tcp dazzling_tereshkova

启动redis服务器

启动redis,连到mybridge上,name=redis, 注意密码

  1. $ docker container run -d --network mybridge --name redis redis:latest redis-server --requirepass abc123

经过几秒钟,我们的flask 变成了healthy

  1. $ docker container ls
  2. CONTAINER ID IMAGE COMMAND CREATED STATUS PORTS NAMES
  3. bc4e826ee938 redis:latest "docker-entrypoint.s…" 18 seconds ago Up 16 seconds 6379/tcp redis
  4. 059c12486019 flask-demo "flask run -h 0.0.0.0" 4 hours ago Up 6 minutes (healthy) 5000/tcp dazzling_tereshkova

docker-compose 健康检查

示例代码下载(flask healthcheck) 本节源码

示例代码下载(flask + redis healthcheck) 本节源码

一个healthcheck不错的例子 https://gist.github.com/phuysmans/4f67a7fa1b0c6809a86f014694ac6c3a