Сделайте запись приложения Docker в stdout

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

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

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

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

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

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

Это отправляет выходные данные в stdout pid 1, который получает docker.

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

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

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

Сценарий бегуна, run.sh, будет выглядеть следующим образом:

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

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

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

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

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

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

для 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;'

В моем случае создание символической ссылки на stdout не сработало, поэтому вместо этого я запускаю следующую команду

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

Мне только что пришлось решить эту проблему с apache2, и я боролся с использованием CustomLog, чтобы попытаться перенаправить на /proc/1/fd/1 но не смог заставить это сработать. В моей реализации apache не работал как pid 1, так что ответ колипто не сработало как есть. Подход Питера казалось убедительным, поэтому я объединил их, и результат работает чудесно:

# 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

Технически это сохраняет apache access.log и error.log собираться stdout и stderr что касается сборщика журналов docker, но было бы здорово, если бы существовал способ разделить их снаружи контейнер, как переключатель для docker logs это показало бы только одно или другое...

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

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

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

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