Вопрос-Ответ

Why doesn't Python app print anything when run in a detached docker container?

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

У меня есть приложение 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 ...

Attach также ничего не отображает:

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

Есть идеи, что происходит не так? "Print" ведет себя по-другому при запуске в фоновом режиме?

Версия для 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
Переведено автоматически
Ответ 1

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

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

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

вместо

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

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

docker logs myapp

почему -u ссылка

- print is indeed buffered and docker logs will eventually give you that output, just after enough of it will have piled up
- executing the same script with python -u gives instant output as said above
- import logging + logging.warning("text") gives the expected result even without -u

что это означает под python -u ref. > python --help | grep -- -u

-u     : force the stdout and stderr streams to be unbuffered;
Ответ 2

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

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

[Редактировать]: Обновлено PYTHONUNBUFFERED=0 до PYTHONUNBUFFERED=1 после комментария Ларса. Это не меняет поведение и добавляет ясности.

Ответ 3

Если вы хотите добавить выходные данные для печати в выходные данные Flask при запуске docker-compose up, добавьте следующее в свой файл docker compose.

web:
environment:
- PYTHONUNBUFFERED=1

https://docs.docker.com/compose/environment-variables/

Ответ 4

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


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



  • Если дескриптор файла не буферизован, то буферизация вообще не происходит, и вызовы функций для чтения или записи данных происходят немедленно (и блокируются).

  • Если файловый дескриптор полностью буферизован, то используется буфер фиксированного размера, и вызовы read или write просто считывают или записывают данные из буфера. Буфер не очищается до тех пор, пока он не заполнится.

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

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

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

python