Ứng dụng Python không in bất cứ thứ gì khi chạy tách rời trong docker


160

Tôi có một ứng dụng Python (2.7) được khởi động trong dockerfile của tôi:

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

main.txt in một số chuỗi khi nó được bắt đầu và đi vào một vòng lặp sau đó:

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

Miễn là tôi khởi động container với cờ -it, mọi thứ sẽ hoạt động như mong đợi:

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

Và tôi có thể thấy đầu ra tương tự thông qua nhật ký sau:

$ docker logs myapp
> App started

Nếu tôi cố chạy cùng một container với cờ -d, container dường như bắt đầu bình thường, nhưng tôi không thể thấy bất kỳ đầu ra nào:

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

Nhưng container dường như vẫn chạy;

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

Đính kèm cũng không hiển thị bất cứ điều gì:

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

Bất cứ ý tưởng whats đi sai? "In" có hoạt động khác khi chạy trong nền không?

Phiên bản 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

Câu trả lời:


265

Cuối cùng tôi đã tìm thấy một giải pháp để xem đầu ra Python khi chạy daemonized trong Docker, nhờ @ahmetalpbalkan tại GitHub . Trả lời nó ở đây để tham khảo thêm:

Sử dụng đầu ra không có bộ đệm với

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

thay vì

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

giải quyết vấn đề; bạn có thể thấy đầu ra (cả, stderr và stdout) thông qua

docker logs myapp

hiện nay!


2
-u dường như làm việc cho tôi, nhưng có một số tài liệu ở đâu đó với một mô tả về những gì nó thực sự làm?
Little geek

7
Theo đề xuất của các câu trả lời khác, bạn có thể thử đặt biến môi trường ENV PYTHONUNBUFFERED=0trong trường hợp -ucờ không hoạt động.
Farshid T

1
Đây cũng là vấn đề của tôi. Để được giải thích chi tiết hơn, xem stackoverflow.com/a/24183941/562883
Jonathan Stray


1
Hoạt động như một giấc mơ trên python3, trong khi đặt PYTHONUNBUFFERED = 0 không giúp được gì.
Lech Migdal

71

Trong trường hợp của tôi, chạy Python -umà không thay đổi gì cả. Tuy nhiên, mẹo đã làm là đặt PYTHONUNBUFFERED=0biến môi trường:

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

6
Trong trường hợp của tôi, thêm -e PYTHONUNBUFFERED=0trợ giúp.
David Ng

1
Cảm ơn bạn! Tôi đã đập đầu vào tường trong nhiều giờ và không thể có được nhật ký để làm việc ngay cả với -u. Giải pháp của bạn đã sửa nó cho tôi trên Docker cho Mac với Django
someguy123

2
Tôi nghĩ rằng đây là một giải pháp tốt hơn, rằng chúng ta không phải xây dựng lại hình ảnh
docker

2
Đây là lời cảm ơn tuyệt vời. Điều đáng nói là đây chỉ cần là một nhân vật không trống để hoạt động theo các tài liệu PYTHONUNBUFFERED
Một ngôi sao

Làm việc cho giao diện docker-compose. Sẽ không bao giờ đoán được
deepelement 30/12/18

24

Đối với tôi nó là một tính năng, không phải là một lỗi. Không có TTY giả, không có gì để xuất hiện. Vì vậy, một giải pháp đơn giản là phân bổ giả TTY cho thùng chứa đang chạy của bạn với:

$ docker run -t ...

Điều này không cung cấp một câu trả lời cho câu hỏi. Để phê bình hoặc yêu cầu làm rõ từ một tác giả, hãy để lại nhận xét bên dưới bài đăng của họ.
Tổng thống James K. Polk

@JamesKPolk, bây giờ có tốt hơn không?
Peter Senna

Docker không yêu cầu một giả giả được phân bổ cho thiết bị xuất chuẩn và thiết bị xuất chuẩn
Matt

3
tty: truetrong vùng đất sáng tác
đào sâu

15

Xem bài viết này giải thích chi tiết lý do cho hành vi:

