「別々のアプリが似た症状で落ちる」を手がかりに、NFS越しのSonarQube・Nexus・Jenkinsが繰り返しクラッシュする原因を追った話
自宅のProxmox上に構築したKubernetesクラスタで、CI/CD基盤(Jenkins、パッケージミラーのNexus、静的解析のSonarQube)をセルフホストで動かしています。ある時期から、これらの別々のJavaアプリが、それぞれ違う症状で、繰り返し落ちるようになりました。個別に見ると無関係な障害に見えますが、実は同じ根っこを持っていました。この記事は、その調査と、まだ終わっていない対応の記録です。
TL;DR
- JenkinsのダッシュボードがときどきIOExceptionで描画に失敗する、Nexusが500を返す、SonarQubeが31回連続で再起動を繰り返す――一見バラバラな症状が、実は全部「NFS上のファイルへの低頻度な書き込みエラー」という共通パターンだった。
- 決定打になったのは、3つのPostgreSQL/Nexus/Jenkinsが同時に
CrashLoopBackOffになった約12時間の大規模障害。ここで初めて、NFSサーバーの/dev/sdbのext4ジャーナルがabortしていたことが分かった。 - さらに掘ると、Proxmoxホストが外部NASからiSCSIでストレージを借りている構成で、その接続が2026年6月から断続的に瞬断していたことが判明した。誰も気づかないまま3か月近く放置されていた。
- 応急処置として、異常を検知して自動でPodを再起動するwatchdogを導入した。ただし根本原因(NAS側のiSCSI不安定性)の調査は、この記事を書いている時点でもまだ着手できていない。
1. 別々のアプリで、似た症状が繰り返された
最初に気づいたのはJenkinsでした。ダッシュボードのジョブ一覧が、ときどき空になります。ログを見ると、こう出ていました。
java.io.IOException: Bad file descriptor
favorite.jarというプラグインのファイルを読み込む最中のエラーで、projectView.jellyの描画が落ちていました。この時点では「たまたま起きた単発の不具合」だと思って、大きく気にしていませんでした。
しばらくして、今度はNexus(社内向けのパッケージミラー)でnpm-proxyやnexus-dockerが500を返すようになりました。
nexus.mv.db(H2組込DB)読込中に Input/output error
さらにその数日後、JVMヒープが91%まで逼迫した状態からThe database has been closedというエラーでNexusが落ち、H2側でもInput/output error(fsync時)が記録されていました。
決定的だったのは、SonarQubeでした。sonarqube-app-sonarqube-0というPodが、31回連続で再起動を繰り返していたのです。原因はElasticSearchが自分のログファイル(NFS上の/opt/sonarqube/logs/es.log)への書き込みでIOException: Stream Closedを出し、プロセスごとクラッシュしていたことでした。
ここまで来て、ようやく共通点に気づきました。Jenkins・Nexus・SonarQube、どれもNFS(nfs01/nfs02)上にデータやログを置いているJavaアプリで、低頻度のファイルI/Oエラーを起点にプロセス全体が異常終了している、という同じ形をしていました。個別にはrollout restart(新しいJVMがファイルを開き直す)で毎回一時的に直るのですが、根本原因は未解決のまま、時間を置いて再発を繰り返していました。
2. 約12時間の大規模障害で、直接原因が判明した
原因調査が本格化したのは、Jenkins・Nexus・n8n用PostgreSQL・SonarQube用PostgreSQLが同時にInit:CrashLoopBackOffになった障害がきっかけでした。書き込み系の操作が軒並みInput/output errorで失敗し続け、約12時間続きました。
調べると、NFSサーバー役のVM(nfs01、Proxmoxホストnozomi上で稼働)の仮想ディスク/dev/sdbで、SCSI I/Oエラー(Synchronize Cacheの失敗)が発生し、そこからext4ジャーナルがabortしていました。ファイルシステムが破損状態のまま書き込みできなくなっていたのです。
復旧手順自体はシンプルでした。nfs-sync.timer/nfs-state-reaper.timer/nfs-kernel-serverを止め、umountしてからfsck -f -y、再mountしてサービスを再開する、という流れです。fsckの結果はfree blocks/inodes countのズレだけで、ファイル自体の破損は無く済みました。
3. さらに掘ると、3か月放置されていた瞬断ログが出てきた
「なぜNFSのディスクがI/Oエラーを起こしたのか」をさらに追うと、真因はもう1段深いところにありました。nfs01の実体(仮想ディスク)は、ProxmoxホストnozomiがSynology NAS(NAS3)からiSCSI経由で借りているLUNの上にあります。nozomiのdmesgを見ると、次のログが2026年6月から断続的に記録されていました。
connection1:0: ping timeout ... detected conn error (1022)
6/24、6/25、6/26、6/27、7/26、8/21――3か月近くにわたって、iSCSI接続の瞬断が繰り返し起きていたのに、これまで表面化せず放置されていました。今回の12時間障害は、この瞬断の1つが引き金になっていただけで、根本原因はNAS3側のiSCSI接続そのものの不安定性にありました。同じ調査の過程で、これとは別の瞬断(No route to host→Connection refusedが53回リトライして復旧)も見つかっています。
低頻度のI/Oエラーがアプリ側で個別に「直った」ように見えていたのは、根本原因を直したからではなく、たまたまその瞬間に瞬断が起きていなかっただけでした。
4. 応急処置: 異常を検知して自動でPodを再起動するwatchdog
根本原因(NAS3側のiSCSI安定性)にはまだ手を付けられていませんが、同種の障害が起きたときに人手を介さず復旧できるよう、watchdogを実装しました。Nexus向けの実装は、5分おきに動くCronJobで、次の2軸で異常を検知します。
-
/service/rest/v1/status/writableのHTTPステータス - ログに
database has been closedという文字列が出ていないか
異常を検知するとkubectl rollout restart statefulset/nexusを自動実行します。ただし、NFS側の根本原因が直っていない場合に無限リスタートし続けないよう、1日あたりの自動再起動回数に上限を設けています。上限に達したら、自動復旧をあきらめてSlackへエスカレーション通知を送るだけにします。
本日の自動 rollout restart 上限 (N 回) に到達。
NFS 側の根本原因調査が必要、これ以上は自動復旧しません
watchdog自体が誤検知して復旧を妨害した
このwatchdogを導入した直後、今度はwatchdog自身がバグを踏みました。Nexusの起動直後は、chown-data-dirの完走を含めてServiceにEndpointsが登録されるまで最大10分近くかかることがあります。この間、watchdogのHTTPチェックは「接続不可」になり、まだ起動中のPodを「unhealthy」と誤判定して、rollout restartをかけてしまっていました。実際に、NFS障害からの復旧直後、まさにこのタイミングでこの誤検知が発生し、復旧をむしろ妨害する結果になっています。
対策は、PodのcreationTimestampから起動経過秒数を見て、起動猶予(900秒)未満なら判定・アクション自体を完全にスキップするガードを追加することでした。「異常を検知して自動対応する仕組み」自体が、起動直後の正常な状態を異常だと誤認しないようにする、という一段メタな検証が必要だったことになります。
5. まだ終わっていないこと
この記事を書いている時点(障害発生から約1か月後)でも、対応案のチェックリストのうち、一番重要な項目は未着手のままです。
- 【最重要・未着手】NAS3自体のiSCSI接続不安定性の原因調査(NAS側のネットワーク設定・負荷・ファームウェア、あるいはProxmoxホスト側のNIC/スイッチポートを疑っているが、まだ手を付けられていない)
- nfs01/nfs02が同じiSCSI系統に依存する単一障害点になっていないかの整理
- ext4ファイルシステム異常の自動検知→fsck+再mountの自動化(現状は手動対応)
- 影響を受けやすいアプリのデータストアを、NFSからブロックストレージへ移行できないかの検討
一方で、調査の過程で見つかった周辺の問題は個別に対処しました。NFSサーバー自体のルートパーティションが同期処理のログ出力で満杯になっていた問題(同期スクリプトへのログ流量制限、logrotateの上限設定を追加)、片方のNFSサーバーだけfsckが未実施のまま再マウントされ続けていた問題(実施して復旧)、そして「ディスク容量が危険な水準」というアラート自体が、通知先の設定不備で6日間サイレントに失敗し続けていた問題も見つかりました。
まとめ
- 一見無関係な複数のアプリの障害を、個別の不具合として片付けず、症状のパターン(低頻度のI/Oエラー→プロセスクラッシュ、NFS上のファイルという共通点)で横断的に見たことが、根本原因(NAS側のiSCSI不安定性)にたどり着く手がかりになった。
- 根本原因は、3か月前からログに残っていたのに、誰も気づかず放置されていた。低頻度で自動復旧する障害は、ログに残っていても「表面化しない」まま蓄積する。
- 応急処置として入れた自己修復の仕組み(watchdog)自体も、起動直後の正常な状態を誤検知するバグを持っていた。「異常を検知して自動対応する」仕組みには、その仕組み自身の誤検知への備えも要る。
- 根本原因への対応はまだ終わっていない。応急処置(自動復旧・上限つきのエスカレーション)で当面の被害は抑えられているが、それは対症療法でしかない。
セルフホスト特有の構成(自宅のNAS・iSCSI)に基づく話なので、クラウド上のマネージドストレージを使っている環境ではそのまま当てはまらない部分もあります。
JQITのエンジニアの95%以上は未経験からの採用です。
よければコーポレートサイトにも遊びに来てください。
未経験から学べます!一緒に挑戦していきましょう![]()
noteやXもやってます↓