我有一个Python(2.7)应用程序,它在我的dockerfile中启动:
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
答案 0 :(得分:145)
最后,我找到了一个解决方案,看看在Docker中运行daemonized时的Python输出,感谢@ahmetalpbalkan在GitHub。在这里回答它以供进一步参考:
使用
的无缓冲输出CMD ["python","-u","main.py"]
而不是
CMD ["python","main.py"]
解决问题;你可以通过
看到输出(stderr和stdout)docker logs myapp
现在!
答案 1 :(得分:48)
就我而言,使用-u
运行Python并没有改变任何东西。然而,诀窍是将PYTHONUNBUFFERED=0
设置为环境变量:
docker run --name=myapp -e PYTHONUNBUFFERED=0 -d myappimage
答案 2 :(得分:14)
尝试将这两个环境变量添加到解决方案PYTHONUNBUFFERED=1
和PYTHONIOENCODING=UTF-8
答案 3 :(得分:12)
对我来说这是一个功能,而不是一个bug。如果没有伪TTY,就没有什么可以去的。因此,一个简单的解决方案是使用以下命令为正在运行的容器分配伪TTY:
$ docker run -t ...
答案 4 :(得分:8)
如果要在运行docker-compose up
时将打印输出添加到Flask输出中,请将以下内容添加到docker compose文件中。
web:
environment:
- PYTHONUNBUFFERED=1
答案 5 :(得分:6)
请参见this article,其中详细说明了该行为的原因:
通常有三种缓冲模式:
- 如果文件描述符未缓冲,则不会发生任何缓冲,并且读取或写入数据的函数调用会立即发生(并会阻塞)。
- 如果文件描述符已完全缓冲,则使用固定大小的缓冲区,并且读或写调用仅从该缓冲区读取或写入。直到缓冲区填满,缓冲区才会被清空。
- 如果文件描述符是行缓冲的,则缓冲将等待直到看到换行符。因此,数据将不断缓冲直到看到\ n,然后在该时间点刷新所有缓冲的数据。实际上,缓冲区通常有一个最大大小(与完全缓冲情况一样),因此规则实际上更像是“缓冲区,直到看到换行符或遇到4096字节的数据为止,以先发生的为准”。 / li>
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
因此,如果使用docker document中的-t
,它将分配一个伪tty,然后stdout
变成line-buffered
,因此docker run --name=myapp -it myappimage
可以看到单行输出。
并且,如果仅使用-d
,则没有分配tty,则stdout
是fully-buffered
,一行App started
肯定无法刷新缓冲区。
然后,使用-dt
到make stdout line buffered
或将python中的-u
添加到flush the buffer
是解决问题的方法。
答案 6 :(得分:4)
如果将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"]
答案 7 :(得分:2)
因为我还没有看到这个答案:
您也可以在打印到标准输出后将其冲洗:
import time
if __name__ == '__main__':
while True:
print('cleaner is up', flush=True)
time.sleep(5)
答案 8 :(得分:1)
在将python -u
用于Django应用程序时,添加环境变量{{1}}解决了我的问题。 {{1}}也对我有用。
但是,{{1}}对我不起作用。
答案 9 :(得分:1)
如果有人使用 conda 运行 python 应用程序,您应该将 --no-capture-output
添加到命令中,因为默认情况下 conda 缓冲区到标准输出。
ENTRYPOINT ["conda", "run", "--no-capture-output", "-n", "my-app", "python", "main.py"]
答案 10 :(得分:0)
快速修复,试试这个:
from __future__ import print_function
# some code
print("App started", file=sys.stderr)
当我遇到同样的问题时,这对我有用。但是,说实话,我不知道为什么会发生这种错误。
答案 11 :(得分:0)
通常,我们将其重定向到特定文件(通过从主机挂载卷并将其写入该文件)。
使用-t添加tty也可以。您需要在Docker日志中将其拾取。
使用大型日志输出,如果不将其放入dockers日志中,我对缓冲区全部存储没有任何问题。
答案 12 :(得分:0)
我必须在docker-compose.yml文件中使用PYTHONUNBUFFERED=1
才能查看django runserver的输出。
答案 13 :(得分:0)
如果您不使用See
,而是使用普通的docker-compose
,则可以将其添加到托管烧瓶应用程序的docker
中
Dockerfile