Заставьте приложение Docker написать в stdout


49

Я развертываю стороннее приложение в соответствии с рекомендациями по 12 факторам , и один из моментов говорит о том, что журналы приложений должны быть напечатаны в stdout / stderr: тогда программное обеспечение для кластеризации может их собрать.

Тем не менее, приложение может записывать только файлы или системный журнал. Как мне распечатать эти журналы вместо этого?


Они уже собираются в системный журнал. Вы можете просто забрать их оттуда!
Майкл Хэмптон

@MichaelHampton, кажется, все в порядке, но Docker запускает один процесс, который может записывать в стандартный вывод, и это звучит как объединение двух из них?
Колыпто

1
У вас может быть демон-процесс, использующий syslog, и фронт-процесс, который печатает?
qkrijger

@qkrijger, хорошая мысль! Теперь, если у кого-то есть опыт с этим ...?
Колыпто

Ответы:


107

Удивительный рецепт дается в 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

Просто приложение может продолжать запись в него в виде файла, но в результате строки будут идти в stdout& stderr!


2
Этот. Является. Только что. Brilliant. И универсальный.
космонавт

11
Единственная проблема, которая связана с этим, заключается в том, что запускаемая вами вещь настаивает на переходе в фоновый режим как процесс без полномочий root. У меня есть это с squid3, а затем возникают проблемы с разрешениями на /dev/stdout.
Микепурвис

4
Это не всегда работает - например, если приложение пытается найти файл, этот метод обычно не будет работать.
mixja

Ссылка не работает ...
Бабкен Варданян

4
Все это файл для победы.
RubberDuck

16

В другом вопросе « Убить дочерний процесс при выходе из родительского процесса» я получил ответ, который помог разобраться в этом.

Таким образом, мы настраиваем приложение таким образом, чтобы оно регистрировалось в файл и непрерывно tail -fего. К счастью, tailможет принять --pid PID: он выйдет при выходе из указанного процесса. Мы помещаем $$туда: PID текущей оболочки.

В качестве последнего шага запущенное приложение execредактируется, что означает, что текущая оболочка полностью заменена этим приложением.

Скрипт бегуна run.sh, будет выглядеть так:

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

ПРИМЕЧАНИЕ: используя tail -Fсписок имен файлов, он будет читать их, даже если они появятся позже!

Наконец, минималистичный Dockerfile:

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

Примечание: для работы с очень странным tail -fповедением (которое говорит «был заменен удаленным файлом. Отказывается от этого имени»), я попробовал другой подход: все известные файлы журналов создаются и усекаются при запуске: таким образом, я гарантирую, что они существуют и только потом - хвост им:

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

Специально для сервера Apache я использую журналы Piped ( httpd.apache.org/docs/2.4/logs.html#piped ) и, похоже, работает.
php-кодер

Решает аналогичные проблемы с alpine и, похоже, отлично работает на BusyBox tailбез опции --pid.
Райан

Обходной путь работал для меня. чрезвычайно полезно, спасибо.
Тамас Кальман

8

Для фонового процесса в Docker-контейнере, например, соединение с exec в / bin / bash, которое я смог использовать.

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

Это отправляет вывод на стандартный вывод pid 1, который является одним из подключаемых докеров.


1
Это правильный ответ. Журналы должны быть отправлены на стандартный вывод для PID1, и если ваше приложение работает под другим PID, оно не будет просматриваться docker logsили kubectl logs. У меня есть контейнер, который планирует задачу через crontab, который не работает как PID1.
leeman24

6

для Nginx вы можете nginx.confуказывать /dev/stderrи /dev/stdoutнравится это

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

и ваша Dockerfileзапись должна быть

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

Не работает, когда основной процесс не выполняется какroot
peedee
Используя наш сайт, вы подтверждаете, что прочитали и поняли нашу Политику в отношении файлов cookie и Политику конфиденциальности.
Licensed under cc by-sa 3.0 with attribution required.