Die Python-App druckt nichts, wenn sie getrennt im Docker ausgeführt wird

160

Ich habe eine Python (2.7) -App, die in meiner Docker-Datei gestartet wird:

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

main.py druckt beim Start einige Zeichenfolgen und geht anschließend in eine Schleife:

print "App started"
while True:
    time.sleep(1)

Solange ich den Container mit dem Flag -it starte, funktioniert alles wie erwartet:

$ docker run --name=myapp -it myappimage
> App started

Und ich kann die gleiche Ausgabe später über Protokolle sehen:

$ docker logs myapp
> App started

Wenn ich versuche, denselben Container mit dem Flag -d auszuführen, scheint der Container normal zu starten, aber ich kann keine Ausgabe sehen:

$ docker run --name=myapp -d myappimage
> b82db1120fee5f92c80000f30f6bdc84e068bafa32738ab7adb47e641b19b4d1
$ docker logs myapp
$ (empty)

Aber der Container scheint immer noch zu laufen;

$ docker ps
Container Status ...
myapp     up 4 minutes ... 

Anhängen zeigt auch nichts an:

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

Irgendwelche Ideen, was falsch läuft? Verhält sich "Drucken" anders, wenn es im Hintergrund ausgeführt wird?

Docker-Version:

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
jpdus
quelle

Antworten:

265

Schließlich habe ich dank @ahmetalpbalkan bei GitHub eine Lösung gefunden, um die Python-Ausgabe zu sehen, wenn sie in Docker daemonisiert ausgeführt wird . Beantworte es hier selbst als weitere Referenz:

Ungepufferte Ausgabe mit

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

anstatt

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

löst das Problem; Sie können die Ausgabe (sowohl stderr als auch stdout) über sehen

docker logs myapp

jetzt!

jpdus
quelle
2
-u scheint für mich zu funktionieren, aber gibt es irgendwo eine Dokumentation mit einer Beschreibung dessen, was es tatsächlich tut?
Little Geek
7
Wie in anderen Antworten vorgeschlagen, können Sie versuchen, Umgebungsvariablen festzulegen, ENV PYTHONUNBUFFERED=0falls das -uFlag nicht funktioniert.
Farshid T
1
Das war auch mein Problem. Eine ausführlichere Erklärung finden Sie unter stackoverflow.com/a/24183941/562883
Jonathan Stray
1
Funktioniert wie ein Traum auf Python3, während das Setzen von PYTHONUNBUFFERED = 0 nicht geholfen hat.
Lech Migdal
71

In meinem Fall hat das Ausführen von Python mit -unichts geändert. Der Trick bestand jedoch darin, eine PYTHONUNBUFFERED=0Umgebungsvariable festzulegen:

docker run --name=myapp -e PYTHONUNBUFFERED=0 -d myappimage
Sieger
quelle
6
In meinem Fall -e PYTHONUNBUFFERED=0hilft das Hinzufügen .
David Ng
1
Danke dir! Ich schlug stundenlang mit dem Kopf gegen eine Wand und konnte nicht einmal Protokolle zum Arbeiten bringen -u. Ihre Lösung hat es für mich auf Docker für Mac mit Django
Someguy123
2
Ich denke, dies ist eine bessere Lösung, dass wir das Docker-Image nicht neu
erstellen
2
Das ist großartig, danke. Es ist erwähnenswert, dass dies nur ein nicht leerer Charakter sein muss, um gemäß den Dokumenten PYTHONUNBUFFERED
A Star
Arbeitete für Docker-Compose-Schnittstelle. Hätte nie
gedacht
24

Für mich ist es eine Funktion, kein Fehler. Ohne ein Pseudo-TTY gibt es nichts zu tun. Eine einfache Lösung besteht darin, Ihrem laufenden Container ein Pseudo-TTY zuzuweisen mit:

$ docker run -t ...
Peter Senna
quelle
Dies gibt keine Antwort auf die Frage. Um einen Autor zu kritisieren oder um Klärung zu bitten, hinterlassen Sie einen Kommentar unter seinem Beitrag.
Präsident James K. Polk
@ JamesKPolk, ist es jetzt besser?
Peter Senna
Docker benötigt keine Pseudo-Tty für stdout und stderr
Matt
3
tty: truein komponieren Land
tiefes Element
15

In diesem Artikel wird der detaillierte Grund für das Verhalten erläutert:

