systemd-journald のログと rsyslog のログが重複していることを疑問に思ったことはありますか?Linux(以降CentOS7を前提とします)で syslog サーバを構築するには rsyslog だけではなく jorunald の仕組みも理解しなければなりません。
Contents
journald と rsyslog の違い
journald と rsyslog の違いで一番分かりやすいのがログの保存方法です。
journald | rsyslog | |
ログの保存形式 | バイナリ | テキスト |
デフォルトのログ保存場所 | /run/log/journal もしくは /var/run/log/journal | /var/log/messages など |
デフォルトのログ保存期間 | 再起動で消える | logrotate.conf 次第 |
これだけ見ると「journald、必要?」となってしまいますが、少なくともCentOS7においては必要です。なぜならCentOS7のログは基本的に journald が管理しているからです。
syslog を使いたい場合は、syslogd が journald からログを読み出すよう設定する必要があるのですが、rsyslog では設定せずに journald から読み出せます。
そのため、OSインストール直後の時点で /run/log/journal/ 配下のジャーナルファイル と /var/log/ 配下のシスログファイルの両方があります。
例えば BIND のログはデフォルトだと /var/log/messages に出力され、postfix のログは /var/log/maillog に出力されます。これらのログは rsyslog が停止していると書き込まれなくなります。
一方、プロキシサーバの squid のログは /var/log/squid/access.log に出力され、rsyslog が停止していても書き込まれます。
squid のようにアプリケーションが独自にログを出力するタイプと、BIND や postfix のように syslog を利用してログを出力するタイプが存在することを理解しましょう(Windows でもイベントビューアーに出力するアプリと独自にログを取るアプリがありますよね)。
そもそも、実は syslog というのは postfix の前身である sendomail の一部として開発されたという経緯があります。postfix が syslog を利用するのはある意味当たり前のことなのです。
journald のログを不揮発にする方法
journald のログが再起動によってクリアされないようにするには、以下の2つの方法の内どちらかを実行します。
- /etc/systemd/journald.conf でジャーナルファイルの保存先を制御する設定項目「Storage=persistent」を設定
- /var/log/journald ディレクトリを作成
ポイントは1番に出てきた「Storage」オプションで、値によって以下のような挙動となります。
volatile | メモリ上(/run/log/journal 以下)でジャーナルを保存する。したがって,再起動でジャーナルは失われる。 |
persistent | ディスク上(/var/log/journal以下)にログを保存する。ディレクトリがなければ作成する。 |
auto | /var/log/journal ディレクトリがなければ voltaile,ディレクトリがあれば persistent の挙動をする。デフォルト値。 |
none | ジャーナルを保存しない。 |
現状ジャーナルログをメモリ以外に保存することはあまりないかと思います。
他ホストから syslog を受け取る場合
ネットワーク機器などの他ホストから syslog でログを受け取る場合は、journald を介しません。この場合は journald のログデータベースと rsyslog のログファイルに差異が生まれます。
シスログサーバの構築
他ホストから syslog を受け取るということはいわゆるシスログサーバということになりますが、構築は簡単です。/etc/rsyslog.conf で以下の行のコメントアウトを外し、最低限のセキュリティ対策としてアクセス許可に関する行を追加します。
# UDPを使用する場合
$ModLoad imudp # TCPでログメッセージを受信するためのモジュールを組み込む
$UDPServerRun 514 # サービスポート番号の指定
# TCPを使用する場合
$ModLoad imtcp # TCPでログメッセージを受信するためのモジュールを組み込む
$InputTCPServerRun 514 # サービスポート番号の指定。UDP と若干書式が違うが同じ意味
# UDPを許可する場合
$AllowedSender UDP, IPアドレス or ホスト名 or ドメイン名
# TCPを許可する場合
$AllowedSender TCP, IPアドレス or ホスト名 or ドメイン名
# IPアドレスにはネットワークアドレスを指定することも可能です
# ホスト名をFQDNで指定する場合、名前解決が出来なかった際はAllowedSenderの対象から除外されます
環境に詳しくない場合は UDP と TCP の両方コメントアウトを外しておいた方がいいでしょう。
syslogd の当初の実装(BSD syslogd)では UDP しか使用できず、ログの信頼性が保証されなかった為 TCP が後に利用できるようになりましたが、送信側の機器が未だに UDP でしかログを送れないというパターンはよくあります。
Linux自身(カーネル)のログは journald が管理
上述したように、syslog とは元々 postfix=アプリケーションのログを管理するために開発された技術です。アプリケーションログではなく、カーネルログはどうでしょうか。journald が存在する場合はカーネルログを journald が管理し、syslog へ転送することで journald と rsyslog 両方でのログ管理を可能にしています。
カーネルが出力するログはまずカーネル内部のカーネルログバッファに保存されます。これは、journald や rsyslog が稼働していない状態でもカーネルからのログメッセージを失わないための仕組みです。
カーネルログがログファイルに書き込まれる流れは次のようになります。
- printk()関数によってログメッセージをカーネルバッファに出力。この時各ログメッセージには0~7のログレベル(syslog のシビアリティに対応)が指定される
- journald がカーネルログバッファの内容を取出し、自身のログデータベースに保存
- 同じメッセージを rsyslog に転送。この時ファシリティは kern、シビアリティはログレベルに対応したものになる
2番と3番のログについて、カーネルログが同じタイムスタンプで複数出力されていたとしても、それはあくまで journald と rsyslog が起動してログファイルに書き出した時刻なので注意が必要です。
以上で journald と rsyslog の関係についてのご紹介を終了します。ご参考になると幸いです。