Claudeが単独で診断・復旧したサーバー障害:AIOpsが現実になった一日

2026年6月13日、運用中のウェブサービスが突然開かなくなった。

最初は単純なサーバー再起動の問題のように見えた。

しかし実際には、LinuxカーネルのアップデートとCilium eBPFデータパスが絡んだ、かなり深いネットワーク障害だった。

興味深いのは、この障害を人間が一つずつ分析したわけではないという点だ。

今回の障害対応は、Claudeがリモートサーバーに接続して状態を確認し、コマンドを実行し、ログを分析し、原因を絞り込み、復旧措置まで実行した事例である。

人間がやったことは、途中で危険な作業について承認したことだけだった。

サービス名、ドメイン、IP、サーバー名、ノード名などの機密情報は*でマスキングした。

ただし、原因分析に必要なカーネルバージョンはそのまま表記した。


3行要約

サーバー再起動後、ウェブサービスは開かなかったが、SSH接続とKubernetesクラスターの状態は正常に見えた。

Claudeがリモートサーバーで直接コマンドを実行し、Gateway、Cilium、NodePort、tcpdump、カーネル履歴を順に分析し、最終的に6.8.0-124-genericカーネルとCilium 1.18.3の組み合わせによるeBPFデータパスの問題と判断した。

以前のカーネルである6.8.0-111-genericで起動するとサービスは即座に復旧し、Claudeは再発防止のためにGRUBのデフォルト起動カーネルまで固定した。


1. 障害の始まり:サーバーは生きているのにウェブサービスだけが停止した

最初の症状は単純だった。

ウェブサイトが開かなかった。

curl https://***/

# curl: (28) 接続が15007ミリ秒後にタイムアウトしました

最初はサーバー自体が停止しているように見えた。

bash scripts/test-connection.sh

# ssh: ホスト ***.***.***.*** ポート 22 への接続: 操作がタイムアウトしました

Tailscaleの状態を確認すると、サーバーがオフライン状態であることが確認された。

***.***.***.***   ***-server   linux   active; relay "***"; offline, last seen 2d ago

ここまでは単純だった。

サーバーが停止しており、再起動すれば終わるように見えた。

しかし、サーバーを再起動した後もウェブサービスは依然として開かなかった。

SSH接続は可能だった。

サーバーリソースも正常範囲だった。

load average: 0.87
CPU idle: 87%
Memory free: 12GB
Disk usage: 12%
Failed systemd services: 0

KubernetesノードもすべてReady状態だった。

kubectl get nodes

# ***-control-plane   Ready   204d
# ***-worker          Ready   204d
# ***-worker2         Ready   204d

表面的にはサーバーは正常だ。

しかし、ユーザーが見るウェブサービスは停止していた。

この時点でClaudeは単に「サーバーは正常だ」と判断しなかった。

サービスが実際に通過する経路全体を基準に障害を見始めた。


2. 構造は単純なウェブサーバーではなかった

今回の環境は、単にNginxが一つ稼働している構造ではなかった。

全体の構造はおおよそ次のようだった。

외부 사용자
  ↓
도메인 ***
  ↓
공인 IP ***.***.***.***
  ↓
물리 서버 ***
  ↓
Docker
  ↓
kind 기반 Kubernetes 클러스터
  ↓
Cilium Gateway API
  ↓
내부 웹 애플리케이션

つまり、障害が発生しうる地点が多かった。

可能な候補は次のとおりだった。

DNS 문제
공인 IP 문제
호스트 방화벽 문제
Docker 네트워크 문제
Kubernetes Service 문제
Cilium Gateway 문제
Envoy 문제
eBPF 데이터패스 문제
백엔드 애플리케이션 문제
Linux 커널 문제

人間が直接見ていたら、どの地点から確認すべきかかなり悩んだだろう。

しかしClaudeは状態を階層別に分け始めた。

サーバー自体が正常か、Kubernetesが正常か、Gatewayが正常か、NodePortが正常か、実際のパケットがどこまで入ってくるかを順に確認した。


3. 今回の障害対応における人間の役割

今回の事例で重要な点は、Claudeが単に助言だけをしたのではないという点だ。

Claudeが直接リモートサーバーに接続し、コマンドを実行し、出力結果を解釈し、次の点検コマンドを続けて実行した。

人間の役割は限定的だった。

사람:
- 위험한 작업 승인
- 재부팅 같은 주요 조치 승인
- 최종 결과 확인

