Python uygulaması, docker'da ayrılmış olarak çalışırken hiçbir şey yazdırmıyor


160

Benim dockerfile başlatılan bir Python (2.7) uygulaması var:

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

main.py başlatıldığında bazı dizeleri yazdırır ve daha sonra bir döngüye girer:

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

-İt bayrağıyla konteyneri başlattığım sürece, her şey beklendiği gibi çalışır:

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

Ve daha sonra günlükler üzerinden aynı çıktıyı görebiliyorum:

$ docker logs myapp
> App started

-D bayrağıyla aynı kapsayıcıyı çalıştırmayı denerseniz, kapsayıcı normal başlıyor gibi görünüyor, ancak herhangi bir çıktı göremiyorum:

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

Ancak konteyner hala çalışıyor gibi görünüyor;

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

Ekle ayrıca hiçbir şey görüntülemez:

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

Yanlış giden bir fikir var mı? Arka planda çalıştırıldığında "yazdırma" farklı davranıyor mu?

Docker sürümü:

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

Yanıtlar:


266

Sonunda GitHub'daki @ahmetalpbalkan sayesinde Docker'da arka plana aktarılırken Python çıktısını görmek için bir çözüm buldum . Daha fazla referans için burada kendim cevaplamak:

İle arabelleksiz çıktı kullanma

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

onun yerine

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

problemi çözer; çıktıyı (hem stderr hem de stdout)

docker logs myapp

Şimdi!


2
-u benim için çalışıyor gibi görünüyor, ama gerçekte ne yaptığını açıklayan bir belge var mı?
Küçük inek

7
Diğer yanıtların önerdiği gibi ENV PYTHONUNBUFFERED=0, -uişaretin çalışmadığı durumlarda ortam değişkenini ayarlamayı deneyebilirsiniz .
Farshid T

1
Bu da benim sorunumdu. Daha ayrıntılı bir açıklama için bkz. Stackoverflow.com/a/24183941/562883
Jonathan Stray


1
PYTHONUNBUFFERED = 0 ayarı yardımcı olmazken, python3'te bir rüya gibi çalışır.
Lech Migdal

71

Benim durumumda, Python ile çalışmak -uhiçbir şeyi değiştirmedi. Bununla birlikte, püf noktası PYTHONUNBUFFERED=0çevre değişkeni olarak ayarlamaktı :

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

6
Benim durumumda, ekleme -e PYTHONUNBUFFERED=0yardımcı olur.
David Ng

1
Teşekkür ederim! Saatlerce kafamı duvardan vuruyordum ve günlükleri bile çalıştıramadım -u. Çözümünüz benim için Django ile Mac için
Docker'da düzeltildi

2
Ben bu daha iyi bir çözüm olduğunu düşünüyorum, biz çıktıları görmek için docker görüntü yeniden oluşturmak zorunda değilsiniz
FF0605 29:18

2
Bu çok teşekkürler. PYTHONUNBUFFERED
A Star

Liman işçisi oluşturma arayüzü için çalıştı. Asla tahmin
etmezdim

24

Benim için bu bir özellik, bir hata değil. Yalancı TTY olmadan stdout yapılacak bir şey yoktur. Böylece basit bir çözüm, çalışan konteynırınız için bir sahte TTY tahsis etmektir:

$ docker run -t ...

Bu soruya bir cevap vermez. Bir yazardan eleştiri veya açıklama istemek için gönderilerinin altına bir yorum bırakın.
Başkan James K. Polk

@JamesKPolk, şimdi daha mı iyi?
Peter Senna

docker, stdout ve stderr için tahsis edilecek bir sahte tty gerektirmez
Matt

3
tty: truebeste
derinleştirme

15

Davranışın ayrıntı nedenini açıklayan bu makaleye bakın :

