概要
dockerを本番運用する際にログの扱いに悩んだので情報をまとめてみました。
環境
- docker v1.12.1
コンテナのログは何処に渡すべきか
主に以下の3通りになると思います。
- コンテナ内に保存
- volume先に指定してに永続保存
- log driverを使って転送
a. コンテナ内に保存
何も設定しないとコンテナに保持されます。
メリット
何も設定しなくていい
デメリット
当然コンテナが破棄された場合はログファイルがなくなります。
b. volume先に指定してに永続保存
volumeを用いてホストに永続的に保存します。
参照が切れないように-v <host_path>:<container_path>
とするか、--volumes-from <container_name>
でデータ用コンテナに保持してください。
メリット
コンテナを破棄したとしてもvolumeでそこを指定すれば継続して利用ができます。
デメリット
オートスケール等でインスタンス自体も頻繁に作成・破棄される場合は別のところに転送して保持する必要があります。
その場合は別途fluentdコンテナなどを用意&そのvolumeをマウントして転送することになると思います。
c. log driverを使って転送
fluentd
、awslogs
、gcplogs
などのdriverを用いて別のところに転送します。
メリット
コンテナを破棄しても大丈夫ですし、オートスケールでインスタンスが破棄されても大丈夫です。
デメリット
fluentd
を例に挙げると、ログの切り分けが大変です。
例えばアクセスログ・行動ログ・課金ログなど、複数のログファイルに分けていた場合、これらのドライバーはログを分けて転送することができません。
なのでこの方針で進める場合はログ自身に判別するためのタグをもたせ、fluentdのout_rewrite_tag_filter
などを使って分ける必要があります。
elasticsearch - Docker logs, stderr - Stack Overflow
docker logsに標準コンソール以外のログを表示するにはどうすればいいか
nginxのように/dev/stdout
、/dev/stderr
へログファイルをリンクすれば良いです。
ln -sf /dev/stdout /var/log/nginx/access.log ln -sf /dev/stderr /var/log/nginx/error.log
rotationはどうすべきか
ログの悩みどころはインスタンスの容量を圧迫する点です。
特に膨大なアクセスが有る場合はきちんとrotateして圧縮or破棄しないと容量が枯渇します。
a. コンテナ内に保存
コンテナが頻繁に破棄されたらなくなるのでそもそも不要です。
b. volume先に指定してに永続保存
のようにlogrotateを使ってrotateする形になると思います。
c. log driverを使って転送
awslogs
やfluend
の場合、そちらに転送されるのでrotateは考えなくて大丈夫です。
syslog
の場合、一般的なLinuxシステムであれば元々ホスト側でlogrotateが動いているので4週間分でrotateされます。
デフォルトのjson-file
の場合、ホスト側に実ファイルとして保存されるのでrotateを考える必要があります。
これをrotateしたい場合、
https://docs.docker.com/compose/compose-file/#/logging
こちらのcomposeの設定のオプションを使って、
logging: driver: "json-file" options: max-size: "10m" max-file: "100"
のように設定することでrotateしてくれるようになります。
ただしこのlogはコンテナを破棄すると消えるので、コンテナの再作成が頻繁であればa
と同じで対応は不要です。
その他
awslogsがDocker for Macで使えない
awslogsを使う場合、AWSのCredentialsが必要ですがDocker for Macだとdocker daemonにその環境変数を渡すことができないので(clientは当然できますが、awslogsはdaemon側で処理するのでdaemon側に必要)ローカルから転送することはできませんでした。
rotationが面倒だからpm2のログをstdoutだけにしたい
pm2のログはデフォルトでは/home/user/.pm2/logs
に保存されます。これはrotateされないので、rotationを面倒だと思う場合は
"error_file" : "/dev/null", "out_file" : "/dev/null",
と設定することでstdoutだけにできます。あとはstdoutがdocker logsの方に流れるのでそれをawslogs
などに転送すればrotationを考えずに済みます。
docker logsの実ファイルってどこ
json-file
の場合、ホスト側に実ファイル(docker logsで参照するファイル)あります。これはコンテナパス(/var/lib/docker/containers/
)の各コンテナのディレクトリにあります。
docker - Where is a log file with logs from a container? - Stack Overflow
まとめ
本番で動かす場合は以下の2通りがベスト・プラクティスかなと考えています。
ログの種類が1つで済む場合
docker log driverでfluentdやマネージドなサービスに転送。
ログの種類が複数ある場合(ファイル自体が複数)
volumeでホスト側にログファイルを保持し、fluentdで各ログファイルをtailして転送。
rotationに関してはlogrotateやログライブラリ側で対応する。