こんにちは。サイオステクノロジー OSS サポート担当何敏欽です。
RHEL7/CentOS7 におけるログファイルの表示と管理は rsyslogd デーモンと journald デーモンによって制御されています。デフォルトでは rsyslogd と journald はシステム上で共存しています。
journal ログを不揮発ログに
journald デーモンは、トラブルシューティング用の主要ツールです。デフォルトでは、/run/log/journal にログを保存するように systemd ジャーナルが設定されています。ジャーナルデータベースのログは持続せず、システムを再起動するとなくなります。しかし、この設定は変更可能です。/var/log/journal にジャーナルログを永続的に保存するには以下の 2つ方法があります。
# 方法①:/var/log/journal ディレクトリを作成する # mkdir -p /var/log/journal # 方法②:/etc/systemd/journald.conf に Storage=persistent を設定する # sed -i 's/#Storage=auto/Storage=persistent/' /etc/systemd/journald.conf # 方法①、方法② の後サービスを再起動する # systemctl restart systemd-journald.service
ソースコードからログ出力の仕様を確認
journal ログと messages の両方にシステムログを記録したい場合、上記の設定を行なった後に rsyslog を再起動する必要があります。
# systemctl restart rsyslog.service
systemd と rsyslog のソースコードを確認するとわかりますが、仕様上 rsyslog を再起動しない場合は messages のログ出力が途絶えて、rsyslog を再起動すると messages に再度ログが出力されます。
rsyslog では、imjournal モジュールを使用して journald から情報を受け取ってログを出力しています。方法①、方法② で /var/log/journal に journal ログを保存するようになりますが、rsyslog はまだ以前の保存先を参照しているため、新しいメッセージを取得できません。
rsyslog を再起動すると imjournal モジュールも再起動し、journal の新しい保存先を検索して参照します。journald から情報を取得し始めると、messages に再度ログが出力されるようになります。
systemd-219-19.el7/src/journal/sd-journal.c … 1508 static int add_search_paths(sd_journal *j) { 1509 int r; 1510 const char search_paths[] = ← /run/log/journal と /var/log/journal の保存先を検索する。 1511 "/run/log/journal\0" 1512 "/var/log/journal\0"; 1513 const char *p; 1514 1515 assert(j); 1516 1517 /* We ignore most errors here, since the idea is to only open 1518 * what's actually accessible, and ignore the rest. */ 1519 1520 NULSTR_FOREACH(p, search_paths) { 1521 r = add_root_directory(j, p); 1522 if (r < 0 && r != -ENOENT) { 1523 r = set_put_error(j, r); 1524 if (r < 0) 1525 return r; 1526 } 1527 } 1528 1529 return 0; 1530 } … 1611 _public_ int sd_journal_open(sd_journal **ret, int flags) { 1612 sd_journal *j; 1613 int r; 1614 1615 assert_return(ret, -EINVAL); 1616 assert_return((flags & ~(SD_JOURNAL_LOCAL_ONLY|SD_JOURNAL_RUNTIME_ONLY|SD_JOURNAL_SYSTEM|SD_JOURNAL_CURRENT_USER)) == 0, -EINVAL); 1617 1618 j = journal_new(flags, NULL); 1619 if (!j) 1620 return -ENOMEM; 1621 1622 r = add_search_paths(j); ← sd_journal_open() が保存先を検索処理する。 1623 if (r < 0) 1624 goto fail; 1625 1626 *ret = j; 1627 return 0; 1628 1629 fail: 1630 sd_journal_close(j); 1631 1632 return r; 1633 } …
rsyslog では、起動後 imjournal プラグインを読み込む時のみ、sd_journal_open() が実行されます。
rsyslog-7.4.7-12.el7/plugins/imjournal/imjournal.c 675 /* open journal */ 676 BEGINwillRun 677 CODESTARTwillRun 678 int ret; 679 ret = sd_journal_open(&j, SD_JOURNAL_LOCAL_ONLY); 680 if (ret < 0) { 681 iRet = RS_RET_IO_ERROR; 682 } 683 ENDwillRun
ログを永続的に保存する設定を行なった後、rsyslog を再起動したら、複数日分 (数ヶ月前とか) の古いメッセージがログファイルに再度書き込まれますので、ビックリするかもしれませんが、これも仕様通りの動作です。
現在 journald が保持する過去のメッセージを取得するかどうかは ImjournalIgnorePreviousMessages の設定で決まります。デフォルトでは、ImjournalIgnorePreviousMessages の設定が off であり、現在 journald が保持する過去のメッセージも含めてすべてのメッセー ジを取得する設定になっています。例えば、新しいメッセージのみをインポートしたい場合は ImjournalIgnorePreviousMessages を on に設定すれば、現在 journald が保持する過去のメッセージを無視して、新しいメッセージのみを取得します。
rsyslog を用いて信頼できるログ転送を実現
rsyslog は、reliable (信頼できる) シスログデーモンという意味で、高い信頼性を実現する次世代の syslog です。信頼性のある通信というのは、ログメッセージを確実に転送され、取りこぼしがないことです。
rsyslog は信頼性のあるログ転送を実現できる理由は、主に下記の 2点です。
- TCP でログメッセージを転送できる。
- 転送に失敗したログメッセージは転送先が再び到達可能になるまでローカルに保存される。
上記 2点目ですが、これは転送先が利用できない (ダウンしたなど) 場合にログメッセージが失われないように、転送アクションに対するアクションキュー (ActionQueue) を設定することで、転送先が復旧後に転送に失敗したログメッセージが再送されます。
仮に下記のような構成があるとします。
[転送元(10.1.100.100)] ↓ ↓ ↓ ↓ ↓ ↓ [転送先_1] [転送先_2] (10.1.100.110) (10.1.100.120)
rsyslog で転送先_1(10.1.100.110)、転送先_2(10.1.100.120) へログを転送する場合、以下のように転送先毎に ActionQueue 等の設定を行う必要があります。それぞれの転送は独立して行われるため、1つの転送先がダウンした場合でも他方への転送はブロックされず、転送先が復旧したらログメッセージが転送されるようになります。
転送元と転送先のログ転送設定について、インターネット上にたくさん情報があるため、ここでは記載しません。ActionQueue の設定は /etc/rsyslog.conf ファイルに直接記載するか、または /etc/rsyslog.d/ 配下に ActionQueue の設定内容のファイルを作成します。
# 転送ルール_1 $ ActionQueueType LinkedList #LinkedList インメモリーキューを有効にする。 $ ActionQueueFileName srvrfwd1 #ファイル名の設定、ディスクストレージを定義する。 $ ActionResumeRetryCount -1 #サーバが応答しない場合に接続を再試行する際 rsyslog がメッセージを破棄しないようにする。 $ ActionQueueSaveOnShutdown on #rsyslog がシャットダウンした場合、インメモリデータが保存される *.* @@10.1.100.110:514 #受信されたすべてのメッセージをサーバに転送する。 # 転送ルール_2 $ActionQueueType LinkedList $ActionQueueFileName example_fwd2 $ActionResumeRetryCount -1 $ActionQueueSaveOnShutdown on *.* @@10.1.100.120:514
では、設定通りになるかを確認してみます。
転送先_1 がダウンしたとします。
[root@destination_1]# systemctl stop rsyslog
転送元からメッセージが出力されたとします。
[root@source]# logger "転送先_1がダウンしました。"
転送先_1 がダウンしたから、当然そのログメッセージが転送されません。
[root@destination_1]# tail -f /var/log/messages (出力なし)
転送先_2 にログが出力されたことを確認できます。転送先_1 と転送先_2 はそれぞれの転送は独立して行われており、転送先_1 がダウンしても転送先_2 は影響されず、ログメッセージが転送されます。
[root@destination_2]# tail -f /var/log/messages Jun 8 12:06:39 rhel7 root: 転送先_1がダウンしました。
転送先_1 が復旧したとします
[root@destination_1]# systemctl start rsyslog
転送先_1 に復旧前のログが出力されたことを確認できます。
[root@destination_1]# tail -f /var/log/messages Jun 8 12:06:39 rhel7 root: 転送先_1がダウンしました。
設定通りの動作になっていますね。これこそ、確実な転送ですね。
以上で systemd ジャーナルでログの永続化を有効にする方法、ログ出力の仕様および rsyslog で複数のサーバへの確実な転送方法を説明しました。