Назад | Перейти на главную страницу

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

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

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

Удивительный рецепт дан в nginx Dockerfile:

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

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

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

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

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

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

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

Сценарий бегуна, 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

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