12ファクタアドバイザリ に準拠してサードパーティアプリケーションをデプロイしています。ポイントの1つは、アプリケーションログをstdout/stderrに出力する必要があることを示しています。その後、クラスタリングソフトウェアが収集できます。
ただし、アプリケーションはファイルまたはsyslogにのみ書き込むことができます。代わりにこれらのログを印刷するにはどうすればよいですか?
素晴らしいレシピが 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
に行きます。
別の質問 親が終了したときに子プロセスを強制終了する で、これを整理するのに役立つ応答を得ました。
このようにして、ファイルにログを記録し、継続的に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
Dockerコンテナのバックグラウンドプロセスの場合。 execを使用して/ bin/bashに接続しました。
echo "test log1" >> /proc/1/fd/1
これにより、出力がpid 1のstdoutに送信されます。
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;'