web-dev-qa-db-ja.com

Dockerアプリケーションにstdoutへの書き込みを行わせる

12ファクタアドバイザリ に準拠してサードパーティアプリケーションをデプロイしています。ポイントの1つは、アプリケーションログをstdout/stderrに出力する必要があることを示しています。その後、クラスタリングソフトウェアが収集できます。

ただし、アプリケーションはファイルまたはsyslogにのみ書き込むことができます。代わりにこれらのログを印刷するにはどうすればよいですか?

53
kolypto

素晴らしいレシピが 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

簡単に言うと、アプリはファイルへの書き込みを続行できますが、その結果、行はstdoutstderrに行きます。

118
kolypto

別の質問 親が終了したときに子プロセスを強制終了する で、これを整理するのに役立つ応答を得ました。

このようにして、ファイルにログを記録し、継続的に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
16
kolypto

Dockerコンテナのバックグラウンドプロセスの場合。 execを使用して/ bin/bashに接続しました。

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

これにより、出力がpid 1のstdoutに送信されます。

15
Pieter

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;'
6
Muayyad Alsadi