Claude:
- 원격 서버 상태 점검
- Kubernetes 상태 점검
- Cilium Gateway 상태 분석
- IP Pool 문제 확인 및 복구
- NodePort 구간 테스트
- tcpdump 기반 패킷 분석
- Envoy 메트릭 확인
- 커널 변경 이력 추적
- 이전 커널 부팅 조치
- GRUB 기본 부팅 커널 고정
- 장애 기록 정리

つまり、今回の対応は「オペレーターがClaudeに尋ねて解決した事例」というよりも「ClaudeがAIOpsエージェントのように障害を診断し復旧した事例」に近い。

もちろん、すべての作業が完全に無監督で進行されたわけではない。

再起動、GRUB変更のようにシステムに影響を与える作業は人間が承認した。

しかし、障害分析と復旧の流れ自体はClaudeが主導した。


4. 最初の原因候補:Cilium Gatewayアドレス未割り当て

Claudeが最初に確認したのはCilium Gatewayの状態だった。

kubectl -n kube-system get gateway cilium

結果は次のとおりだった。

NAME     CLASS    ADDRESS   PROGRAMMED   AGE
cilium   cilium             False        204d

PROGRAMMED=False状態だった。

Gatewayが外部トラフィックを受け入れる準備ができていない状態だ。

詳細条件を確認すると、理由はAddressNotAssignedだった。

Gateway waiting for address

つまり、Gatewayが使用する外部IPを受け取れていなかった。

ClaudeはすぐにCilium LoadBalancer IP Poolの状態を確認した。

kubectl get ciliumloadbalancerippool

# リソースが見つかりません

IP Poolリソースが消えていた。

この環境ではCilium Gatewayが特定のパブリックIPを使用する必要があったため、IP PoolがなければGatewayは外部アドレスを受け取ることができない。

Claudeは既存の設定を見つけてIP Poolを再適用した。

apiVersion: "cilium.io/v2alpha1"
kind: CiliumLoadBalancerIPPool
metadata:
  name: "cilium-pool"
spec:
  blocks:
    - cidr: "***.***.***.***/32"

再びGatewayの状態を確認した。

kubectl -n kube-system get gateway cilium
NAME     CLASS    ADDRESS           PROGRAMMED   AGE
cilium   cilium   ***.***.***.***   True         204d

Gatewayは正常状態になった。

ここまでは問題が解決したように見えた。

しかし、ウェブサービスは依然としてタイムアウトだった。

Claudeはここで分析を止めなかった。

「Gatewayアドレスの問題は解決されたが、ユーザーのトラフィックが依然として失敗するなら、別の問題が残っている」と判断した。


5. 区間別テスト:どこまでが正常か

次にClaudeはネットワーク経路を区間別に分割し始めた。

NodePort 30080を基準に、出発地を変えながらテストした。

テスト区間 結果
ワーカーコンテナ内部 → 自分自身 30080 正常
他のKubernetesノード → ワーカーノード 30080 正常
物理サーバーホスト → ワーカーコンテナ 30080 タイムアウト
外部ユーザー → ドメイン HTTPS タイムアウト

この結果は非常に重要だった。

Kubernetes内部通信は正常だった。

ノード間通信も正常だった。

バックエンドアプリケーションも完全に停止していたわけではなかった。

問題はホストの外からコンテナ側へ入ってくる経路だった。

Claudeはこの結果を基に障害範囲を大きく絞り込んだ。

애플리케이션 자체 문제 가능성 낮음
Kubernetes 내부 네트워크 문제 가능성 낮음
노드 간 통신 문제 가능성 낮음
호스트 → 컨테이너 NodePort 처리 경로 문제 가능성 높음
Cilium/eBPF 데이터패스 문제 가능성 상승

ファイアウォールも確認した。

ufw status

# 非アクティブ

IPフォワーディングも有効になっていた。

sysctl net.ipv4.ip_forward

# net.ipv4.ip_forward = 1

ホストからコンテナへのpingも正常に到達した。

したがって、単純なファイアウォールの問題やルーティングの完全な切断とは考えにくかった。


6. 決定的な証拠:SYNは到着するがSYN-ACKがない

Claudeは次の段階でtcpdumpを使用した。

ワーカーコンテナのネットワークネームスペース内で30080ポートをキャプチャした。

nsenter -t $WORKER_PID -n tcpdump -ni eth0 'tcp port 30080'

そしてホストから30080ポートへ接続を試みた。

tcpdumpの結果は次のとおりだった。

01:18:53 IP ***.***.***.***.51640 > ***.***.***.***.30080: Flags [S]
01:18:54 IP ***.***.***.***.51640 > ***.***.***.***.30080: Flags [S]
01:18:55 IP ***.***.***.***.51640 > ***.***.***.***.30080: Flags [S]

