Niech aplikacja Docker napisze na standardowe wyjście

49

Wdrażam aplikację innej firmy zgodnie z poradnikiem 12-czynnikowym , a jeden z punktów mówi, że dzienniki aplikacji powinny być drukowane na stdout / stderr: wtedy oprogramowanie klastrowe może je zebrać.

Jednak aplikacja może zapisywać tylko do plików lub syslog. Jak zamiast tego wydrukować te dzienniki?

kolypto
źródło
Oni już idą do syslog. Możesz je po prostu odebrać stamtąd!
Michael Hampton
@MichaelHampton, wydaje się w porządku, ale Docker uruchamia jeden proces, który może zapisywać na standardowe wyjście, a to brzmi jak połączenie dwóch z nich?
kolypto
1
Możesz mieć proces demona używający syslog i mieć frontowy proces, który drukuje?
qkrijger
@qkrijger, dobry punkt! Teraz, jeśli ktoś ma z tym doświadczenie ...?
kolypto

Odpowiedzi:

107

Niesamowity przepis znajduje się w pliku dokowanym 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

Po prostu aplikacja może kontynuować zapisywanie do niej jako plik, ale w rezultacie wiersze przejdą do stdout& stderr!

kolypto
źródło
2
To. Jest. Właśnie. Znakomity. I wszechstronny.
spacediver
11
Problem polega na tym, że rzecz, którą prowadzisz, nalega na przejście do tła jako proces inny niż root. Mam to z squid3, a następnie ma problem z uprawnieniami na /dev/stdout.
mikepurvis
4
To nie zawsze działa - na przykład, jeśli aplikacja próbuje wyszukać plik, ta metoda zazwyczaj nie działa.
mixja
Link nie działa ...
Babken Vardanyan,
4
Wszystko jest plikiem do wygrania.
RubberDuck,
16

W innym pytaniu: Zabij proces potomny, gdy rodzic wyjdzie , otrzymałem odpowiedź, która pomogła rozwiązać ten problem.

W ten sposób konfigurujemy aplikację, aby logowała się do pliku i ciągle tail -fgo zapisywała . Na szczęście tailmoże zaakceptować --pid PID: zakończy działanie po zakończeniu określonego procesu. Umieszczamy $$tam: PID bieżącej powłoki.

Ostatnim krokiem jest uruchomienie uruchomionej aplikacji exec, co oznacza, że ​​bieżąca powłoka została całkowicie zastąpiona przez tę aplikację.

Skrypt runner run.shbędzie wyglądał następująco:

#! /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

UWAGA: korzystając z tail -Flisty nazw plików, odczytamy je, nawet jeśli pojawią się później!

Wreszcie minimalistyczny plik Docker:

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

Uwaga: aby obejść bardzo dziwne tail -fzachowanie (które mówi „został zastąpiony plikiem zdalnym. Rezygnacja z tej nazwy”) wypróbowałem inne podejście: wszystkie znane pliki dziennika są tworzone i obcinane przy uruchamianiu: w ten sposób upewniam się, że istnieją i tylko wtedy - ogonić je:

#! /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
kolypto
źródło
Specjalnie dla serwera Apache używam dzienników Piped ( httpd.apache.org/docs/2.4/logs.html#piped ) i wygląda na to, że to działa.
koder php
Rozwiązuje podobne problemy z alpine i wydaje się, że działa dobrze na BusyBox tailbez opcji --pid.
Ryan,
obejście działało dla mnie. bardzo przydatne, dziękuję.
Tamas Kalman
8

Do procesu w tle w kontenerze dokera, np. Połączenia z exec do / bin / bash, mogłem użyć.

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

To wysyła dane wyjściowe do wyjścia standardowego pid 1, który jest podniesieniem jednego dokera.

Pieter
źródło
1
To jest poprawna odpowiedź. Dzienniki powinny zostać wysłane na standardowe wyjście dla PID1, a jeśli twoja aplikacja działa pod innym PID, nie będzie widoczna przez docker logslub kubectl logs. Mam kontener, który planuje zadanie przez crontab, który nie działa jako PID1.
leeman24
6

dla nginx możesz nginx.confwskazać /dev/stderri /dev/stdoutpolubić to

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

i twój Dockerfilewpis powinien być

/usr/sbin/nginx -g 'daemon off;'
Muayyad Alsadi
źródło
Nie działa, gdy proces główny nie działa jakoroot
peedee