Thông thường có ba chế độ để đệm:

  • Nếu một bộ mô tả tập tin không có bộ đệm thì không có bộ đệm nào xảy ra và các lệnh gọi chức năng đọc hoặc ghi dữ liệu xảy ra ngay lập tức (và sẽ chặn).
  • Nếu một bộ mô tả tệp được đệm đầy đủ thì bộ đệm có kích thước cố định được sử dụng và đọc hoặc viết các cuộc gọi chỉ đơn giản là đọc hoặc ghi từ bộ đệm. Bộ đệm không bị xóa cho đến khi nó đầy lên.
  • Nếu một bộ mô tả tập tin được đệm dòng thì bộ đệm sẽ đợi cho đến khi nó thấy một ký tự dòng mới. Vì vậy, dữ liệu sẽ đệm và đệm cho đến khi nhìn thấy một \ n, và sau đó tất cả dữ liệu được đệm được xóa tại thời điểm đó. Trong thực tế, thường có kích thước tối đa trên bộ đệm (giống như trong trường hợp được đệm hoàn toàn), do đó, quy tắc thực sự giống như bộ đệm cho đến khi nhìn thấy một ký tự dòng mới hoặc gặp phải 4096 byte dữ liệu, tùy theo trường hợp nào xảy ra đầu tiên.

Và GNU libc (glibc) sử dụng các quy tắc sau để đệm:

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

Vì vậy, nếu sử dụng -t, từ tài liệu docker , nó sẽ phân bổ một giả, sau đó stdouttrở thành line-buffered, do đó docker run --name=myapp -it myappimagecó thể thấy đầu ra một dòng.

Và, nếu chỉ sử dụng -d, không có tty được phân bổ, sau đó, stdoutfully-buffered, một dòng App startedchắc chắn không thể tuôn bộ đệm.

Sau đó, sử dụng -dtđể make stdout line bufferedhoặc thêm -uvào python flush the bufferlà cách để sửa nó.



6

Bạn có thể thấy nhật ký trên hình ảnh tách ra nếu bạn thay đổi printthành logging.

chính:

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
đẹp. mẹo: sử dụng Python 3.
adhg

câu hỏi là trong Python 2 (câu lệnh in không có dấu ngoặc đơn) do đó đang sử dụng 2 ở đây. Mặc dù đó chính xác là hành vi tương tự trên Python3.6, vì vậy xin cảm ơn vì một mẹo;)
Hog

6

Vì tôi chưa thấy câu trả lời này:

Bạn cũng có thể xóa tiêu chuẩn sau khi in ra:

import time

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

1
Điều này làm việc hoàn hảo cho tôi, thật ngu ngốc khi điều này cần phải có, nhưng bây giờ hoạt động rất tốt.
jamescampbell

5

Cố gắng thêm hai biến môi trường này vào giải pháp của bạn PYTHONUNBUFFERED=1PYTHONIOENCODING=UTF-8


3

Để khắc phục nhanh, hãy thử điều này:

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

Điều này làm việc cho tôi khi tôi gặp phải những vấn đề tương tự. Nhưng, thành thật mà nói, tôi không biết tại sao lỗi này xảy ra.


Cảm ơn vì tiền hỗ trợ! Đã thử thay thế tất cả các bản in bằng phiên bản của bạn, tiếc là nó không hoạt động với tôi, vẫn không thể nhận được bất kỳ đầu ra nào thông qua nhật ký docker (thay đổi giữa sys.stderr / sys.stdout không có kết quả hiển thị). Đây có phải là một lỗi docker?
jpdus

Xem câu trả lời của tôi , lý do là: stderr không có bộ đệm, vì vậy bạn có thể sửa nó bằng giải pháp của mình.
trực tuyến

1

Tôi đã phải sử dụng PYTHONUNBUFFERED=1trong tập tin docker-compose.yml của mình để xem đầu ra từ máy chủ django.


0

Thông thường, chúng tôi chuyển hướng nó đến một tệp cụ thể (bằng cách gắn một ổ đĩa từ máy chủ và ghi nó vào tệp đó).

Thêm một tty bằng cách sử dụng -t cũng tốt. Bạn cần phải chọn nó trong nhật ký docker.

Sử dụng các đầu ra nhật ký lớn, tôi không gặp vấn đề gì với việc lưu trữ bộ đệm mà không đưa nó vào nhật ký docker.


-1

Nếu bạn không sử dụng docker-composevà chỉ bình thường dockerthay vào đó, bạn có thể thêm Dockerfileứng dụng này vào ứng dụng đang lưu trữ ứng dụng bình

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

CMD [ "flask", "run" ]
Khi sử dụng trang web của chúng tôi, bạn xác nhận rằng bạn đã đọc và hiểu Chính sách cookieChính sách bảo mật của chúng tôi.
Licensed under cc by-sa 3.0 with attribution required.