Herokuは Twelve-Factor App manifest でログを単純なイベントストリームとして記述します。
ログは、実行中のすべてのプロセスとバッキングサービスの出力ストリームから収集された、時間順に並べられた集約イベントのストリームです。生の形式のログは、通常、1行に1つのイベントが含まれるテキスト形式です(例外からのバックトレースは複数行に及ぶ場合があります)。ログには開始または終了の固定はありませんが、アプリが動作している限り継続的に流れます。
さらに、アプリは単にstdout
にログを書き込み、タスクを「環境」に任せる必要があります。
12要素のアプリは、出力ストリームのルーティングやストレージに関係することはありません。ログファイルへの書き込みや管理を試みるべきではありません。代わりに、実行中の各プロセスは、バッファリングされていないイベントストリームをstdoutに書き込みます。ローカルでの開発中、開発者はこのストリームを端末のフォアグラウンドで表示して、アプリの動作を観察します。
ステージングまたは本番デプロイでは、各プロセスのストリームが実行環境によってキャプチャされ、アプリからの他のすべてのストリームと照合され、1つ以上の最終的な宛先にルーティングされて、表示および長期的なアーカイブが行われます。これらのアーカイブ先は、アプリからは見えず、構成もできません。代わりに、実行環境によって完全に管理されます。この目的のために、オープンソースのログルーター(LogplexやFluentなど)を使用できます。
では、信頼性、効率、使いやすさの観点から、Docker環境でこれを実現するための最良の方法は何でしょうか。次の質問が頭に浮かぶと思います。
docker logs
)?stdout
を直接ファイル(ディスク領域)にリダイレクトできますか?docker run --volume=[]
)?Docker 1.6 導入ロギングドライバー の概念により、ログ出力をより詳細に制御できます。 --log-driver
フラグは、コンテナーで実行されているプロセスからのstdout
&stderr
をどこに送信するかを構成します。 ロギングドライバの設定 も参照してください。
いくつかのドライバーが利用可能です。 json-file
を除くこれらすべては、コンテナログを収集するためのdocker logs
の使用を無効にすることに注意してください。
/var/lib/docker/containers/<containerid>/<containerid>-json.log
でjson形式のstdoutを使用できます--log-opt
も受け入れて、ログメッセージをTCP、UDP、またはUnixドメインソケット経由で指定されたsyslogに送信します。 docker logs
も無効にします*Docker 1.8の新機能
**Docker 1.9の新機能
例えば:
docker run --log-driver=syslog --log-opt syslog-address=tcp://10.0.0.10:1514 ...
これは、ログメッセージをstdout
&stderr
に書き込むソフトウェアのDocker推奨ソリューションです。ただし、一部のソフトウェアはstdout/stderr
にログメッセージを書き込みません。代わりに、ログファイルやsyslogなどに書き込みます。これらの場合、以下の元の回答の詳細の一部が引き続き適用されます。要点をまとめると:
アプリがローカルログファイルに書き込む場合は、ホストからボリュームをマウントします(または データ専用コンテナー を使用してコンテナーに移動し、ログメッセージをその場所に書き込みます)。
アプリがsyslogに書き込む場合、いくつかのオプションがあります。
/dev/log
を使用してコンテナにホストのsyslogソケット(-v /dev/log:/dev/log
)をマウントすることにより、ホストのsyslogに送信します。コンテナー内のログは、ホストOSの場合と同じようにローテーションする必要があることを忘れないでください。
Docker自体のログ機能(dockerログ)に依存しても安全ですか?
docker logs
は、新しいログだけでなく、毎回ストリーム全体を出力するため、適切ではありません。 docker logs --follow
はtail -f
に似た機能を提供しますが、その後は常にdocker CLIコマンドが実行されます。したがって、docker logs
を実行するのは安全ですが、最適ではありません。
Dockerを切り離さずに実行し、その出力をロギングストリームと見なしても安全ですか?
デーモン化せずにsystemdでコンテナーを開始できるため、systemdジャーナル内のすべてのstdoutをキャプチャできます。これは、ホストで管理できます。
Stdoutを直接ファイル(ディスク領域)にリダイレクトできますか?
もちろん、これをdocker run ... > logfile
で行うこともできますが、自動化と管理が不安定で難しくなります。
ファイルを使用する場合、それはDockerイメージまたはバインドされたボリューム内にある必要がありますか(Docker run --volume = [])?
コンテナー内に書き込む場合、ログファイルを管理するためにコンテナー内でlogrotateまたは何かを実行する必要があります。ホストからボリュームをマウントし、ホストのログローテーションデーモンを使用してボリュームを制御することをお勧めします。
ログローテーションは必要ですか?
もちろん、アプリがログを書き込む場合は、ネイティブOS環境と同じようにログをローテーションする必要があります。ただし、ログファイルの場所は予測できないため、コンテナー内に書き込む場合は困難です。ホストでローテーションする場合、ログファイルは、たとえばデバイスマッパーをストレージドライバー/var/lib/docker/devicemapper/mnt/<containerid>/rootfs/...
として使用します。 logrotateがそのパスの下にあるログを見つけるには、醜いラッパーが必要になります。
Stdoutを直接logshipper(およびどのlogshipper)にリダイレクトしても安全ですか?
Syslogを使用し、ログコレクターにsyslogを処理させることをお勧めします。
名前付きパイプ(別名FIFO)はオプションですか?
名前付きパイプは、パイプの読み取り側が終了するとライター(コンテナー)が壊れたパイプになるため、理想的ではありません。そのイベントがアプリで処理された場合でも、再度リーダーが存在するまでブロックされます。さらに、docker logs
を回避します。
これも参照してください dockerを使用したfluentdへの投稿 。
実行中のコンテナーからログを収集し、必要に応じてルーティングするJeff Lindsayのツール logspout を参照してください。
最後に、コンテナからのstdoutが/var/lib/docker/containers/<containerid>/<containerid>-json.log
のホスト上のファイルにログを記録することに注意してください。