【问题标题】:PHP in Docker - fopen() or file_put_contents() cannot write to /proc/1/fd/2 for stdout writingDocker 中的 PHP - fopen() 或 file_put_contents() 无法写入 /proc/1/fd/2 以进行标准输出写入
【发布时间】:2019-09-01 07:21:16
【问题描述】:

在基于 CentOS7 的 Docker 容器中运行 php-fpm 应用程序。

由于我使用的是 Docker,我必须将所有进程的日志输出写入 PID 1 的输出。这样,Docker 引擎可以获取日志以供以后处理(因此它们显示在 docker logs 中)。

我可以通过将所有日志写入/proc/1/fd/2 来完成此操作,而不会在任何应用程序中出现问题。我可以用 nginx 来做,只做echo "test" > /proc/1/fd/2,它对docker logs 显示很好。

但是使用 php 软件我想做同样的事情,写信给/proc/1/fd/2 但是无论我做什么,我似乎都无法获得文件流。

PHP-FPM 产生许多子进程。因此,我必须明确写入 PID 1 的标准输出!

所以我正在做这样的事情:

$handle = fopen("/proc/1/fd/2", "w");
fwrite($handle, $msg);
fclose($handle);

我刚收到Warning: fopen(/proc/1/fd/2): failed to open stream: No such file or directory

注意:我也用https://www.php.net/manual/en/function.file-put-contents.php 尝试过,结果也一样。它本质上是 fopen、fwrite、fclose 的包装器。

我试着把它扔到一个符号链接上:

bash-4.2$ ls -l /tmp/stdout
lrwxrwxrwx. 1 nginx nginx 12 Apr 10 11:19 /tmp/stdout -> /proc/1/fd/2

然后像fopen("/tmp/stdout", "w");一样将方法指向它

我得到完全相同的错误Warning: fopen(/tmp/stdout): failed to open stream: No such file or directory

这是我需要写入的输出:

bash-4.2$ ls -l /proc/1/fd/2
l-wx------. 1 nginx nginx 64 Apr 10 11:21 /proc/1/fd/2 -> pipe:[3523867]

我可以使用我尝试过的任何其他应用程序(包括 nginx 和 bash)毫无问题地写入它(直接或通过符号链接)。

PHP 进程以拥有输出流的同一用户身份运行

bash-4.2$ ps -ef
UID        PID  PPID  C STIME TTY          TIME CMD
nginx        1     0  0 11:21 ?        00:00:00 php-fpm: master process (/etc/php-fpm.conf)
nginx        7     1  0 11:21 ?        00:00:00 php-fpm: pool www
nginx        8     1  0 11:21 ?        00:00:00 php-fpm: pool www
nginx        9     1  0 11:21 ?        00:00:00 php-fpm: pool www
nginx       10     1  0 11:21 ?        00:00:00 php-fpm: pool www
nginx       11     1  0 11:21 ?        00:00:00 php-fpm: pool www
nginx       12     1  0 11:21 ?        00:00:00 php-fpm: pool www

bash-4.2$ ls -l /proc/1/fd/2
l-wx------. 1 nginx nginx 64 Apr 10 11:21 /proc/1/fd/2 -> pipe:[3523867]

我尝试向它抛出一些疯狂的权限,他们不接受:

bash-4.2$ chmod 777 /proc/1/fd/2
bash-4.2$ ls -l /proc/1/fd/2
l-wx------. 1 nginx nginx 64 Apr 10 11:21 /proc/1/fd/2 -> pipe:[3523867]

这里是/dev/ 目录,我不能使用它们,因为它们指向proc/self 而不是/proc/1

lrwxrwxrwx. 1 root root   11 Apr 10 11:21 core -> /proc/kcore
lrwxrwxrwx. 1 root root   13 Apr 10 11:21 fd -> /proc/self/fd
crw-rw-rw-. 1 root root 1, 7 Apr 10 11:21 full
drwxrwxrwt. 2 root root   40 Apr 10 11:21 mqueue
crw-rw-rw-. 1 root root 1, 3 Apr 10 11:21 null
lrwxrwxrwx. 1 root root    8 Apr 10 11:21 ptmx -> pts/ptmx
drwxr-xr-x. 2 root root    0 Apr 10 11:21 pts
crw-rw-rw-. 1 root root 1, 8 Apr 10 11:21 random
drwxrwxrwt. 2 root root   40 Apr 10 11:21 shm
lrwxrwxrwx. 1 root root   15 Apr 10 11:21 stderr -> /proc/self/fd/2
lrwxrwxrwx. 1 root root   15 Apr 10 11:21 stdin -> /proc/self/fd/0
lrwxrwxrwx. 1 root root   15 Apr 10 11:21 stdout -> /proc/self/fd/1

我尝试将/dev/fd 符号链接更改为指向/proc/1/fd/2,然后尝试写入php://fd/2,但它也不起作用,同样的错误。

【问题讨论】:

  • /proc 中胡闹不是这样做的方法。而是找到一种通过其他方法聚合日志记录的方法。考虑使用可以写入的套接字创建记录器进程。
  • @tadman serverfault.com/questions/658367/… 我只是在这里使用被广泛接受的方法。
  • 这可能有效,但如果多个进程直接写入同一个文件句柄,也会导致日志输出严重混乱。除非每个进程在每个换行符后显式刷新输出,否则每个进程的输出将非常糟糕地混合在一起,即使那样我也不确定它会好起来。

标签: php docker logging stdout


【解决方案1】:

我也面临同样的问题。现在,作为一种解决方法,我将在真实日志文件上尝试后台“tail -f”并将输出从 tail 重定向到 /proc/1/fd/1,如下所示:

tail -f file.log > /proc/1/fd/1 &

不是最好的解决方案,但它可以完成工作

【讨论】:

  • 也许检查一下我的答案,在你的回答之后约 45 分钟创建 ^^
【解决方案2】:

php-fpm 在nginx 用户下运行,我敢打赌 nginx 用户无权访问/proc/1/fd/2

要查看 nginx 用户可以走多远,请运行:

sudo -u nginx /bin/sh -c 'namei -l /proc/1/fd/2'

我打赌它不会达到 2,namei 会告诉你错误发生在哪里,修复你的权限。

作为记录,当我在 Debian Linux 系统上运行它时,我得到:

root@x2ratma:~# sudo -u www-data /bin/sh -c 'namei -l /proc/1/fd/2'
f: /proc/1/fd/2
drwxr-xr-x root root /
dr-xr-xr-x root root proc
dr-xr-xr-x root root 1
dr-x------ root root fd
                     2 - Permission denied

告诉我www-data 用户没有对 /proc/1/fd 文件夹的读取权限。 (一个肮脏的快速修复将是:sudo chmod a+rx /proc/1/fd 这意味着 give everybody read access to /proc/1/fd

【讨论】:

    【解决方案3】:

    我通过在php.ini 中将error_log 设置为/proc/1/fd/2 来解决这个问题,并使用error_log 将日志发送到PHP 的系统记录器。

    error_log($msg, 0);
    

    【讨论】:

      猜你喜欢
      • 2018-12-05
      • 1970-01-01
      • 2013-06-24
      • 2011-07-23
      • 2014-11-09
      • 1970-01-01
      • 1970-01-01
      • 2018-03-07
      相关资源
      最近更新 更多