在 Docker 中拖尾命名管道以写入标准输出
Tailing named pipe in Docker to write to stdout
我的Docker文件:
FROM php:7.0-fpm
# Install dependencies, etc
RUN \
&& mkfifo /tmp/stdout \
&& chmod 777 /tmp/stdout
ADD docker-entrypoint.sh /usr/local/bin/docker-entrypoint.sh
ENTRYPOINT ["/usr/local/bin/docker-entrypoint.sh"]
如您所见,我正在 /tmp/stdout
创建一个命名管道。还有我的 docker-entrypoint.sh
:
#!/usr/bin/env bash
# Some run-time configuration stuff...
exec "./my-app" "$@" | tail -f /tmp/stdout
我的 PHP 应用程序(名为 my-app
的可执行文件)将其应用程序日志写入 /tmp/stdout
。我希望这些日志随后被 Docker 捕获,以便我可以执行 docker logs <container_id>
并查看应用程序写入 /tmp/stdout
的日志。我正在尝试通过 运行 执行 my-app
命令然后拖尾 /tmp/stdout
,然后将日志输出到 stdout
.
我看到的情况是,当我 运行 我的应用程序写入第一条日志消息时挂起。我相信发生这种情况是因为没有从命名管道中“读取”任何内容,并且写入命名管道块直到从中读取内容。如果我执行 docker exec -it <container_id> bash
,然后在容器内自己执行 tail -f /tmp/stdout
,则可以确认这一点。一旦我这样做,容器立即退出,因为应用程序已将其日志写入命名管道。
由于我不想让这个 post 膨胀的原因,my-app
本身不可能将日志写入 stdout
。它必须使用 /tmp/stdout
.
谁能告诉我为什么这不起作用,我需要更改什么?我希望我必须更改 docker-entrypoint.sh
中的 exec
调用,但我不确定如何更改。谢谢!
What I'm seeing happen is that when I run my application, it hangs when it writes the first log message. I believe this happens because there is nothing "reading" from the named pipe, and writing to a named pipe blocks until something reads from it.
这是正确的,参见 fifo(7)
。但是使用您的示例代码
exec "./my-app" "$@" | tail -f /tmp/stdout
这实际上应该有效,因为管道将同时启动 ./my-app
和 tail
,因此 是 从 /tmp/stdout
读取的内容。
但这里的一个问题是 tail -f
永远不会自行终止,因此您的 docker-entrypoint.sh
/容器也不会。您可以通过以下方式解决此问题:
tail --pid=$$ -f /tmp/stdout &
exec "./my-app" "$@"
tail --pid
将在 id 提供的进程终止后立即终止,其中 $$
是 bash
进程的 pid(通过 exec
之后的 pid ./my-app
).
For reasons that I won't bloat this post with, it's not possible for my-app
itself to write logs to stdout
. It has to use /tmp/stdout
.
这是否意味着它必须写入文件系统 路径 还是路径 /tmp/stdout
是硬编码的?
如果您可以使用任何路径,您可以使用 /dev/stdout
/ /proc/self/fd/1
/ /proc/$$/fd/1
作为日志记录路径,让您的应用程序写入 stdout
.
如果 /tmp/stdout
是硬编码的,请尝试将其符号链接到 /dev/stdout
:
ln -s /dev/stdout /tmp/stdout
我的Docker文件:
FROM php:7.0-fpm
# Install dependencies, etc
RUN \
&& mkfifo /tmp/stdout \
&& chmod 777 /tmp/stdout
ADD docker-entrypoint.sh /usr/local/bin/docker-entrypoint.sh
ENTRYPOINT ["/usr/local/bin/docker-entrypoint.sh"]
如您所见,我正在 /tmp/stdout
创建一个命名管道。还有我的 docker-entrypoint.sh
:
#!/usr/bin/env bash
# Some run-time configuration stuff...
exec "./my-app" "$@" | tail -f /tmp/stdout
我的 PHP 应用程序(名为 my-app
的可执行文件)将其应用程序日志写入 /tmp/stdout
。我希望这些日志随后被 Docker 捕获,以便我可以执行 docker logs <container_id>
并查看应用程序写入 /tmp/stdout
的日志。我正在尝试通过 运行 执行 my-app
命令然后拖尾 /tmp/stdout
,然后将日志输出到 stdout
.
我看到的情况是,当我 运行 我的应用程序写入第一条日志消息时挂起。我相信发生这种情况是因为没有从命名管道中“读取”任何内容,并且写入命名管道块直到从中读取内容。如果我执行 docker exec -it <container_id> bash
,然后在容器内自己执行 tail -f /tmp/stdout
,则可以确认这一点。一旦我这样做,容器立即退出,因为应用程序已将其日志写入命名管道。
由于我不想让这个 post 膨胀的原因,my-app
本身不可能将日志写入 stdout
。它必须使用 /tmp/stdout
.
谁能告诉我为什么这不起作用,我需要更改什么?我希望我必须更改 docker-entrypoint.sh
中的 exec
调用,但我不确定如何更改。谢谢!
What I'm seeing happen is that when I run my application, it hangs when it writes the first log message. I believe this happens because there is nothing "reading" from the named pipe, and writing to a named pipe blocks until something reads from it.
这是正确的,参见 fifo(7)
。但是使用您的示例代码
exec "./my-app" "$@" | tail -f /tmp/stdout
这实际上应该有效,因为管道将同时启动 ./my-app
和 tail
,因此 是 从 /tmp/stdout
读取的内容。
但这里的一个问题是 tail -f
永远不会自行终止,因此您的 docker-entrypoint.sh
/容器也不会。您可以通过以下方式解决此问题:
tail --pid=$$ -f /tmp/stdout &
exec "./my-app" "$@"
tail --pid
将在 id 提供的进程终止后立即终止,其中 $$
是 bash
进程的 pid(通过 exec
之后的 pid ./my-app
).
For reasons that I won't bloat this post with, it's not possible for
my-app
itself to write logs tostdout
. It has to use/tmp/stdout
.
这是否意味着它必须写入文件系统 路径 还是路径 /tmp/stdout
是硬编码的?
如果您可以使用任何路径,您可以使用 /dev/stdout
/ /proc/self/fd/1
/ /proc/$$/fd/1
作为日志记录路径,让您的应用程序写入 stdout
.
如果 /tmp/stdout
是硬编码的,请尝试将其符号链接到 /dev/stdout
:
ln -s /dev/stdout /tmp/stdout