Arabelleğe alma için genellikle üç mod vardır:

  • Bir dosya tanıtıcısının arabelleği kaldırılırsa, hiçbir arabellekleme olmaz ve verileri okuyan veya yazan işlev çağrıları hemen gerçekleşir (ve engellenir).
  • Bir dosya tanımlayıcı tamamen arabelleğe alınırsa, sabit boyutlu bir tampon kullanılır ve okuma veya yazma aramaları arabellekten basitçe okunur veya yazılır. Tampon, dolana kadar temizlenmez.
  • Bir dosya tanıtıcısı satır arabelleğe alınırsa, arabelleğe alma yeni satır karakteri görene kadar bekler. Böylece veriler bir \ n görülene kadar arabelleğe alınır ve arabelleğe alınır ve daha sonra arabelleğe alınan tüm veriler o anda temizlenir. Gerçekte tamponda tipik olarak maksimum bir boyut vardır (tam olarak arabelleğe alınmış durumda olduğu gibi), bu nedenle kural aslında "yeni satır karakteri görünene kadar tampon veya hangisi önce olursa olsun 4096 bayt veriyle karşılaşılıncaya" benzer.

Ve GNU libc (glibc) arabelleğe alma için aşağıdaki kuralları kullanır:

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

Yani, eğer kullanıldığında -t, docker belgesinden , bir sahte-tty tahsis eder, sonra stdoutolur line-buffered, böylece docker run --name=myapp -it myappimagetek satırlık çıktıyı görebilir.

Sadece kullanım eğer, -dhiçbir tty tahsis edilmiş, daha sonra, stdoutbir fully-bufferedtek satır, App startedtampon temizlemek mutlaka mümkün değildir.

Ardından, kullanım -dtiçin make stdout line bufferedveya eklenti -upython için flush the bufferbunu düzeltmek için bir yoldur.



6

Eğer değiştirirseniz müstakil resmin üzerine günlükleri görebilirsiniz printiçin 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"]

1
Güzel. ipucu: Python 3'ü kullanın.
adhg

soru Python 2'de (parantez olmadan baskı ifadesi) bu yüzden burada 2 kullanıyorum. Python3.6'da tam olarak aynı davranış olmasına rağmen, bir ipucu için teşekkürler;)
Domuz

6

Bu cevabı henüz görmediğim için:

Stdout'u yazdırdıktan sonra da temizleyebilirsiniz:

import time

if __name__ == '__main__':
    while True:
        print('cleaner is up', flush=True)
        time.sleep(5)

1
bu benim için mükemmel çalıştı, bunun orada olması gerektiğini aptalca, ama şimdi harika çalışıyor.
jamescampbell

5

Bu iki ortam değişkenini çözümünüze eklemeye çalışın PYTHONUNBUFFERED=1vePYTHONIOENCODING=UTF-8


3

Hızlı bir düzeltme olarak şunu deneyin:

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

Aynı sorunlarla karşılaştığımda bu benim için işe yarıyor. Ama dürüst olmak gerekirse, bu hatanın neden oluştuğunu bilmiyorum.


Bahşiş için teşekkürler! Tüm baskıları sürümünüzle değiştirmeyi denedim, maalesef benim için işe yaramadı, yine de docker günlükleri aracılığıyla herhangi bir çıktı alamıyor (sys.stderr / sys.stdout arasında geçişin görünür bir sonucu yok). Bu bir liman işçisi hatası mı?
jpdus

Cevabımı gör , nedeni: stderr arabelleğe alınmadı, böylece çözümünüzle düzeltmeyi sağlayabilirsiniz.
atline

1

PYTHONUNBUFFERED=1Django runserver çıktı görmek için docker-compose.yml dosyamda kullanmak zorunda kaldı .


0

Genellikle, dosyayı belirli bir dosyaya yönlendiririz (ana bilgisayardan bir birim bağlayıp bu dosyaya yazarak).

-T kullanarak tty eklemek de iyidir. Docker günlüklerinde almanız gerekiyor.

Büyük günlük çıktılarını kullanarak, dockers günlüğüne koymadan tüm arabellek depolama ile ilgili herhangi bir sorun yoktu.


-1

Kullanmıyorsanız docker-composeve dockerbunun yerine normalseniz , bunu Dockerfilebir şişe uygulaması barındıran bilgisayarınıza ekleyebilirsiniz.

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

CMD [ "flask", "run" ]
Sitemizi kullandığınızda şunları okuyup anladığınızı kabul etmiş olursunuz: Çerez Politikası ve Gizlilik Politikası.
Licensed under cc by-sa 3.0 with attribution required.