Python应用程序在docker中运行时不会打印任何内容

Python应用程序在docker中运行时不会打印任何内容,python,docker,dockerfile,Python,Docker,Dockerfile,我在dockerfile中启动了一个Python(2.7)应用程序: CMD ["python","main.py"] FROM python:2.7-stretch ADD . /app WORKDIR /app CMD ["python","main.py"] main.py在启动时打印一些字符串,然后进入循环: print "App started" while True: time.sleep(1) 只要我用-it标志启动容器,一切都会正常工作: $ docker run

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

CMD ["python","main.py"]
FROM python:2.7-stretch
ADD . /app
WORKDIR /app
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

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

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

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

最后,我找到了一个在Docker中运行daemonized时查看Python输出的解决方案,这要感谢@ahmetalpbarkan over at。我本人在此回答,以供进一步参考:

将无缓冲输出与

CMD ["python","-u","main.py"]
而不是

CMD ["python","main.py"]
解决问题;您可以通过查看输出(stderr和stdout)


现在

在我的例子中,使用
-u
运行Python不会改变任何东西。然而,诀窍是将
PYTHONUNBUFFERED=1
设置为环境变量:

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

[编辑]:在Lars的评论之后,将
pythonunbuffer=0
更新为
pythonunbuffer=1
。这不会改变行为并增加清晰度。

请参见以下哪项解释行为的详细原因:

缓冲通常有三种模式:

Stream               Type          Behavior
stdin                input         line-buffered
stdout (TTY)         output        line-buffered
stdout (not a TTY)   output        fully-buffered
stderr               output        unbuffered
  • 如果文件描述符未缓冲,则不会发生任何缓冲,并且读取或写入数据的函数调用会立即发生(并将阻塞)
  • 如果文件描述符已完全缓冲,则使用固定大小的缓冲区,读或写调用仅从缓冲区进行读或写。缓冲区在填满之前不会刷新
  • 如果文件描述符是行缓冲的,那么缓冲将等待直到它看到换行符。因此,数据将一个接一个地缓冲,直到看到\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
因此,如果使用
-t
,from,它将分配一个伪tty,然后
stdout
变为
line buffered
,因此
docker run--name=myapp-it myappimage
可以看到一行输出

而且,如果只使用
-d
,没有分配tty,那么,
stdout
完全缓冲
,一行
应用程序启动
肯定无法刷新缓冲区


然后,使用
-dt
缓冲标准输出行
,或者在python中添加
-u
刷新缓冲区
是解决问题的方法。

如果将
打印
更改为
日志记录,则可以在分离的图像上看到日志

main.py:

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

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

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

使用-t添加tty也可以。你需要在docker日志中找到它


使用大型日志输出时,缓冲区存储所有日志而不将其放入dockers日志中并没有任何问题

因为我还没有看到这个答案:

打印到标准输出后,还可以刷新标准输出:

import time

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

我必须在docker-compose.yml文件中使用
PYTHONUNBUFFERED=1
,才能查看django runserver的输出。

如果要在运行
docker compose up
时将打印输出添加到烧瓶输出,请将以下内容添加到docker compose文件中

web:
  environment:
    - PYTHONUNBUFFERED=1

尝试将这两个环境变量添加到您的解决方案中
PYTHONUNBUFFERED=1
pythonionecoding=UTF-8
如果您没有使用
docker compose
和普通
docker
,您可以将其添加到承载flask应用程序的
Dockerfile

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

CMD [ "flask", "run" ]

对Django应用程序使用
python manage.py runserver
时,添加环境变量
pythonunbuffer=1
可以解决我的问题<代码>打印('helloworld',flush=True)
对我也适用


但是,
python-u
对我不起作用。

如果有人使用conda运行python应用程序,您应该向命令添加
——无捕获输出,因为默认情况下conda会将缓冲区添加到stdout

ENTRYPOINT ["conda", "run", "--no-capture-output", "-n", "my-app", "python", "main.py"]

谢谢你的提示!尝试用您的版本替换所有打印,不幸的是它对我不起作用,仍然无法通过docker日志获得任何输出(在sys.stderr/sys.stdout之间更改没有可见的结果)。这是docker bug吗?请看,原因是:stderr未缓冲,因此您可以使用解决方案修复它。在我的情况下,添加
-e pythonunbuffer=0
会有帮助。谢谢!我的头撞在墙上好几个小时了,即使使用
-u
也无法让日志工作。您的解决方案在Docker for Mac和Django上为我修复了它。我认为这是一个更好的解决方案,我们不必重建Docker映像来查看输出。这非常感谢。值得一提的是,根据文档
PYTHONUNBUFFERED=0
的规定,这只需要是一个非空字符就可以工作。这是一个误导性的b/c。它建议禁用取消缓冲。相反,它是启用的b/c python查找非空字符串。也就是说,最好使用具有相同效果但不会导致错误假设的
PYTHONUNBUFFERED=1
。-u似乎对我有用,但是否有一些文档描述了它的实际功能?正如其他答案所建议的,您可以尝试设置环境变量
ENV PYTHONUNBUFFERED=0
,以防