Подтвердить что ты не робот

Приложение Python ничего не печатает при запуске отсоединенного в докере

У меня есть приложение Python (2.7), которое запускается в моем файле docker:

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)

Любые идеи, что происходит не так? Выполняется ли "печать" по-разному при работе в фоновом режиме?

Версия для докеров:

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
4b9b3361

Ответ 1

Наконец, я нашел решение увидеть вывод Python при запуске demonized в Docker, благодаря @ahmetalpbalkan на GitHub. Отвечая на него здесь для дальнейших ссылок:

Использование небуферизованного вывода с

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

вместо

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

решает проблему; вы можете видеть выходные данные (как stderr, так и stdout) через

docker logs myapp

сейчас

Ответ 2

В моем случае запуск Python с -u ничего не изменил. Однако фокус в том, чтобы установить PYTHONUNBUFFERED=0 в качестве переменной среды:

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

Ответ 3

Для меня это особенность, а не ошибка. Без псевдо-TTY нет ничего общего с stdout. Поэтому простым решением является выделение псевдотематического TTY для запускаемого контейнера:

$ docker run -t ...

Ответ 4

См. эту статью, в которой подробно объясняется причина такого поведения:

Обычно существует три режима буферизации:

  • Если дескриптор файла не буферизован, то буферизация вообще не происходит, и вызовы функций, которые читают или записывают данные, происходят немедленно (и будут блокироваться).
  • Если файловый дескриптор полностью буферизован, то используется буфер фиксированного размера, а вызовы чтения или записи просто читают или пишут из буфера. Буфер не очищается, пока не заполнится.
  • Если файловый дескриптор буферизирован строкой, то буферизация ждет, пока не увидит символ новой строки. Таким образом, данные будут буферизоваться и буферизоваться до тех пор, пока не будет замечено \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 из документа докера, он выделит псевдотетти, тогда stdout станет line-buffered, поэтому docker run --name=myapp -it myappimage сможет увидеть однострочный вывод.

И, если просто использовать -d, tty не был выделен, то stdout - это fully-buffered, одна строка App started наверняка не сможет очистить буфер.

Затем используйте -dt для make stdout line buffered или добавьте -u в python к flush the buffer - это способ исправить это.

Ответ 5

В качестве быстрого исправления попробуйте следующее:

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

Это работает для меня, когда я сталкиваюсь с теми же проблемами. Но, честно говоря, я не знаю, почему эта ошибка происходит.

Ответ 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"]

Ответ 7

Обычно мы перенаправляем его в определенный файл (монтируя том с хоста и записывая его в этот файл).

Добавление tty с использованием -t тоже подойдет. Вы должны поднять это в журналах докера.

Используя большие выходы журнала, у меня не было никаких проблем с хранением буфера все, не помещая это в журнал докеров.