DockerのCMDでログファイルをtailする

Dockerは標準出力に出力したログなどはlogsコマンドで確認することができますが、Dockerで動かすアプリケーションがファイルにログを出力している場合はlogsコマンドで確認することができません。

このような場合は、CMDでtail -fすることが多いと思います。

CMD tail -f /var/log/cron.log

しかしこれだとlogsコマンドに何も流れてきません。
そこでログファイルの中身をexecコマンドで確認してみると正しくログが出力されています。
なにが起こっているのでしょうか。

Dockerのファイルシステム

原因はDockerが採用しているファイルシステムにあります。

DockerはUnion File Systemというファイルシステムを採用していて、このファイルシステムcopy-on-writeという方法で動作しています。
Union File Systemcopy-on-writeについてはこの記事がわかりやすいです。

namu-r21.hatenablog.com

直接的な原因は、CMDでtailしているログファイルはDocker imageに保存されているファイルであり、コピーされてログが書き込まれるようになったファイルではないためです。

対策

CMDでtailする前にcopy-on-writeを発生させればいいだけです。

やり方は色々あると思いますが、1つの例としてはこのようにCMDを書けば意図した通りに動きます。

CMD : >> /var/log/cron.log && tail -f /var/log/cron.log

なお、このようにCMDで&&を使って複数コマンドを実行するときは、DockerのPID1とゾンビプロセスのことを考慮する必要が出てくるので注意しましょう。

参考

dockerfile - Output of `tail -f` at the end of a docker CMD is not showing - Stack Overflow