PHP-FPM在Docker没有日志输出到/dev/stderr

kubernetes迁移产生日志收集问题

今天把腾讯kubernetes TKE上的一些服务弄到单机docker-compose里去了。为什么迁TKE的问题先不谈,因为原来的服务日志都是依赖腾讯Loglistener,这个日志端和腾讯TKE是完美配合的,去node上拿文件日志非常方便,也没有去优化。但这次由于结构换了,期望从docker-compose的Fluentd驱动来获得日志然后用kafka协议发到接收端,第一步就是要把容器都输出到/dev/stdout和/dev/stderr。

找不到日志

monolog的配置

代码用的是php里最有名的monolog,先改配置。把日志流输出到path: "php://stderr",这里有第一个发现,不能写path: "/dev/stderr"或者path: "/proc/1/fd/2",这两种写法都会报File Append的错误,显然要使用最前面的封装版本,当然这和手册上的有点出入。

推荐你简单使用常量 STDIN、 STDOUT 和 STDERR 来代替手工打开这些封装器。

https://www.php.net/manual/zh/wrappers.php.php 手册上原话。

找不到日志

容器服务是用Supervisor管理的,一个容器上跑php-fpm和nginx,Supervisor里FPM的配置是写到/dev/stderr里去的,但结果就是无论如何配置都无法写到/dev/stderr。

bash-5.1# ps aux | grep master
    7 root      0:00 php-fpm: master process (/usr/local/etc/php-fpm.d/www.conf)
    8 root      0:00 nginx: master process /usr/local/nginx/sbin/nginx -g daemon off;

查看下进程err输出情况。

bash-5.1# ls -l /proc/7/fd/2
l-wx------    1 root     root            64 Apr  7 14:44 /proc/7/fd/2 -> /usr/local/var/log/php-fpm.log

日志被牢牢的写进了/usr/local/var/log/php-fpm.log,没有进管道,找了半天发现,是一个神奇的配置组合问题。

[program:php-fpm]
command=/usr/local/sbin/php-fpm --force-stderr --nodaemonize --fpm-config /usr/local/etc/php-fpm.d/www.conf
autostart=true
autorestart=true
priority=5
stdout_events_enabled=true
stderr_events_enabled=true
stdout_logfile=/dev/stdout
stdout_logfile_maxbytes=0
stderr_logfile=/dev/stderr
stderr_logfile_maxbytes=0
stopsignal=QUIT

关键在于,当你用了nodaemonized,就要用–force-stderr来保证进程写到容器的stderr输出。参考,https://stackoverflow.com/questions/50995042/docker-does-not-catch-php-fpm-outputs-with-symfony-and-monolog

As php-fpm is run in nodaemonized mode, you need to set the –force-stderr flag which "Force output to stderr in nodaemonize even if stderr is not a TTY."

检查一下,连接对了!用docker logs -f container检查也没问题了!

bash-5.1# ls -l /proc/7/fd/2
l-wx------    1 root     root            64 Apr  7 14:44 /proc/7/fd/2 -> pipe:[13099270]

已发布

分类

作者: