【Linux】ログローテーションの重要性 ~logrotate入門~

#サーバ
written by パイン

前置き

どうも。夏バテおじさんことパインです。
これからの時期、脱水症状や熱中症のほか、食中毒などにも気を使わなければならない嫌な季節になりますね。。。

今日はLinuxのログローテーションの基本について解説していきます。

ログローテーションとは

ログローテーションとは読んで字のごとく、ログファイルをローテーションします。

日々出力され溜まっていくログファイルは気づかないうちに膨大な容量になり、システムのディスクを圧迫します。そしてログファイルというのはシステム動作の証跡でもあるため、各社・各業界の規定にのっとって保管する必要もあります。そのためログローテーションを設定、実施する究極的な目的は下記の2点になります。

1. システム監査上、証跡となるログデータを必要な期間残す
2. システム保守上、容量が圧迫されないように必要以上のログファイルを残さない

ログローテーションの設定が甘いと、肥大したログファイルにディスク容量が圧迫されてシステムが止まったり、逆にログデータが削除されすぎてISMSとか情報セキュリティ委員会など対監査面で問題になります。特に対監査面は業界によってはそもそも法律で定められてたりするので注意が必要です。

普段、みなさまWindowsPCをご利用かと思いますが、イベントログのメンテナンスを行ったことはありますか?ないですよね?もちろんないよね?
たぶん大体の人はないと思いますが、これはログローテーションが実行されているためです。Windowsのイベントログは容量が一定を超過しないように古いエントリを削除する仕組みになっています。

Windowsのイベントログ然り、Linuxでもログローテーションを行います。
これには各種スクリプトで自作するほか、基本機能としてlogrotateを利用します。

ログファイルのローテーション方式について

ローテーション方式にはいくつか種類があります。
1. ファイルの中身を別ファイルに書き出して、ログファイルをクリアする(copytruncate方式)
2. ファイルを別名に変更して新しいログファイルを生成する(create方式/movecreate方式)
3. 古いエントリを削除する
4. 複数のログファイルを順番に使用する

logrotateで利用できるローテーションは「1.」および「2.」になります。
では「1.copytruncate方式」と「2.create方式/movecreate方式」の違いはなんでしょう?

ざっくりとした違いはiノード番号と呼ばれる内部IDを維持するかどうかです。

「1.copytruncate方式」の場合はログファイルを別名ファイルにコピーし、対象のログファイルを空にします。ファイルのオブジェクトが変更されないため、iノード番号が維持されるという特徴があります。MySQLなどのDB系のプロダクトはログファイルをオープンにしたまま(iノード番号を参照したまま)にしていることが多く、iノード番号が変更される「2.」のローテーション方式だと、ローテーションができなかったり、ログが書き込めなくなったり、mv先のファイルにログが書き込まれ続ける☆エキセントリック☆な挙動をしたりします。
「1.copytruncate方式」のほうが無難…と思われるかもしれませんが、コピー後にログファイルを空にするという処理が発生する都合上、処理中に書き込まれたメッセージがログから消えるということが起きます。

「2.create方式/movecreate方式」の場合はログファイルを別名ファイルにムーブし、対象のログファイルを新しく生成します。ファイルのオブジェクトが変更されるため、先に触れたとおりiノード番号が維持されません。「1.copytruncate方式」に比べ処理内容が軽量なので(といっても誤差)ログ情報が消失しにくい特徴があります。特にiノード周りの制約がなければ「2.create方式/movecreate方式」の方式でローテーションを行うほうが無難です。ただし新しくオブジェクトを生成するため、パーミッションなどの定義をちゃんとやっておかないとログファイルに書き込みができない…というエラーが発生するので注意が必要です。

まぁログ出力中にコピーされたりムーブされたりしてダイイングメッセージみたいになるのは割と日常茶飯事なんですけどね☆

「3.」は先述のWindowsイベントログなど、「4.」はアプリケーションが内部でローテーションを行っているケースがあります。
今回の記事の本流には関係ないので↓絵↓で解説するにとどめます。

logrotateの設定項目について

