tail -f 方法并不是真正的最佳实践。
正如您所注意到的,运行进程并生成日志的正确方法是将其输出直接写入 stdout 和 stderr,docker logs 将捕获它们。您可以配置 Docker 的日志记录层以将它们发送到其他地方;如果您迁移到 Kubernetes 等集群基础架构,您可以配置其日志记录层来捕获日志,而无需修改您的应用程序代码。
#!/bin/sh
# I am the script that runs the main container process.
# Run a single process, as a foreground process; when that
# process ends, the container exits.
exec some_server --no-daemon --log-file /dev/stdout
当您看到tail -f 时,它通常看起来像这样:
#!/bin/sh
# Start something as a background process.
something --log-file /var/log/something.log &
# Hackily keep the container from exiting.
tail -f /var/log/something.log
主容器进程是tail 进程。当tail退出时,容器会停止,如果你docker stop容器,信号会转到tail。哦,顺便说一句,作为副作用,有一个something 进程正在运行,但如果它失败了,Docker 无法注意到它。尽管如此,由于tail 进程是主进程并且tail -f 将永远不会退出,这会保持容器运行,并且它会使其基于文件的日志对容器的标准输出可见。
这里另一个有趣的方法是 Docker Hub httpd 映像所做的:它将日志记录设置为指向一个文件,但该文件的默认内容是指向 /dev/stdout 的符号链接。
RUN mkdir /var/log/something \
&& ln -s /dev/stdout /var/log/something/something.log
CMD ["something", "--log-file", "/var/log/something/something.log"]
这很有趣,因为默认行为是将内容写入该日志文件,但它实际上是 /dev/stdout 特殊设备,因此它将转到进程的标准输出(主容器进程的)。如果您想在文件中捕获它,您可以将自己的目录绑定到 /var/log/something 上,这将隐藏符号链接。