ここで核心は一つだ。

SYNパケットはコンテナのeth0まで到着した。

しかし、SYN-ACK応答が出なかった。

TCP接続は通常、次の順序で開始される。

Client → Server : SYN
Server → Client : SYN-ACK
Client → Server : ACK

今回は最初のSYNだけが繰り返し見られた。

サーバー側の応答であるSYN-ACKがなかった。

つまり、パケットが全く到着しなかったわけではなかった。

パケットは目的地の近くまで来た。

しかし、コンテナ内部のネットワーク処理経路で正常に応答が生成されなかった。

CiliumはeBPFを利用してカーネルレベルでパケットを処理する。

Gateway APIを使用する場合、トラフィックはCiliumのeBPF経路を通りEnvoyに転送される。

ClaudeはEnvoyのメトリックも確認した。

listener-insecure downstream_cx_total = 0

接続を試みてもカウンターは増加しなかった。

つまり、パケットはコンテナのeth0まで見えたがEnvoyまで到達しなかった。

この時点で原因候補はかなり絞り込まれた。

애플리케이션 문제 아님
DNS 문제 아님
단순 방화벽 문제 아님
Kubernetes 내부 통신 문제 아님
Envoy까지 트래픽이 도달하지 않음
Cilium eBPF 데이터패스 또는 커널 네트워크 처리 경로 의심

7. Cilium再起動でも解決しなかった

一時的なCiliumの状態問題である可能性があったため、ClaudeはCilium関連コンポーネントを再起動した。

kubectl -n kube-system rollout restart ds/cilium
kubectl -n kube-system rollout restart ds/cilium-envoy

しかし症状はそのままだった。

GatewayはPROGRAMMED=Trueだった。

Kubernetes内部通信も正常だった。

しかし外部から入ってくるトラフィックは依然としてタイムアウトだった。

このときClaudeが捉えた核心的な質問はこれだった。

재부팅 전에는 정상인데,
재부팅 후 장애가 발생했다면,
재부팅으로 인해 실제로 바뀐 것은 무엇인가?

この質問が決定打だった。

設定が変わったわけでもなく、アプリケーションが変わったわけでもなかった。

再起動で新しく適用されたのはカーネルだった。


8. 本当の原因候補:カーネルアップデート

現在のカーネルバージョンを確認した。

uname -r

# 6.8.0-124-generic

再起動履歴を確認した。

last reboot -F

結果は次のとおりだった。

Sat Jun 13 00:03  boot  6.8.0-124-generic
Tue May 19 13:04  boot  6.8.0-111-generic

以前は6.8.0-111-genericカーネルで運用されていた。

しかし今回の再起動後には6.8.0-124-genericカーネルに上がっていた。

カーネルのインストール履歴も確認した。

grep "install linux-image" /var/log/dpkg.log
2026-06-04 install linux-image-6.8.0-124-generic

まとめるとこうだ。

6월 4일:
- linux-image-6.8.0-124-generic 자동 설치

6월 4일 이후:
- 서버는 계속 기존 커널 6.8.0-111-generic으로 운영

6월 13일:
- 서버 재부팅
- 새 커널 6.8.0-124-generic으로 부팅
- Cilium eBPF 경로에서 외부 트래픽 처리 이상 발생
- 웹서비스 타임아웃

このような障害は原因と症状が時間差を置いて現れる。

カーネルは6月4日にすでにインストールされていた。

しかし実際に適用されたのは6月13日の再起動後だった。

運用者からすれば「今日何も変えてないのに、なぜ障害が起きた?」と感じるかもしれない。

しかし実際の原因は数日前の自動アップデートで入り、再起動によって有効化されたのだ。

Claudeはこの点を障害原因候補として確定した。


9. 復旧:以前のカーネルで起動

最も早い復旧方法は、障害発生前に正常に動作していたカーネルに戻すことだった。

Claudeは次の起動で以前のカーネルを使用するように設定した。

grub-reboot "Advanced options for Ubuntu>Ubuntu, with Linux 6.8.0-111-generic"
reboot

この作業はシステム再起動を伴うため、人間の承認を経て進行した。

起動後、カーネルバージョンを確認した。

uname -r

# 6.8.0-111-generic

KubernetesノードとCiliumコンポーネントが正常に起動するまで待った後、再度テストした。

curl http://127.0.0.1:30080/

正常な応答が返ってきた。

外部ドメインも確認した。

curl -L https://***/

結果はHTTP 200だった。

HTTP 200

サービスが復旧した。

原因候補が事実上確認された瞬間だった。

