Docker容器仅在退出时打印输出

3

我编写了一个 Python 程序和它的 Dockerfile:

import time
print("Begin")
time.sleep(100);
print("End")

已创建了相关镜像,并使用 docker run <image-id> 命令运行。让我感到惊讶的是,在控制台中给出运行命令后,它会等待 sleep(100) 秒钟,然后一起打印 "Begin""End"
为什么我们在运行过程中没有得到中间结果?
另外,如果数据产生后不会立即发送,我应该如何编写流式应用程序(在 Kafka 或其他应用中)?

1
“禁用输出缓冲”不完全是重复的,但它描述了您正在看到的行为。 - David Maze
2个回答

5
当您从控制台运行Python脚本时,它会立即在stdout上显示Begin,因为它是tty(交互式)并在每行的末尾进行刷新。但如果像这样重定向stdoutstdinpython /tmp/a.py < /dev/null | cat,Python脚本将不会注意到它是从tty运行的,并且只有在完成时才会进行刷新。
如果您从Docker容器中运行相同的脚本,默认情况下它没有tty,您必须使用--tty,-t分配伪终端显式地请求一个:
docker run -t yourimage

或者,如果您不想让容器运行时附带tty,您可以通过设置PYTHONUNBUFFERED环境变量、在python解释器中添加-u选项或修改脚本来强制执行flush

import sys
import time
print("Begin")
sys.stdout.flush()
time.sleep(100);
print("End")

或者使用flush参数(仅适用于Python3):
import time
print("Begin", flush=True)
time.sleep(100);
print("End")

2

当向 stdout 打印时,操作系统不能保证它会立即被写入。

保证的是,当文件描述符关闭时,操作系统将刷新写入缓冲区(这就是为什么当 Docker 退出时你会得到输出)。

为了确保操作系统会刷新,可以在任何重要的打印之后添加以下代码:

import sys
sys.stdout.flush()

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接