Es gibt normalerweise drei Modi zum Puffern:

  • Wenn ein Dateideskriptor ungepuffert ist, tritt keinerlei Pufferung auf, und Funktionsaufrufe, die Daten lesen oder schreiben, treten sofort auf (und werden blockiert).
  • Wenn ein Dateideskriptor vollständig gepuffert ist, wird ein Puffer fester Größe verwendet, und Lese- oder Schreibaufrufe werden einfach aus dem Puffer gelesen oder geschrieben. Der Puffer wird erst geleert, wenn er voll ist.
  • Wenn ein Dateideskriptor zeilengepuffert ist, wartet die Pufferung, bis ein Zeilenumbruchzeichen angezeigt wird. Daten werden also gepuffert und gepuffert, bis ein \ n angezeigt wird, und dann werden alle gepufferten Daten zu diesem Zeitpunkt gelöscht. In der Realität gibt es normalerweise eine maximale Größe für den Puffer (genau wie im vollständig gepufferten Fall). Die Regel lautet also eher "Puffer, bis ein Zeilenumbruchzeichen angezeigt wird oder 4096 Datenbytes gefunden werden, je nachdem, was zuerst eintritt".

Und GNU libc (glibc) verwendet die folgenden Regeln zum Puffern:

Stream               Type          Behavior
stdin                input         line-buffered
stdout (TTY)         output        line-buffered
stdout (not a TTY)   output        fully-buffered
stderr               output        unbuffered

Also, wenn die Verwendung -tvon Docker Dokument , wird es eine pseudo-tty zuweisen, dann stdoutwird line-buffered, so dass docker run --name=myapp -it myappimagedie Ausgabe einzeiligen sehen konnte.

Und wenn nur verwendet -d, wurde kein tty zugewiesen, dann stdoutist fully-bufferedeine Zeile App startedsicher nicht in der Lage, den Puffer zu leeren.

Dann verwenden Sie -dtzumake stdout line buffered oder fügen Sie -uPython hinzu, flush the bufferum das Problem zu beheben.

atline
quelle
6

Sie können die Protokolle auf freistehende Bild sehen , wenn Sie ändern printzu 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"]
Das Schwein
quelle
1
nett. Tipp: Verwenden Sie Python 3.
Adhg
Frage ist in Python 2 (Anweisung ohne Klammer drucken), daher verwende ich hier 2. Obwohl es genau das gleiche Verhalten auf Python3.6 ist, danke für einen Tipp;)
The Hog
6

Da ich diese Antwort noch nicht gesehen habe:

Sie können stdout auch nach dem Drucken leeren:

import time

if __name__ == '__main__':
    while True:
        print('cleaner is up', flush=True)
        time.sleep(5)
tycl
quelle
1
Das hat perfekt für mich funktioniert, dumm, dass das da sein muss, aber jetzt funktioniert es großartig.
Jamescampbell
5

Versuchen Sie, diese beiden Umgebungsvariablen zu Ihrer Lösung PYTHONUNBUFFERED=1und hinzuzufügenPYTHONIOENCODING=UTF-8

Lukasz Dynowski
quelle
3

Versuchen Sie als schnelle Lösung Folgendes:

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

Dies funktioniert bei mir, wenn ich auf dieselben Probleme stoße. Aber um ehrlich zu sein, ich weiß nicht, warum dieser Fehler auftritt.

Vitaly Isaev
quelle
Danke für den Tipp! Es wurde versucht, alle Ausdrucke durch Ihre Version zu ersetzen. Leider hat dies bei mir nicht funktioniert. Es kann immer noch keine Ausgabe über Docker-Protokolle erfolgen (ein Wechsel zwischen sys.stderr / sys.stdout hat kein sichtbares Ergebnis). Ist das ein Docker-Bug?
jpdus
Siehe meine Antwort , der Grund ist: stderr war ungepuffert, so dass Sie es mit Ihrer Lösung beheben können.
atline
1

Ich musste PYTHONUNBUFFERED=1in meiner Datei docker-compose.yml verwenden, um die Ausgabe von django runserver zu sehen.

Adam Radestock
quelle
0

Normalerweise leiten wir es in eine bestimmte Datei um (indem wir ein Volume vom Host bereitstellen und in diese Datei schreiben).

Das Hinzufügen eines tty mit -t ist ebenfalls in Ordnung. Sie müssen es in Docker-Protokollen abholen.

Bei Verwendung großer Protokollausgaben hatte ich keine Probleme mit der Speicherung aller Puffer, ohne sie in das Docker-Protokoll aufzunehmen.

Edward Aung
quelle
-1

Wenn Sie nicht verwenden docker-composeund dockerstattdessen nur normal sind , können Sie dies zu Ihrer hinzufügen Dockerfile, die eine Flaschen-App hostet

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

CMD [ "flask", "run" ]
G Wayne
quelle