EC2 起動時に logrotate と nginx が競合してログが空になる問題
EC2 起動時に logrotate と nginx が競合してログが空になる問題
現象
CloudWatch Logs のログ配信チェックで、nginx の access.log が数日間 0 bytes のままだった。実際にはアクセスがあるのにログが記録されていない状態。
調査
lsof で nginx のファイルディスクリプタを確認すると、access.log ではなくローテート済みの access.log.1 を掴んでいた。
$ sudo lsof -p $(pgrep -o nginx) | grep access
nginx 937 root 3w REG 259,1 4284007 319103 /var/log/nginx/access.log.1access.log は 0 bytes、access.log.1 は数 MB で今も書き込みが続いていた。
原因
syslog を確認すると、EC2 インスタンスの起動シーケンスで logrotate と nginx がほぼ同時に起動していた。
13:37:09 logrotate.service 開始
13:37:09 nginx.service 開始
13:37:10 logrotate.service 完了(postrotate で nginx rotate 実行)
13:37:11 nginx.service 起動完了logrotate の postrotate スクリプト(invoke-rc.d nginx rotate)が nginx 起動途中に実行されたため、シグナルが効かず nginx は旧ファイルのファイルディスクリプタを掴んだまま起動した。
この環境では AMI からの起動時にリブートしない設定で、ASG がインスタンスを立ち上げるたびに発生する。通常の daily logrotate(毎日 0:00)では nginx は既に稼働中なので問題は起きない。
対処
手動で nginx にログファイルを開き直させると解消する。
sudo nginx -s reopen
# または
sudo invoke-rc.d nginx rotate恒久対策(案)
- AMI 作成前にログファイルをクリアする
- 起動スクリプト(cloud-init 等)で nginx 起動後に
nginx -s reopenを遅延実行する - logrotate の nginx 設定で起動直後のローテートを回避する仕組みを入れる
この投稿は投稿者によって CC BY 4.0 の下でライセンスされています。