6.8.0-124-genericでは外部トラフィックがCilium eBPF経路で正常に処理されず、6.8.0-111-genericに戻すとサービスが正常化した。


10. 再発防止:GRUBデフォルトカーネル固定

しかし、ここで終わらせてはいけない。

grub-rebootは1回限りの設定だ。

次の再起動時に再び6.8.0-124-genericに上がると、同じ障害が繰り返される可能性がある。

Claudeは再発防止のためにGRUBのデフォルト起動カーネルを6.8.0-111-genericに固定した。

grub-set-default "Advanced options for Ubuntu>Ubuntu, with Linux 6.8.0-111-generic"
update-grub

設定確認も行った。

grub-editenv list
saved_entry=Advanced options for Ubuntu>Ubuntu, with Linux 6.8.0-111-generic

これで次の再起動でもデフォルトで6.8.0-111-genericカーネルで起動する。

ただし、これは一時的な措置だ。

以前のカーネルに固定すると、最新カーネルのセキュリティパッチを見逃す可能性がある。

したがって、長期的には次の後続作業が必要だ。

- Cilium 업그레이드 검토
- 6.8.0-124-generic 또는 이후 커널에서 재현 테스트
- Cilium eBPF 관련 설정 검토
- 커널 자동 업데이트 정책 재검토
- 재부팅 전후 외부 헬스체크 자동화
- 운영 노드 재부팅 전 사전 검증 절차 마련

11. AIOpsの観点から見た今回の障害

今回の障害は単に「Claudeに尋ねたら答えを教えてくれた」という事例ではない。

Claudeが実際にリモートサーバーで状態を確認し、コマンドを実行し、ログを解釈し、次の確認地点を自ら続けていった。

AIOpsの観点から見ると、次の流れに近い。

1. 장애 감지
2. 서버 접속 상태 확인
3. Kubernetes 상태 확인
4. Gateway 상태 확인
5. 누락된 IP Pool 복구
6. 사용자 증상 재확인
7. NodePort 구간별 테스트
8. tcpdump로 패킷 흐름 확인
9. Envoy 메트릭 확인
10. Cilium 재시작
11. 재부팅 전후 커널 변경 확인
12. 이전 커널로 복구
13. GRUB 기본값 고정
14. 장애 기록 작성

この過程で人間はすべてのコマンドを直接設計し実行したわけではない。

Claudeが判断し実行した。

人間は危険度の高い作業で承認しただけだった。

これはAIOpsが単純なモニタリングやアラート自動化のレベルを超えうることを示している。


12. Claudeが特に優れていた点

12.1 障害範囲を素早く絞り込んだ

最初は可能な原因が多すぎた。

DNS
방화벽
Docker
Kubernetes
Cilium
Gateway
Envoy
eBPF
Linux 커널
애플리케이션

しかしClaudeは区間別テストを通じて候補を減らした。

Kubernetes 내부 정상
노드 간 통신 정상
호스트 → 컨테이너 NodePort 실패
SYN은 도착
SYN-ACK 없음
Envoy까지 미도달
재부팅 후 커널 변경

結局、原因候補はカーネル+Cilium eBPFデータパスの組み合わせに絞り込まれた。


12.2 tcpdumpの結果を障害原因と結びつけた

tcpdumpでSYNだけが繰り返され、SYN-ACKがないというのは重要な手がかりだ。

Claudeはこの結果を単に「パケットが見える」で終わらせなかった。

次のように解釈した。

패킷은 목적지 네트워크 인터페이스까지 도착했다.
하지만 TCP 응답이 생성되지 않았다.
따라서 단순 라우팅 단절이나 방화벽 차단보다는 수신 처리 경로가 의심된다.
Cilium eBPF 또는 Envoy 전달 경로를 확인해야 한다.

この解釈のおかげで、不要なDNS、TLS、アプリケーション分析に陥ることなく済んだ。


12.3 再起動で適用された変更点を追跡した

今回の障害の核心は再起動だった。

再起動前は正常で、再起動後に障害が発生した。

Claudeはこの違いを基準にカーネル履歴を確認した。

uname -r
last reboot -F
grep "install linux-image" /var/log/dpkg.log

そして6.8.0-111-genericから6.8.0-124-genericへカーネルが変わった事実を見つけ出した。

これが最終的な復旧方向を決定した核心的な手がかりだった。


12.4 復旧から再発防止まで続けた

障害対応でよくある間違いは「とりあえず復旧したから終わり」と考えることだ。

しかしClaudeは以前のカーネルで1回限りの起動をした後も止まらなかった。

次の再起動時に同じ問題が繰り返されないようにGRUBのデフォルト値を固定した。

grub-set-default "Advanced options for Ubuntu>Ubuntu, with Linux 6.8.0-111-generic"
update-grub

復旧と再発防止を区別して処理したのだ。


13. AIが直接サーバーを管理する利点

今回の事例を通じて、AIベースのリモートサーバー管理の利点が明確に示された。

第一に、障害対応速度が速くなる。

Claudeはコマンド結果を見て次の確認地点にすぐさま進んだ。

人間が検索したり悩んだりする時間を大幅に削減した。

第二に、複雑な階層を構造化する。

物理サーバー、Docker、Kubernetes、Cilium、eBPF、Envoyが絡み合った環境でも、階層別に問題を分離した。

第三に、コマンド結果を解釈する。

単にコマンドを羅列するだけでなく、結果が何を意味するのかを分析した。

第四に、復旧後の文書化が容易だ。

障害対応プロセス自体が記録として残りやすいように整理された。

今回の記事もClaudeが実行した作業の流れに基づいて整理したものだ。

第五に、繰り返し可能なRunbookに発展させることができる。

今回の手順は、次の障害対応自動化の基盤となりうる。

서버 상태 확인
Kubernetes 상태 확인
Gateway 상태 확인
NodePort 구간 테스트
tcpdump 패킷 확인
커널 변경 이력 확인
복구 커널 선택
재발 방지 설정

14. 注意点:AIにすべての権限を与えるのは危険だ

今回の事例が成功したからといって、AIに運用サーバーのすべての権限を無制限に与えるのは危険だ。

特に次の作業は必ず承認手続きが必要だ。

reboot
grub-reboot
grub-set-default
update-grub
kubectl delete
kubectl rollout restart
iptables
tc
sysctl

今回もClaudeが障害分析と復旧を主導したが、再起動やGRUB変更のように危険度の高い作業は人間が承認した。

現実的な運用モデルは次のとおりだ。

일반 조회 명령:
- Claude가 자유롭게 수행

상태 변경 명령:
- Claude가 제안 및 실행 준비
- 사람 승인 후 실행

위험 명령:
- 사람 승인 필수
- 가능하면 롤백 방법 확인 후 실행

AIOpsの核心は人間を完全に排除することではない。

AIが実務作業の大部分を実行するが、危険な決定には承認ゲートを設けることだ。


15. 今回の障害から得た教訓

第一に、サーバーが生きていてもサービスは停止しうる。

SSH接続が可能で、CPUとメモリが正常でも、ユーザーがアクセスするウェブサービスは失敗しうる。

第二に、AIは複雑な障害の原因をかなり深く追跡できる。

今回の事例でClaudeは単純なログ要約だけでなく、Gateway、Cilium、NodePort、tcpdump、Envoy、カーネル履歴まで連結して分析した。

第三に、再起動後の障害はカーネル変更を必ず確認する必要がある。

uname -r
last reboot -F
grep "install linux-image" /var/log/dpkg.log

第四に、eBPFベースのネットワークはカーネルアップデートに敏感だ。

CiliumはカーネルのeBPF機能を積極的に使用するため、カーネルアップデートがネットワークデータパスに影響を与える可能性がある。

第五に、AIに実行権限を与える際は承認境界を明確にする必要がある。

照会と分析はAIが自動で実行しても、再起動や起動設定変更は承認ベースで処理するのが安全だ。


まとめ

今回の障害は単にウェブサイトが開かない問題から始まった。

しかし実際の原因はウェブサーバーやアプリケーションではなかった。

サーバー再起動で新しいカーネル6.8.0-124-genericが適用され、この環境でCilium 1.18.3のeBPFデータパスが外部トラフィックを正常に処理できなかったと判断された。

Claudeはリモートサーバーに接続して状態を確認し、Gateway問題を復旧し、NodePort区間をテストし、tcpdumpでパケットを分析し、カーネル履歴を追跡した後、以前のカーネル6.8.0-111-genericに戻してサービスを復旧した。

人間がやったことは主要な危険作業に対する承認だけだった。

今回の事例は、AIOpsが単なるアラート要約のレベルを超え、実際のサーバー障害診断と復旧プロセスまで実行できる可能性を示している。

もちろん、運用サーバーでAIに実行権限を与える際は慎重でなければならない。

しかし、適切な承認体系と権限境界を設ければ、AIは単純な補助ツールではなく、実際の運用エージェントに近い役割を果たすことができる。

今回の障害はその可能性を確認した一日だった。



Comments

コメントを残す

メールアドレスが公開されることはありません。 が付いている欄は必須項目です