Docker容器运行Django+Gunicorn时,非PID 1进程日志问题咨询
嘿,这事儿我熟!你遇到的是Gunicorn多进程架构下的典型日志问题,咱们一步步来理清楚:
先看你给出的ps -ef输出:
root@72981b4f355e:/usr/src/app# ps -ef UID PID PPID C STIME TTY TIME CMD root 1 0 0 15:32 ? 00:00:00 /usr/local/bin/python /usr/local/bin/gunicorn MyApp.wsgi:application --bind 0.0.0.0:8000 --workers 3 root 9 1 1 15:32 ? 00:00:02 /usr/local/bin/python /usr/local/bin/gunicorn MyApp.wsgi:application --bind 0.0.0.0:8000 --workers 3 root 11 1 1 15:32 ? 00:00:02 /usr/local/bin/python /usr/local/bin/gunicorn MyApp.wsgi:application --bind 0.0.0.0:8000 --workers 3
这里PID=1的是Gunicorn的主进程(master),而PID=9、11的是它fork出来的worker进程——这些worker才是实际处理HTTP请求、输出业务日志的进程,所以你会看到来自PID≠1的日志,这是Gunicorn多进程模式的正常表现,不是bug!
下面给你几个实用的解决方案,按需选择:
开发环境快速方案:单进程运行Gunicorn
如果是开发测试用,直接去掉--workers 3参数,让Gunicorn只启动主进程,所有日志都会从PID=1输出。启动命令改成:gunicorn MyApp.wsgi:application --bind 0.0.0.0:8000缺点是没法利用多核CPU,也没有进程自动重启的守护能力,不适合生产环境。
生产环境推荐方案:统一worker日志到主进程
Gunicorn自带参数可以把所有worker的标准输出/错误重定向到主进程,启动时加上--capture-output和--log-file=-(让日志输出到stdout,Docker默认收集这个流)。修改后的启动命令:gunicorn MyApp.wsgi:application --bind 0.0.0.0:8000 --workers 3 --capture-output --log-file=-这样所有worker的日志都会被主进程捕获,统一从PID=1输出,Docker就能完整收集到所有应用日志了。
进阶方案:容器内日志收集工具
如果不想修改Gunicorn启动参数,可以在容器内部署rsyslog这类工具,收集所有进程的日志并统一输出;或者配置Docker的第三方日志驱动(比如Fluentd、Logstash)来抓取容器内所有进程的日志。不过这种方式配置相对复杂,一般推荐前面两种更直接的方法。
内容的提问来源于stack exchange,提问作者blueFast

