運用者のための logrotate 入門:つまずきポイントと対処法
本記事は実案件でのナレッジを一般化したものです。環境固有の情報は含みません。
この記事でわかること
- logrotate の基本ディレクティブ(
daily/weekly/rotate/maxage/compress/delaycompress/dateext/nodateext) -
nginx/php-fpm/rsyslogなどの実用スニペット - 安全な検証手順(dry-run / journalctl / stateファイル)
- systemd タイマーで 毎日09:00(JST)=00:00(UTC) に揺れ少なく回す設定
1. 基本の考え方
- 設定は
/etc/logrotate.conf(全体)+/etc/logrotate.d/*(サービスごと) -
実行タイミングを決めるのは timer/cron。デフォは systemd:
logrotate.timer - 回す条件は「頻度(daily/weekly 等)」「サイズ(size X)」などを起動時に評価する(常時監視ではない)
よく使うディレクティブ早見表
| 設定 | 意味 | Tips |
|---|---|---|
daily / weekly
|
評価頻度 | サーバ停止時間帯があるなら Persistent の扱いに注意 |
rotate N |
N世代保持 |
maxage と厳しい方が優先
|
maxage D |
D日超えは削除 | 期限切れは rotate 未満でも消える |
compress |
gzip圧縮 | すぐ .gz に |
delaycompress |
圧縮を1回遅らせる | 当日できた *-YYYYMMDD は未圧縮で残り、翌回 .gz に |
dateext / nodateext
|
-YYYYMMDD or .1 方式 |
日付で追跡するなら dateext
|
postrotate ... endscript |
回転直後の処理 | nginx/php-fpm へ USR1 等 |
2. スニペット例
2.1 nginx(日次・10世代・即圧縮+翌日まで未圧縮を残す運用)
/var/log/nginx/*.log {
create 0640 nginx root
daily
rotate 10
missingok
notifempty
compress
delaycompress
sharedscripts
postrotate
/bin/kill -USR1 $(cat /run/nginx.pid 2>/dev/null) 2>/dev/null || true
endscript
}
- 挙動:当日できた *-YYYYMMDD は未圧縮のまま → 翌日のローテで .gz 化
- 即 .gz にしたいなら delaycompress を外す
2.2 php-fpm(週次・4世代・日付サフィックス)
/var/log/php-fpm/*log {
weekly
rotate 4
dateext
missingok
notifempty
sharedscripts
compress # 必要に応じて
# delaycompress # 使う場合は compress とセットで
postrotate
/bin/kill -SIGUSR1 $(cat /run/php-fpm/php-fpm.pid 2>/dev/null) 2>/dev/null || true
endscript
}
2.3 rsyslog(週次・4世代)
/var/log/cron
/var/log/maillog
/var/log/messages
/var/log/secure
/var/log/spooler
{
weekly
rotate 4
dateext
missingok
notifempty
sharedscripts
postrotate
/usr/bin/systemctl kill -s HUP rsyslog.service >/dev/null 2>&1 || true
endscript
}
3. 実行時刻を 09:00(JST)=00:00(UTC) に揃える(systemd)
# 現設定の確認
systemctl cat logrotate.timer
systemctl list-timers | grep logrotate
# 09:00(JST) きっちり寄せ(±5分、補填なし)
sudo systemctl edit logrotate.timer
# ↓エディタで追記
[Timer]
OnCalendar=
OnCalendar=00:00
AccuracySec=5min
RandomizedDelaySec=0
Persistent=false
# 反映
sudo systemctl daemon-reload
sudo systemctl restart logrotate.timer
systemctl show logrotate.timer -p NextElapseUSecRealtime -p LastTriggerUSecRealtime -p Persistent
- Persistent=false:深夜停止中でも起動直後の補填実行をしない(毎朝9:00だけ回る)
- Persistent=true:スケジュール時刻に止まっていたら起動後すぐ1回だけ補填(用途によって使い分け)
4. 安全な検証(dry-run / journalctl / state)
4.1 破壊なしのドライラン
sudo logrotate -d -v /etc/logrotate.conf | sed -n '1,200p'
4.2 実行ログの確認(UTCで“今日 00:00–00:10”)
start=$(date -u -d 'today 00:00' +'%Y-%m-%d %H:%M:%S')
end=$(date -u -d 'today 00:10' +'%Y-%m-%d %H:%M:%S')
journalctl --utc -o short-iso-precise -u logrotate.timer --since "$start" --until "$end"
journalctl --utc -o short-iso-precise -u logrotate --since "$start" --until "$end"
4.3 最終回転時刻のソース(stateファイル)
sudo grep -E '/var/log/(nginx|php-fpm|messages|secure|maillog|cron)' /var/lib/logrotate/logrotate.status
5. よくある落とし穴
- compress 無効で delaycompress だけ入れても効果なし(no-op)
- postrotate の PID ファイルパスが違うと再オープンされない
- cron.daily/logrotate と systemd を併用して二重実行になっている
- EFS/NFS への退避は未マウント時に失敗
まとめ
- 実行時刻は timer が決める/回す条件は起動時に評価
- compress/delaycompress の意味を理解して設計する
- 検証は dry-run → journalctl → state の三点セットで安全に
間違っている箇所、更新した情報があった際は別途更新しようと思います。