问题描述
在设置一个由三个运行小型Flask应用程序的Docker容器组成的网络时,遇到了一个关于日志记录的奇怪问题。他的Python应用程序如下所示:
from flask import Flask, request
import sys
import logging
import logging.handlers
import os
app = Flask(__name__)
logger = logging.getLogger('Logger')
logger.setLevel(logging.DEBUG)
log_handler = logging.StreamHandler(sys.stdout)
logger.addHandler(log_handler)
service_name = ""
if 'SERVICE_NAME' in os.environ:
service_name = os.environ['SERVICE_NAME']
logger = logging.LoggerAdapter(logger, {"serviceName" : service_name})
@app.route("/ping")
def ping():
logger.info(f'answering ping request')
return f'{service_name} OK'
if __name__ == "__main__":
logger.info("Started")
app.run(debug=True, host='0.0.0.0')
他在一个Docker网络中启动了三个此应用程序的实例,并在nginx后面运行:
docker network create tNet
docker run -it -d -p 24224:24224 -v `pwd`:/fluentd/etc -e FLUENTD_CONF=fluentd.conf --name=fluentd_logging fluent/fluentd
docker run -d --log-driver=fluentd --name ms1 -e SERVICE_NAME="ms1" --network tNet testflask
docker run -d --log-driver=fluentd --name ms2 -e SERVICE_NAME="ms2" --network tNet testflask
docker run -d --log-driver=fluentd --name ms3 -e SERVICE_NAME="ms3" --network tNet testflask
docker run -d --name=nginx --network tNet --volume `pwd`/nginx.conf:/etc/nginx/conf.d/default.conf -p 2000:2000 -p 3000:3000 nginx
nginx的配置如下:
upstream app {
server ms1:5000;
server ms2:5000;
server ms3:5000;
}
server {
listen 2000;
location / {
proxy_pass http://app;
}
}
Fluentd的配置如下:
<source>
@type forward
</source>
<match>
@type stdout
</match>
虽然使用curl可以看到每个服务实例都有响应:
curl localhost:2000/ping
ms1 OK
curl localhost:2000/ping
ms2 OK
curl localhost:2000/ping
ms3 OK
但当用户检查日志时,只能看到来自第三个服务实例的日志:
docker logs <fluent容器ID> | grep -Eis "answering ping"
19-08-06 15:34:46.000000000 +0000 be338a3d5aa0: {"container_id":"be338a3d5aa0b8920366fdf1ba2a267082cee47e681adcea16b6c51c9c82cf0d","container_name":"/ms3","source":"stdout","log":"answering ping request"}
解决方案
请注意以下操作可能因版本差异而有所不同,建议进行备份。
用户在这里遇到了Fluentd容器启动需要一些时间的问题。由于Fluentd容器是以--detach
模式启动的,所以在后续的容器尝试连接之前,Fluentd实际上还没有完全运行。只有当Fluentd已经启动时,Flask应用程序的第三个实例才能连接。因此,通过延迟其他容器的启动,可以解决这个问题。
解决方案步骤
- 修改启动脚本,将其他Flask应用程序容器的启动延迟一段时间,以确保Fluentd容器已经完全运行。
- 可以使用一些简单的延迟机制,如在脚本中使用
sleep
命令。
以下是示例脚本修改:
#!/bin/bash
# 启动Fluentd容器
docker run -it -d -p 24224:24224 -v `pwd`:/fluentd/etc -e FLUENTD_CONF=fluentd.conf --name=fluentd_logging fluent/fluentd
# 延迟一段时间,等待Fluentd完全启动
sleep 5
# 启动其他Flask应用程序容器
docker run -d --log-driver=fluentd --name ms1 -e SERVICE_NAME="ms1" --network tNet testflask
docker run -d --log-driver=fluentd --name ms2 -e SERVICE_NAME="ms2" --network tNet testflask
docker run -d --log-driver=fluentd --name ms3 -e SERVICE_NAME="ms3" --network tNet testflask
# 启动Nginx容器
docker run -d --name=nginx --network tNet --volume `pwd`/nginx.conf:/etc/nginx/conf.d/default.conf -p 2000:2000 -p 3000:3000 nginx
通过在脚本中添加适当的延迟,可以确保所有Flask应用程序容器在Fluentd容器完全运行后才连接,从而解决日志记录问题。
这样,所有的Flask应用程序容器将有足够的时间连接到Fluentd容器,确保日志能够正确记录。
请注意,延迟的时间可以根据实际情况进行调整,以确保Fluentd容器已经完全就绪。
正文完