Membuat aplikasi Docker menulis ke stdout

Saya menerapkan aplikasi pihak ke-3 sesuai dengan 12 faktor penasehat, dan salah satu poin mengatakan bahwa log aplikasi harus dicetak ke stdout/stderr: kemudian perangkat lunak pengelompokan dapat mengumpulkannya.

Namun, aplikasi hanya dapat menulis ke file atau syslog. Bagaimana cara mencetak log ini?

Resep yang luar biasa diberikan dalam nginx Dockerfile:

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

Cukup, aplikasi dapat terus menulis untuk itu sebagai file, tetapi sebagai hasilnya garis akan pergi ke stdout & stderr!

Untuk proses latar belakang dalam wadah docker, misalnya menghubungkan dengan exec ke /bin/bash yang dapat saya gunakan.

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

Ini mengirimkan output ke stdout pid 1, yang merupakan satu-satunya pengambilan docker.

Dalam pertanyaan lain, Membunuh proses anak ketika orangtua keluar, Saya mendapat tanggapan yang membantu menyelesaikan masalah ini.

Dengan cara ini, kita mengkonfigurasi aplikasi sehingga log ke file, dan terus menerus tail -f itu. Untungnya, tail dapat menerima --pid PID: ini akan keluar ketika proses yang ditentukan keluar. Kami menempatkan $$ ada: PID dari shell saat ini.

Sebagai langkah terakhir, aplikasi yang diluncurkan adalah exec'ed, yang berarti bahwa shell saat ini sepenuhnya diganti dengan aplikasi itu.

Runner script, run.sh, akan terlihat seperti ini:

#! /usr/bin/env bashset -eurm -rf /var/log/my-application.logtail --pid $$ -F /var/log/my-application.log &exec /path/to/my-application --logfile /var/log/my-application.log

Catatan: dengan menggunakan tail -F kami Daftar nama file, dan akan membacanya bahkan jika mereka muncul kemudian!

Akhirnya, Dockerfile minimalis:

FROM ubuntuADD run.sh /root/run.shCMD ['/root/run.sh']

Catatan: untuk workaroung beberapa sangat aneh tail -f perilaku (yang mengatakan "telah diganti dengan file jarak jauh. menyerah pada nama ini") saya mencoba pendekatan lain: semua file log yang diketahui dibuat & terpotong saat start up: dengan cara ini saya memastikan mereka ada, dan baru kemudian -- ekor mereka:

#! /usr/bin/env bashset -euLOGS=/var/log/myapp/( umask 0 && truncate -s0 $LOGS/http.{access,error}.log )tail --pid $$ -n0 -F $LOGS/* &exec /usr/sbin/apache2 -DFOREGROUND

untuk nginx Anda dapat memiliki nginx.conf menunjuk ke /dev/stderr dan /dev/stdout seperti ini

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

dan Anda Dockerfile entri harus

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

Dalam kasus saya membuat tautan simbolis ke stdout tidak berfungsi, jadi saya menjalankan perintah berikut

ln -sf /proc/self/fd/1 /var/log/main.log 

Saya baru saja menyelesaikan masalah ini dengan apache2, dan bergumul dengan menggunakan CustomLog untuk mencoba mengarahkan ulang ke /proc/1/fd/1 tapi tidak bisa mendapatkan yang bekerja. Dalam implementasi saya, apache tidak berjalan sebagai pid 1, jadi jawaban kolypto tidak bekerja seperti apa adanya. Pendekatan Pieter tampak menarik, jadi saya menggabungkan keduanya dan hasilnya bekerja dengan sangat baik:

# Redirect apache log output to docker log collectorRUN ln -sf /proc/1/fd/1 /var/log/apache2/access.log \    && ln -sf /proc/1/fd/2 /var/log/apache2/error.log

Secara teknis ini membuat apache access.log dan error.log pergi ke stdout dan stderr sejauh menyangkut Kolektor log buruh pelabuhan, tetapi akan sangat bagus jika ada cara untuk memisahkan keduanya di luar wadah, seperti saklar untuk docker logs itu hanya akan menunjukkan satu atau yang lain...

Anda dapat memiliki proses daemon menggunakan syslog dan memiliki proses depan yang mencetak?

Mereka sudah pergi ke syslog. Anda bisa mengambilnya dari sana!

@ MichaelHampton, tampaknya baik-baik saja, tetapi Docker menjalankan satu proses yang dapat menulis ke stdout, dan ini terdengar seperti menggabungkan dua di antaranya?

@ qkrijger, poin bagus! Sekarang, jika ada yang memiliki pengalaman dengan itu … ?