在docker中分离运行时,Python应用程序不显示任何内容


160

我有一个在我的dockerfile中启动的Python(2.7)应用程序:

CMD ["python","main.py"]

main.py在启动时会打印一些字符串,然后进入循环:

print "App started"
while True:
    time.sleep(1)

只要我使用-it标志启动容器,一切都会按预期进行:

$ docker run --name=myapp -it myappimage
> App started

我稍后可以通过日志看到相同的输出:

$ docker logs myapp
> App started

如果我尝试使用-d标志运行相同的容器,则该容器似乎正常启动,但看不到任何输出:

$ docker run --name=myapp -d myappimage
> b82db1120fee5f92c80000f30f6bdc84e068bafa32738ab7adb47e641b19b4d1
$ docker logs myapp
$ (empty)

但是容器似乎仍在运行;

$ docker ps
Container Status ...
myapp     up 4 minutes ... 

附件也不显示任何内容:

$ docker attach --sig-proxy=false myapp
(working, no output)

任何想法出什么事了吗?在后台运行时,“打印”行为是否有所不同?

Docker版本:

Client version: 1.5.0
Client API version: 1.17
Go version (client): go1.4.2
Git commit (client): a8a31ef
OS/Arch (client): linux/arm
Server version: 1.5.0
Server API version: 1.17
Go version (server): go1.4.2
Git commit (server): a8a31ef

Answers:


265

终于,我找到了一个解决方案,可以在Docker中守护进程运行时查看Python输出,这要感谢GitHub上的 @ahmetalpbalkan 。我自己在这里回答以便进一步参考:

使用无缓冲输出

CMD ["python","-u","main.py"]

代替

CMD ["python","main.py"]

解决问题;您可以通过查看输出(stderr和stdout)

docker logs myapp

现在!


2
-u似乎对我有用,但是在某些地方有一些文档说明了它的实际作用?
小怪杰

7
如其他答案所建议,您可以尝试设置环境变量ENV PYTHONUNBUFFERED=0,以防该-u标志不起作用。
Farshid T

1
这也是我的问题。有关更详细的说明,请参见stackoverflow.com/a/24183941/562883
Jonathan Stray


1
在python3上像梦一样工作,同时将PYTHONUNBUFFERED = 0设置为无济于事。
Lech Migdal

71

就我而言,使用Python运行-u并没有任何改变。但是,窍门是将其设置PYTHONUNBUFFERED=0为环境变量:

docker run --name=myapp -e PYTHONUNBUFFERED=0 -d myappimage

6
就我而言,添加-e PYTHONUNBUFFERED=0帮助。
伍振荣

1
谢谢!我从墙上撞了几个小时,甚至连都无法工作-u。您的解决方案为我在Django的Mac Docker上为我修复了该问题
Someguy123'9

2
我认为这是一个更好的解决方案,我们不必重建
docker

2
非常感谢。值得一提的是,根据文档PYTHONUNBUFFERED
A Star

适用于docker-compose接口。永远不会猜到
深度元素'18

24

对我来说,这是一个功能,而不是错误。如果没有伪TTY,则没有任何标准输出。因此,一个简单的解决方案是使用以下方法为正在运行的容器分配一个伪TTY:

$ docker run -t ...

这不能为问题提供答案。要批评或要求作者澄清,请在其帖子下方发表评论。
总统詹姆斯·波尔克(James K. Polk)

@JamesKPolk,现在好点了吗?
彼得·塞纳

码头工人不需要为stdout和stderr分配伪tty
马特

3
tty: true在土地上
深度元素

15

请参阅本文该文章解释了行为的详细原因:

通常有三种缓冲模式:

  • 如果文件描述符未缓冲,则不会发生任何缓冲,并且读取或写入数据的函数调用会立即发生(并会阻塞)。
  • 如果文件描述符是完全缓冲的,则使用固定大小的缓冲区,并且读或写调用仅从该缓冲区读取或写入。缓冲区填满之前不会刷新。
  • 如果文件描述符是行缓冲的,则缓冲将等待直到看到换行符。因此,数据将一直缓冲直到看到\ n,然后在该时间点刷新所有缓冲的数据。实际上,缓冲区通常有一个最大大小(与完全缓冲情况一样),因此规则实际上更像是“缓冲区,直到看到换行符或遇到4096字节的数据为止,以先发生的为准”。

GNU libc(glibc)使用以下规则进行缓冲:

Stream               Type          Behavior
stdin                input         line-buffered
stdout (TTY)         output        line-buffered
stdout (not a TTY)   output        fully-buffered
stderr               output        unbuffered

因此,如果-tdocker document使用use ,它将分配一个伪tty,然后stdout成为line-buffered,从而docker run --name=myapp -it myappimage可以看到单行输出。

而且,如果仅使用-d,则没有分配tty,那么stdoutis 肯定是fully-buffered一行App started不能刷新缓冲区。

然后,使用-dtto make stdout line buffered-u在python中添加flush the buffer是修复它的方法。



6

如果更改print为,则可以在分离的图像上看到日志logging

main.py:

import time
import logging
print "App started"
logging.warning("Log app started")
while True:
    time.sleep(1)

Dockerfile:

FROM python:2.7-stretch
ADD . /app
WORKDIR /app
CMD ["python","main.py"]

1
很好 提示:使用
Python3。– adhg

问题是在Python 2中(不带括号的打印语句),因此在这里使用2。尽管它在Python3.6上的行为完全相同,所以感谢您提供技巧;)
The Hog

6

由于我还没有看到这个答案:

您也可以在打印到标准输出后刷新它:

import time

if __name__ == '__main__':
    while True:
        print('cleaner is up', flush=True)
        time.sleep(5)

1
这对我来说非常有效,愚蠢的需要这样做,但是现在效果很好。
jamescampbell


3

作为快速解决方案,请尝试以下操作:

from __future__ import print_function
# some code
print("App started", file=sys.stderr)

当我遇到相同的问题时,这对我有用。但是,老实说,我不知道为什么会发生此错误。


谢谢你的提示!尝试用您的版本替换所有打印,但不幸的是,它对我不起作用,仍然无法通过docker日志获得任何输出(在sys.stderr / sys.stdout之间切换不会产生可见结果)。这是Docker错误吗?
jpdus 2015年

看到我的回答,原因是:stderr没有缓冲,因此您可以使用解决方案对其进行修复。
ATLINE


0

通常,我们将其重定向到特定文件(通过从主机挂载卷并将其写入该文件)。

使用-t添加tty也可以。您需要在Docker日志中将其拾取。

使用大型日志输出,如果没有将其存储在dockers日志中,我对缓冲区全部存储没有任何问题。


-1

如果您不使用docker-compose而只是正常使用docker,则可以将其添加到Dockerfile托管flask应用程序的主机中

ARG FLASK_ENV="production"
ENV FLASK_ENV="${FLASK_ENV}" \
    PYTHONUNBUFFERED="true"

CMD [ "flask", "run" ]
By using our site, you acknowledge that you have read and understand our Cookie Policy and Privacy Policy.
Licensed under cc by-sa 3.0 with attribution required.