logrotateの設定は下記2ファイルで行っていきます。
・/etc/logrotate.conf
・/etc/logrotate.d/*

/etc/logrotate.confのglobal設定に該当するログファイルであれば特に設定しなくてもローテーションしてくれますが、フルスクラッチで開発されたアプリケーションやサードパーティー製品のミドルウェアなどは特殊な処理をはさんだり、そもそもglobalに該当する場所にログファイルを出力しなかったりするため、別途/etc/logrotate.d/配下に定義ファイルを作成してそちらで細かく定義していくことになります。
基本的な設定項目としては下記になります。

1. ローテーション方式
先般述べたcopytruncate方式/create方式を選びます。create方式の場合はパーミッションの設定も併せて定義します。

2. 管理世代数
何世代残し、以降のデータを削除するか設定します。

3. ローテーション頻度
日次、週次、月次など実行頻度を設定します。
ログ出力が多い環境や製品は日次に、そうでない場合は週次や月次で設定することが多いです。
というのもログ出力が多い環境・製品の場合、vimなどのエディタでログファイルを参照するとRAM上にデータが展開された際にvimにメモリが占有され処理速度に悪影響が出たり、最悪の場合はOut of Memoryエラーなどでサーバーがクラッシュします。
ローテーション期間を短くすることで1ファイルあたりの容量を抑えてやる必要が出てくるわけです。

4. ローテーション後のファイル命名規則や圧縮要否
標準だと、ファイル名.1とかでローテーションされますが、例えばYYYYMMDD形式のサフィックスをつけたりできます。
またcompressを有効にすると、gzip形式で圧縮されるためディスク容量を節約できます。

5. その他前後処理や容量上限の設定など
・ログローテーションをする際の前後処理を定義する
・ログファイルの上限容量を定義する
などなど。

設定を見てみる

まずglobalの設定がどうなっているのか見ていきます。
ファイルは/etc/logrotate.confになります。

# see "man logrotate" for details

詳しくはmanを参照しろとおっしゃっております^^;

# rotate log files weekly
weekly

global設定はweekly(週次)の設定になっていますね。
この場合、個別の定義ファイルで明示的に記載しない限り週次でローテーションが実行されることになります。

# keep 4 weeks worth of backlogs
rotate 4

rotateで世代管理を定義します。この場合は4世代管理となります。
週次/4世代なのでだいたい1カ月保管ですね。(7日×4世代=28日分≒1カ月)

# use date as a suffix of the rotated file
dateext

dateextとはファイルの末尾にローテーション実行日のサフィックスを追加する設定です。
デフォルトだと「ファイル名-YYYYMMDD」の形式で追加されます。
ハイフン区切りが気に入らないなど、ファイル名フォーマットを変更したい場合はdateformat設定で変更できます。

dateformat _%Y%m%d
※ ファイル名_YYYYMMDD形式に変更

次を見ます。

# uncomment this if you want your log files compressed
#compress

compressはファイルをgzip形式に圧縮するか指定します。デフォルトだとコメントアウトされていますね。基本的にログファイルはテキスト形式なので圧縮を有効にしておくとディスク容量が節約できてよきです〇

# RPM packages drop log rotation information into this directory
include /etc/logrotate.d

includeで/etc/logrotate.d配下の定義ファイルも読み込む設定になっています。
個別の設定等は/etc/logrotate.d配下において定義していきましょうね。

では個別の設定を見ていきます。
参考までにApacheのログローテーションの設定を見てみましょう。

# view /etc/logrotate.d/httpd
/var/log/httpd/*log {
missingok
notifempty
sharedscripts
delaycompress
postrotate
/bin/systemctl reload httpd.service > /dev/null 2>/dev/null || true
endscript
}

基本的な構文としてローテーション対象のログファイル名を記載し、処理の内容を{}でくくって定義していきます。
Apacheの場合は/var/log/httpd配下の*logに該当するログファイルをローテーションするという設定になっています。
missingokはログファイルが存在していなくてもエラーにしない設定です。

notifemptyはログファイルが空の場合はローテーションをしない設定になります。
空ファイルでローテーションされなかった場合、保管される期間がずれるので注意が必要になります。

sharedscriptsは複数のログファイルにまたがる処理について単一回処理を実行する定義になります。
Apacheの場合、access_logやerror_log、ssl_access_logにssl_request_logなど複数のログファイルが生成されるためこれらを一括で処理するための定義ですね。

delaycompressはログローテーション時にログファイルを圧縮するのですが、compressと違い圧縮処理を1回スキップします。
直近のログファイルを非圧縮データで保持したい場合には有効な定義です。

postrotate~endscriptまではログローテーション実行後の処理になります。今回のケースではhttpdをreloadしていますね。
ローテーション前に実行したい処理がある場合はprerotate~endscriptで定義します。

ざっくりオプションまとめてみた

調べてみると意外とオプション多いんですよね。まぁ使わないオプションも多いので興味があったら是非。

ログファイル名 {
 [ create パーミッション ユーザー名 グループ名 | copytruncate ]
 [ rotate X ]
 [ dateext ]
 [ dateformat ]
 [ nocompress | compress | delaycompress ]
 [ monthly | weekly | daily | hourly | size ファイルサイズ ]
 [ maxsize ファイルサイズ ]
 [ minsize ファイルサイズ ]
 [ sharedscript ]
 [ nocreate ]
 [ missingok | nomissingok ]
 [ ifempty | notifempty ]
 [ noolddir | olddir ディレクトリ ]
 [ prerotate ~ endscript ]
 [ postrotate ~ endscript ]
}

最後に

今回はlogrotateについて解説しました。
ローテーションの設定は間違えるとうまく動かなかったり、最悪DDoSアタックでログファイルが肥大化してシステムが止まる原因にもなるので、これを機に頭の片隅にでも置いといてもらえると嬉しいです。

前回の記事

【Linux】作業中によく使うコマンド 23選 + おまけ