Tạo một ứng dụng Docker ghi vào thiết bị xuất chuẩn


49

Tôi đang triển khai ứng dụng của bên thứ 3 tuân thủ tư vấn 12 yếu tố và một trong những điểm cho biết rằng nhật ký ứng dụng nên được in ra thiết bị xuất chuẩn / stderr: sau đó phần mềm phân cụm có thể thu thập nó.

Tuy nhiên, ứng dụng chỉ có thể ghi vào tệp hoặc syslog. Làm thế nào để tôi in các bản ghi thay thế?


Họ đã đi đến syslog. Bạn chỉ có thể chọn chúng từ đó!
Michael Hampton

@MichaelHampton, có vẻ ổn, nhưng Docker chạy một quy trình duy nhất có thể ghi vào thiết bị xuất chuẩn, và điều này nghe có vẻ như kết hợp hai trong số chúng?
kolypto

1
Bạn có thể có một quy trình daemon sử dụng syslog và có một quy trình phía trước in?
qkrijger

@qkrijger, điểm tốt! Bây giờ, nếu có ai có kinh nghiệm với nó ...?
kolypto

Câu trả lời:


107

Một công thức tuyệt vời được đưa ra trong Dockerfile nginx :

# forward request and error logs to docker log collector
RUN ln -sf /dev/stdout /var/log/nginx/access.log \
    && ln -sf /dev/stderr /var/log/nginx/error.log

Đơn giản, ứng dụng có thể tiếp tục ghi vào nó dưới dạng tệp, nhưng kết quả là các dòng sẽ chuyển đến stdout& stderr!


2
Điều này. Là. Chỉ. Xuất sắc. Và đa năng.
spainediver

11
Một điều có vấn đề với điều này là khi thứ bạn đang chạy khăng khăng đòi tự mình làm nền như một quá trình không root. Tôi đang gặp vấn đề này squid3và sau đó nó gặp rắc rối với quyền trên /dev/stdout.
mikepurvis

4
Điều này không phải lúc nào cũng hoạt động - ví dụ nếu ứng dụng cố gắng tìm kiếm tệp, phương pháp này thường sẽ không hoạt động.
mixja

Liên kết ngừng hoạt động ...
Babken Vardanyan

4
Tất cả mọi thứ là một tập tin cho chiến thắng.
RubberDuck

16

Trong một câu hỏi khác, Giết con xử lý khi cha mẹ thoát ra , tôi nhận được phản hồi giúp loại bỏ điều này.

Bằng cách này, chúng tôi định cấu hình ứng dụng để nó đăng nhập vào một tệp và liên tục tail -f. May mắn thay, tailcó thể chấp nhận --pid PID: nó sẽ thoát khi quá trình được chỉ định thoát. Chúng tôi đặt $$ở đó: PID của vỏ hiện tại.

Bước cuối cùng, ứng dụng đã khởi chạy là exec'ed, có nghĩa là trình bao hiện tại được thay thế hoàn toàn bằng ứng dụng đó.

Kịch bản của người chạy run.sh, sẽ giống như thế này:

#! /usr/bin/env bash
set -eu

rm -rf /var/log/my-application.log
tail --pid $$ -F /var/log/my-application.log &

exec /path/to/my-application --logfile /var/log/my-application.log

LƯU Ý: bằng cách sử dụng tail -Fchúng tôi liệt kê tên tệp và nó sẽ đọc chúng ngay cả khi chúng xuất hiện sau!

Cuối cùng, Dockerfile tối giản:

FROM ubuntu
ADD run.sh /root/run.sh
CMD ['/root/run.sh']

Lưu ý: để làm việc với một số tail -fhành vi cực kỳ lạ (có nghĩa là "đã được thay thế bằng một tệp từ xa. Từ bỏ tên này") tôi đã thử một cách tiếp cận khác: tất cả các tệp nhật ký đã biết được tạo và cắt bớt khi khởi động: cách này tôi đảm bảo chúng tồn tại và chỉ sau đó - theo đuôi họ:

#! /usr/bin/env bash
set -eu

LOGS=/var/log/myapp/

( umask 0 && truncate -s0 $LOGS/http.{access,error}.log )
tail --pid $$ -n0 -F $LOGS/* &

exec /usr/sbin/apache2 -DFOREGROUND

Đặc biệt đối với máy chủ Apache tôi đang sử dụng nhật ký Piped ( httpd.apache.org/docs/2.4/logs.html#piped ) và có vẻ như nó hoạt động.
Bộ mã hóa php

Giải quyết các vấn đề tương tự với alpine và dường như hoạt động tốt trên BusyBox tailmà không có tùy chọn --pid.
Ryan

cách giải quyết đã làm việc cho tôi. cực kỳ hữu ích, cảm ơn bạn.
Tamas Kalman

8

Đối với quy trình nền trong bộ chứa docker, ví dụ: kết nối với exec với / bin / bash tôi có thể sử dụng.

echo "test log1" >> /proc/1/fd/1

Điều này sẽ gửi đầu ra tới thiết bị xuất chuẩn của pid 1, đây là phần tiếp nhận của docker.


1
Đây là câu trả lời chính xác. Các nhật ký sẽ được gửi đến thiết bị xuất chuẩn cho PID1 và nếu ứng dụng của bạn đang chạy dưới một PID khác, nó sẽ không được nhìn thấy bởi docker logshoặc kubectl logs. Tôi có một container chứa lịch trình tác vụ thông qua crontab không chạy dưới dạng PID1.
leeman24

6

cho nginx bạn có thể nginx.confchỉ vào /dev/stderr/dev/stdoutthích cái này

user  nginx;
worker_processes  4;
error_log  /dev/stderr;
http {
    access_log  /dev/stdout  main;
...

Dockerfilemục nhập của bạn nên được

/usr/sbin/nginx -g 'daemon off;'

Không hoạt động khi quy trình tổng thể không chạy nhưroot
peedee
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.