Dockerコンテナ内の複数のログを/var/log/messagesに転送する方法


Dockerのログ転送

はじめに

Dockerでは logging Driverを使用することで、コンテナ内のプロセス(PID1)のログを転送することが出来ます。今回は特にsyslogによる転送がテーマです

1コンテナ1プロセスがDocker公式の推奨ですが、アプリやDBだけではなく、監視やメールなど、コンテナに役割をもたせ複数のプロセスを起動するケースも往々にして存在します。

そんな時、複数のプロセスがバラバラのログを吐くことになりますが、これをまとめてホストOSの/var/log/messagesに転送したいというときに使えるテクニックです。

割りと力技ですので、よりよいアイデアがあれば教えていただけると助かります。

どう実現するのか

Dockerのlogging driver はコンテナ内プロセスPID(1)の標準出力を転送しています。(/proc/1/fd/1

ですので、コンテナ内でtail -F [ログ名]...[ログ名] > /proc/1/fd/1 &プロセスを立ち上げてやることで、複数のログをPID(1)のプロセスの標準出力に飛ばしてやります。

実際のソース

イメージですがこんな感じなります。

Dockerfile
FROM apache
ENTRYPOINT ["sh","-c","/start_apache.sh"]
start_apache.sh
tail -F aaa.log bbb.log ccc.log 2 > /dev/null 1 > /proc/1/fd/1 &

exec /usr/sbin/apachectl -DFOREGROUND -k start
docker_run_コマンド
docker run -d --log-driver=syslog --log-opt image_name

ログローテートへの対応もできる!

コンテナ内のログが肥大化してしまうためログ自体を外出するのが普通です。しかし訳あって出来ない場合は(Dockerコンテナのログをローテートする - Qiita)で紹介したテクニックでローテートすることが出来ます。

この時ログがローテートされると、tail が途切れてしまうと思われますが、賢いtail に -F をつけると、同じログ名であればローテート後も監視を続けてくれる動きをします。

オプション 説明
-F --follow=name --retry と等価である。
-f, --follow ファイルの内容が増え続ける時、追加されたデータを出力する; -f,--follow と --follow=descriptor は等価である。
--retry ファイルがアクセスできない、あるいはアクセスできなくなろうとしていたとしても、ファイルのオープンを繰り返す; --follow=name で名前で追跡している場合に有用である。