はじめに
「無人運用しているEdge PCが、突然応答しなくなる」
「再起動すると復旧するが、ログを見ても原因が分からない」
「フリーズ直前のCPU・メモリ・I/Oの状態を確認したい」
この記事では、こうした問題を調べるために、別のLinux端末へログと状態情報を残す外部監視の設計を紹介します。
医療向けのエッジ/クラウド環境で、電源断からの復旧や長期間の安定運用に取り組んでいます。本記事は、その取り組みを紹介する連載の第12回です。
前回は、systemd timerによる定期メンテナンスと自己復旧を扱いました。しかし、OS全体がフリーズすると、監視処理も復旧処理も一緒に止まります。
そこで、監視対象とは別のUbuntu端末を用意し、次の情報を外側へ残す構成にしました。
| 監視経路 | 残したい情報 |
|---|---|
| Ping | 最後にネットワーク応答を確認できた時刻 |
| Heartbeat | 監視用プロセスが動作していたこと |
| Telemetry | フリーズ前のCPU・メモリ・I/Oなど |
| rsyslog | 外部へ転送できたシステムログ |
| netconsole | 外部へ送信できたカーネルメッセージ |
完全なフリーズでも必ず原因を記録できる、という仕組みではありません。最後に観測できた状態を増やし、原因を切り分けるための構成です。
1. なぜフリーズ後のローカルログだけでは調べにくいのか
通常は、Edge PC自身でCPU使用率、メモリ、アプリケーション、コンテナ、システムログなどを記録します。
しかし、OS全体が停止すると、これらの記録も止まります。
Edge PCがフリーズ
↓
監視用プロセスが停止
↓
ログ出力・転送が停止
↓
自己復旧処理も停止
さらに、出力したログがディスクへ書き込まれる前に停止すると、最後の記録が失われる可能性があります。
つまり、再起動後に確認できるログは、必ずしも「停止する直前までのすべての情報」ではありません。
そのため、正常に動いている間から、状態とログを別端末へ送っておきます。
2. 監視対象とは別のUbuntu端末へ証拠を残す
構成は次のようにしました。
Edge PC
┌──────────────────┐
│ Application │
│ Container │
│ Ubuntu / Kernel │
└──────────────────┘
│ ▲
Heartbeat │ │ Ping
Telemetry │ │
rsyslog / TCP │ │
netconsole / UDP │ │
▼ │
┌──────────────────┐
│ 外部監視端末 │
│ │
│ 応答確認 │
│ データ受信 │
│ 受信時刻の記録 │
│ ログ保存 │
└──────────────────┘
大切なのは、Edge PCが停止したときにも、監視端末が動き続けることです。
別のPCを用意しても、同じ電源やスイッチの障害で両方が停止すれば、観測できなくなります。調査したい障害に応じて、電源やネットワーク経路の分離も検討します。
また、rsyslogとnetconsoleはソフトウェア上の経路が異なりますが、同じNICやスイッチを使う場合、物理的には共通の障害点を持ちます。
3. PingとHeartbeatで「どこまで動いているか」を切り分ける
Pingは1秒周期でネットワーク応答を見る
外部監視端末から、Edge PCへ1秒周期でPingを送ります。
これによって、「最後に応答した確認」と「最初に応答しなかった確認」を記録できます。
ただし、Pingが返らない理由には、フリーズ以外もあります。
- 電源断
- NICやLANケーブルの異常
- スイッチの障害
- Firewallによる遮断
- 一時的なパケット損失
Pingの失敗だけでは、OSのフリーズと断定できません。
また、1秒周期で監視しても、停止時刻を正確に1秒単位で確定できるわけではありません。判定には応答タイムアウトや監視処理の遅延も影響します。
Heartbeatは5秒周期でプロセスの動作を見る
Edge PC側の監視用プロセスから、5秒周期でHeartbeatを送ります。
Pingがネットワーク応答を見るのに対して、Heartbeatでは、送信処理が実行できていることを確認します。
| Ping | Heartbeat | 次に確認すること |
|---|---|---|
| 応答あり | 受信あり | 監視対象アプリの処理結果や状態 |
| 応答あり | 未受信が継続 | 送信プロセス、送信経路、受信処理 |
| 応答なし | 受信あり | ICMPの遮断、経路差、一時的な損失 |
| 応答なし | 未受信が継続 | 電源、ネットワーク、OS、監視端末側の異常 |
ここでいうHeartbeatは、監視用プロセスの生存確認です。別プロセスで送っているだけなら、業務アプリケーションが正常に動いていることまでは保証しません。
業務処理の停止も検知したい場合は、アプリ側の最終処理時刻や処理件数などを追加します。
Heartbeatは1回届かなかっただけで障害扱いにせず、複数周期の未受信が続いた場合に判定する設計にします。
4. フリーズ直前の状態は、軽量なTelemetryで残す
Heartbeatだけでは、停止前に何が起きていたか分かりません。
そこで、5秒周期で軽量な状態情報も送ります。
| 情報 | 主な取得元の例 | 確認したいこと |
|---|---|---|
| CPU時間 | /proc/stat |
CPU使用状況の変化 |
| メモリ | /proc/meminfo |
利用可能メモリの減少 |
| Load Average | /proc/loadavg |
実行待ちなどの増加 |
| Disk I/O | /proc/diskstats |
読み書きの変化 |
| Network I/O | /proc/net/dev |
通信量やエラーの変化 |
| Uptime | /proc/uptime |
稼働時間 |
| Boot ID | /proc/sys/kernel/random/boot_id |
再起動前後の区別 |
CPU時間やI/O統計には累積値が含まれます。使用率や毎秒の通信量を見るには、前回との差分と経過時間から計算します。
再起動で値がリセットされるため、Boot IDが変わった場合は差分計算もリセットします。
また、Load Averageの上昇を、そのままCPU使用率の上昇と解釈しないことも大切です。I/O待ちなど、ほかの情報と合わせて確認します。
データには時刻と識別情報を付ける
Telemetryには、状態値に加えて、次の情報を持たせます。
{
"device_id": "edge-01",
"boot_id": "<boot-id>",
"seq": 12345,
"sampled_at": "2026-10-03T03:30:10Z",
"uptime_sec": 86400.5,
"metrics": {
"mem_available_kib": 2048000
}
}
これはデータ形式の例です。
受信側では、さらに受信時刻を付けます。
-
sampled_at:Edge PC側で採取した時刻 -
received_at:監視端末へ到着した時刻 -
seq:送信データの連番 -
boot_id:どの起動期間のデータか
送信側と受信側の時計にはずれがあり、送信キューで遅れる場合もあります。受信時刻だけを見て、その瞬間までEdge PCが動いていたと判断しないようにします。
未受信の経過時間を判定する処理では、時計補正の影響を受けにくい単調増加時計を使い、調査用の記録にはUTCの時刻を残す方針にします。
5. 監視負荷を抑えるため、取得周期を分ける
フリーズ調査では、監視処理によって調査対象の動作を変えすぎないことも重要です。
短周期で大量のコマンドを実行すると、プロセス生成、CPUの起床、ディスクアクセスなどが増えます。特にアイドル時や省電力状態の問題では、再現条件に影響する可能性があります。
今回の構成では、次の周期に分けました。
| 周期 | 取得する情報 |
|---|---|
| 5秒 | Heartbeat、CPU、メモリ、Load、Disk I/O、Network I/O |
| 60秒 | C-state関連統計、PSI、/proc/vmstat、IRQ・softirq、GPU Runtime PM、コンテナ状態 |
| 10分 | NIC詳細統計、Filesystem、時刻同期、Failed Service、SMARTの一部 |
| 1時間 | SMART詳細情報 |
この周期は、今回の調査に合わせた値です。端末性能や再現条件に応じて調整します。
PSIは、CPU・メモリ・I/Oの資源不足によって、タスクが処理を進められなかった時間を観測する仕組みです。CPU使用率だけでは見えない待ちを調べる材料になります。取得方法はLinux KernelのPSIドキュメントに記載されています。
C-state関連の取得項目は、CPU・ドライバ・カーネル構成によって異なります。また、取得できた統計だけで、停止した瞬間のC-stateや原因を確定できるわけではありません。
取得処理にはタイムアウトを設け、前回の処理が終わらないまま次の処理を重ねないようにします。取得失敗は正常値の0へ置き換えず、失敗として記録します。
6. rsyslogで、ローカルにしかないログを外部へ転送する
通常のシステムログは、rsyslogで外部監視端末へ転送します。
Edge PCのログ
↓
rsyslog
↓ TCP
外部監視端末
↓
ファイルへ保存
TCP転送の最小構成例
以下は、管理用LAN内で動作を確認するための設定例です。
Edge PC : 192.168.10.10
外部監視端末 : 192.168.10.20
受信ポート : TCP 514
Edge PC側の/etc/rsyslog.d/60-edge-forward.confに、転送設定を追加します。
action(
type="omfwd"
target="192.168.10.20"
port="514"
protocol="tcp"
queue.type="linkedList"
)
転送先が応答しない場合の影響を抑えるため、転送用のキューを設けます。設定の考え方はrsyslogの転送ドキュメントを参照してください。
監視端末側では、例えば/etc/rsyslog.d/20-edge-receiver.confに次を追加します。
module(load="imtcp")
ruleset(name="edge_remote") {
action(
type="omfile"
file="/var/log/edge-remote.log"
)
}
input(
type="imtcp"
address="192.168.10.20"
port="514"
ruleset="edge_remote"
)
imtcpが既存設定で読み込まれている場合は、重複して追加しません。受信設定の詳細はimtcpの公式ドキュメントを参照してください。
両端末で構文を確認し、エラーがなければ設定を反映します。
sudo rsyslogd -N1
sudo systemctl restart rsyslog
Edge PC側でテストメッセージを出します。
logger -t edge-monitor-test "remote syslog test"
監視端末側で、同じメッセージが保存されたことを確認します。
sudo tail -n 20 /var/log/edge-remote.log
この例は、rsyslogへ入力されたログを転送するものです。アプリ独自のファイルやコンテナの標準出力まで、自動ですべて転送されるわけではありません。必要なログごとに、rsyslogへの入力経路を確認します。
また、TCPを使っても、最後のログの保存は保証されません。送信前のログやメモリ上のキューは、完全なフリーズや電源断で失われる可能性があります。TCP転送の限界はomfwdの公式ドキュメントでも説明されています。
7. netconsoleでカーネルメッセージの経路を追加する
rsyslogはユーザー空間で動くため、カーネルの異常時に最後のメッセージを転送できない場合があります。
そこで、カーネルのprintkメッセージをUDPで送るnetconsoleも追加します。
Kernel / printk
↓
netconsole
↓ UDP
外部監視端末
rsyslogが扱うログにはカーネルログも含まれ得ます。netconsoleを追加する理由は、ユーザー空間の転送処理とは異なる経路を持つためです。
設定では、送信元IP・NIC、宛先IP・ポート・MACアドレスを確認します。同一LAN内なら監視端末のMACアドレスを使い、ブロードキャスト送信を避けます。形式はLinux Kernelのnetconsoleドキュメントに記載されています。
ただし、次の限界があります。
- UDPなので、配送や順序を保証しない
- NICや送信処理が動けない状態では届かない
- 送信対象はコンソールへ出力されるメッセージで、ログレベル設定の影響を受ける
また、netconsoleは定期的な生存通知ではありません。メッセージが来ないこと自体を、停止の証拠にはできません。
受信確認には、識別できるテストメッセージを使います。調査中にログレベルを変更した場合は、その変更も実験条件として記録します。
8. 障害後は「最後に観測できたこと」を時系列で確認する
例えば、監視端末に次の記録が残ったとします。
12:30:10 Heartbeat受信
12:30:10 Telemetry受信
12:30:11 Ping応答あり
12:30:12 netconsoleでカーネル警告を受信
12:30:13 Ping応答なし
12:30:15 Heartbeatの予定受信なし
これは読み方を説明するための例です。
障害後は、次の順番で確認します。
- 監視端末自身が正常に動いていたか
- Pingの最後の成功と、失敗が継続し始めた時刻
- HeartbeatとTelemetryの最終採取時刻・受信時刻
- 最後に受信したrsyslogとnetconsoleの内容
- 障害前のCPU・メモリ・I/O・PSIなどの推移
- 復旧後のBoot IDと、再起動前後のログ
カーネル警告があれば重要な手掛かりですが、その警告が停止原因とは限りません。
また、経路ごとのバッファリングや配送遅延があるため、受信順序をそのまま実行順序や因果関係として扱わないようにします。
rsyslogやnetconsoleは、イベントがなければ正常でも静かです。「ログが途切れた時刻」と「その転送経路が停止した時刻」も区別する必要があります。
9. kdumpとWatchdogは、外部監視とは役割が異なる
監視端末のkdumpでは、Edge PCのダンプは取れない
kdumpは、クラッシュした端末自身に事前設定し、ダンプ取得用カーネルへ移行できた場合にメモリ情報を残す仕組みです。Linux Kernelのkdumpドキュメントで概要を確認できます。
今回、監視端末側に設定するkdumpは、監視端末自身のクラッシュ調査用です。
Edge PCのクラッシュダンプが必要なら、Edge PC側にも設定が必要です。完全なハングや電源断で、必ずダンプを取得できるわけではありません。
NMI Watchdogの無効化には、失う情報もある
今回のC-state調査では、監視対象側でNMI Watchdogを無効にする方針を取りました。監視による割り込みを、追加の実験変数として持ち込みたくなかったためです。
ただし、無効化すると、その検知機構によるhard lockupの情報を失います。これはフリーズ対策として一律に推奨する設定ではありません。
また、カーネルのlockup detectorと、ハードウェアWatchdogによる自動再起動は別の仕組みです。検知機構の違いはLinux KernelのWatchdogドキュメントを参照してください。
復旧を優先して再起動させるのか、停止状態を保持して証拠を集めるのか。調査フェーズごとに目的を決め、設定を一つずつ変更します。
10. 導入時は「サービスが動いている」ではなく「証拠が保存された」を確認する
導入時には、最低5分間動かして、短周期の監視が機能することを確認します。
| 確認項目 | 合格の判断 |
|---|---|
| Ping | 成功・失敗と確認時刻が記録される |
| Heartbeat | 連番が進み、未受信を判定できる |
| 5秒Telemetry | 値・Boot ID・採取時刻・受信時刻が残る |
| 60秒Telemetry | 複数回取得され、失敗も識別できる |
| rsyslog | テストメッセージが外部ファイルに残る |
| netconsole | テストメッセージが外部で確認できる |
10分・1時間周期の処理は、5分間では十分に確認できません。導入試験で個別に実行するか、必要な時間まで監視を継続します。
さらに、次も確認します。
- 監視プロセスを止めると、未受信として検知できる
- 通信断と復旧後の記録が残る
- 再起動後も受信処理が起動する
- 保存容量、保持期間、ローテーションが設定されている
- 監視追加前後でCPU負荷やI/Oが大きく変わっていない
監視端末のjournalを永続化しても、Telemetryや別ファイルへ書いたログの保存設定まで自動で整うわけではありません。保存先ごとに確認します。
通信の許可は端末と用途を限定する
受信ポートは管理用インターフェースへ限定し、FirewallではEdge PCから必要な通信だけを許可します。Pingも監視端末からの通信に限定します。
前述のrsyslog設定例は平文TCPです。ネットワークの信頼境界に応じてTLSを使い、netconsoleは分離した管理用LANなどで扱います。
医療向け環境では、ログに患者情報や認証情報を含めない設計も必要です。フリーズ調査に必要な端末状態を中心に収集します。
まとめ
Edge PCが完全にフリーズすると、自己監視も自己復旧も止まります。
そこで、正常に動いている間から、別端末へ状態とログを残しておきます。
- Pingで、ネットワーク応答を確認する
- Heartbeatで、送信プロセスの動作を確認する
- Telemetryで、停止前の状態変化を残す
- rsyslogで、通常のログを外部へ転送する
- netconsoleで、カーネルメッセージの送信経路を追加する
そのうえで、監視負荷を抑え、採取時刻と受信時刻を分け、実際に記録が保存されることまで確認します。
フリーズ調査では、「止まったこと」に加えて、「最後に何を観測できたか」を残すことが、原因を絞る手掛かりになります。
次回は、Edge PCからクラウドへの通信が途切れたときに、クラウド側で未受信を検知し、一時的な切断と対応が必要な障害を区別して通知する設計を紹介します。