投稿

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.1

access.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 の下でライセンスされています。

トレンドのタグ