journal ログをきちんと記録・保存する


はじめに

journald が利用されるようになってしばらく経ちました.
普段なんとなく使ってはいても,OSをリブートするとログが消えることを知らず
困ったことがあるという,自分と同じ経験をした人もいるのではないでしょうか.

ここでは,journalログを永続化するために必要な設定や
ログが記録される仕組みについて確認します.

ちなみにsystemdのバージョンによって多少挙動が異なるようです.
Ubuntu18.04.1 (systemd 237) を中心に, CentOS 7.6 (systemd 219) / Ubuntu 16.04.5 (systemd 229)
あたりでも動作確認しています.

journaldとは

journald は systemd 環境におけるログ管理の仕組みです.
全体概要を知るには,少し古いですが中井さんの記事を読むとよいと思います.

rsyslogが並行して稼動している環境も多いため,
普段は /var/log/ 以下に生成されるログファイルを参照し,
journalctl コマンドは利用しない,という人もいるかもしれません.

一方で,journalログは構造化されバイナリ形式で保存されていることもあり,
検索が便利だったりとより細かい制御ができるメリットがあります.

journalログの永続化

ここで注意すべきなのがログの永続化です.
何もせずにログが蓄積されていると思いきや,
ブート時に過去のログが破棄されたり,ディスク容量やログの出力頻度によっては
ログが記録されないことがわかりました.

ここではその内容とその緩和方法を記載します.

揮発性領域への保存

従来は,journalログはデフォルトでは再起動のたびに破棄される tmpfs 領域である
/run/log/journal 以下に記録されていました.
Ubuntu 18.04ではデフォルトで永続化されていますが, Ubuntu 16.04 や CentOS 7
など古い環境を利用している場合もあると思いますので注意が必要です.
実際,Ubuntu 16.04の環境で ブート一覧を表示しても1つしか表示されませんでした.

$ journalctl --list-boots
 0 8f4718670edb44dcb83c9840f31218b3 日 2018-12-09 01:05:30 JST—日 2018-12-09 01:08:37 JST

これを解決するためには,記録先を永続化領域である /var/log/journal へと変更する必要があります.
これを実現するには /var/log/journal ディレクトリを作成することで,自動的に変更されます.

$ mkdir -p /var/log/journal

記録先は /etc/systemd/journal.conf のStorageオプションが決定します.
デフォルトでは auto となっており, /var/log/journal ディレクトリの有無で動作が異なります.
オプションの内容による動作の違いは以下の通りです.詳細は man journald.conf を参照してください.

オプション設定値 効果
volatile /run/log/journal に記録する
persistent /var/log/journal に記録する
auto(default) /var/log/journal が存在すればそちらに,なければ /run/log/journalに記録する
none ログを記録せずに破棄する(syslog等への転送は実施する)

実際,ディレクトリを作成し, systemd-journald を再起動したところ,
journalログは /var/log/journal 以下に記録されるようになりました.

ディスク使用量による制限

journalログの保存先を永続化領域に変更すれば
すべてのログが保存できるかというと,そういうわけではありません.
journaldはディスクの現在の使用量に応じてjournalログがディスクを圧迫しないよう
記録を制限する場合があります.

設定オプションとしては以下があります.

オプション項目 内容
SystemMaxUse ディスク容量のうち,journalログが利用可能な最大値を指定する.デフォルトは10%で上限は4G./var/log/journal への記録時に適用.
SystemKeepFree ディスク容量のうち,journalログが残しておく空き容量を指定する.デフォルトは15%で上限は4G./var/log/journal への記録時に適用.
RunMaxUse SystemMaxUse と同様で /run/log/journalへの記録時に適用.
RunKeepFree SystemKeepFree と同様で /run/log/journalへの記録時に適用.

実際の値は,journald起動時にもログ出力されています.

journalctl -u systemd-journald
Dec 08 14:27:25 ubuntu18 systemd-journald[357]: System journal (/var/log/journal/d24355bb43ff4b038f4b8d0a493625da) is 16.0M, max 1.9G, 1.9G free.

が,適当なファイルを作成して空き容量を1GB以下に減らして試してみたところ,
実際にはログの記録は継続して行われた上に,初期のログも削除されませんでした.
journald も空き容量が不足していることが認識されている様子なので
なぜ記録が止まらなかったのかは不明です.わかる人教えて下さい.

journalctl -u systemd-journald
Dec 09 06:39:22 ubuntu18 systemd-journald[1409]: System journal (/var/log/journal/d24355bb43ff4b038f4b8d0a493625da) is 32.0M, max 32.0M, 0B free.

メッセージ出力レートの制限

journalログに短期間で大量のログを出力しようとすると,
それを抑止し,対象サービスからのログのみ破棄する仕組みがあります.
短期間で大量のログを出力することが想定される場合はレート制限を
緩和するように設定を変更した方がよいでしょう.
オプションは以下の通りです.

オプション項目 内容
RateLimitIntervalSec レート制限を課す単位時間.デフォルトでは30秒.
RateLimitBurst 単位時間あたりに受付ける最大メッセージ数.デフォルトでは1000.

rsyslog への転送

journald の設定で syslog 転送が有効になっており,journald が受け取ったログは
並行して動作する rsyslog に転送されます.

journald の syslog 転送設定は, journald.confForwardToSyslog で設定します.
/etc/systemd/journald.conf のデフォルトの設定では以下の通りです.

#ForwardToSyslog=yes

このため journaldのログに記録されるのと同時に,rsyslog の設定に従ってログが記録されます.
デフォルトでは, /etc/rsyslog.d/50-default.conf などに記録ファイルなどが保存されています.

auth,authpriv.*                 /var/log/auth.log
*.*;auth,authpriv.none          -/var/log/syslog
#cron.*                         /var/log/cron.log
#daemon.*                       -/var/log/daemon.log
kern.*                          -/var/log/kern.log
#lpr.*                          -/var/log/lpr.log
mail.*                          -/var/log/mail.log
#user.*                         -/var/log/user.log

これをリモートのサーバに転送する設定にすれば,ローカルファイルには記録されず,
リモートのログ集約サーバに保存することができます.

参考