Python应用程序在docker中运行时不会打印任何内容
我在dockerfile中启动了一个Python(2.7)应用程序: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
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字节数据之前进行缓冲,以先出现的为准”
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
,以防