Google CloudがGKEの障害の原因を紹介、カーネル修正をGKE 1.33.5以降で提供
公開:
GKEのKCP VMで、パケットの順序の乱れやEnvoyのhalf-close、Linuxカーネルの不具合が重なり、接続障害が起きました。新しい接続はi/o timeoutで失敗し、3つのうちLinuxカーネルの修正はGKE 1.33.5以降で提供されています。[1]
この記事では、3つの要因が重なって接続の失敗につながった流れと、修正の提供範囲を解説します。i/o timeoutで接続が完了しない症状を調べる場合に、複数の層を見比べる確認方針も編集部が整理しました。
目次
GKE KCP VMの障害で交差した3つの要因
正常なTCPスタックはFINを処理してACKを返し、接続を閉じます。障害当時のGKE KCP VMはこの処理を行えず、half-open接続がFIN_WAIT_2の状態で2分を超えて残りました。[1]
2分を超える残留は、Private Service ConnectのNAT層がポートを再利用できる長さでした。障害の原因は1つのバグではなく、3つの別々の要因が最悪のタイミングで交差したものです。
3つの要因のうち、Envoyのhalf-closeは不具合ではなく正しい動作です。この動作は、FINが処理されない場合にだけ問題化します。
PIGvでのパケット順序の乱れ
KCP VMのホストNICでは、パケットは順序どおりに届いていました。USPSを通ってPIGv(VMから見た仮想NIC)に現れた時点では、順序が少し入れ替わっていました。
順序の乱れの原因は、Private Service Connectのmiss-thread処理です。遅い経路ではproxy protocolヘッダーを追加し、閉じる途中のフローのFINやRSTは、後続のACKと順序が少し前後する場合があります。
KCP VMが実際に受信した並びでは、順序が入れ替わり、クライアントのACKが先に届いてFINが続きました。サーバーは自身のFINを送ってFIN_WAIT_1に入り、その後に現れた古いFINへACKを返すべきでしたが、返しませんでした。
並びに2回現れるFINのうち古いFINを見ると、順序の入れ替わりにより、クライアントのFINは、サーバーが自身のFINを送った後に届きました。サーバーはFIN_WAIT_1の後にFIN_WAIT_2へ進みましたが、サーバーのカーネルは届いたFINを無視しました。
Envoyのhalf-closeの影響
障害当時、孤立ソケットに限り適用されるtcp_fin_timeoutは、FIN_WAIT_2のソケットが強制的に閉じられるまでの待ち時間を決めるLinuxカーネルのパラメータです。KCP VMでは60秒に設定されていました。
孤立ソケットは、どのプロセスも開いていないソケットです。障害当時のKCP VMでは、Envoyが開いたままのソケットは対象外でした。
Envoyは、KCP VMでkube-apiserverの前段に置かれたプロキシです。shutdown(SHUT_WR)で書き込み側を閉じ、受信のためにソケットを開いたままにするhalf-closeを行っていました。
half-close自体は正当なTCPの動作です。ただし、Envoyが保持する間はカーネルが孤立ソケットと見なさず、ソケットは正しく処理できないFINを待ち続けました。
Linuxカーネル6.1でのFIN破棄
順序が入れ替わったFINでも、健全なカーネルならFIN_WAIT_2で受信したFINを処理してTIME_WAITへ進むはずです。ソケットはいずれ閉じるはずですが、KCP VMでは閉じませんでした。
Linuxカーネル6.1には、RFC 5961の許容範囲内にある古いACKを受けると、tcp_ack()がゼロを返すコード経路がありました。FIN_WAIT_2では、呼び出し元が有効な受信FINを処理しないまま破棄し、接続が無期限に残りました。
この不具合はカーネル6.1から存在し、カーネル6.9.7では修正済みでした。KCP VMはContainer-Optimized OS(COS)の6.1系と6.6系のビルドで動いていたため、バックポートとCOSイメージの更新が必要でした。
不具合を修正したLinuxカーネルのコミットは、upstreamにある795a7dfbc3d9です。作者はEric Dumazet氏です。
GKE KCP VMで3つの要因が重なる流れ
3つの要因は単独では今回の規模の障害にならず、3つが同時に作用して初めて障害が起きたとGoogle Cloudは評価しています。単独と同時の違いは、以下の通りです。[1]
FIN_WAIT_2に残ったソケットのポートは、Private Service Connect NATに再利用されました。challenge ACKが送られてもUSPSの修正で破棄され、接続が失敗しました。
障害調査で原因特定につながった確認項目
i/o timeoutの症状は、Private Service Connectの層やカーネルのTCP状態機械、Envoyの接続管理のどれを見ても同じでした。各層にもっともらしい説明があり、どの説明も不完全だったとGoogle Cloudは振り返っています。[1]
経路上の複数地点での同時パケットキャプチャが、原因の特定につながりました。キャプチャとUSPSの指標の照合や、ラボ環境での再現も欠かせなかったと、Google Cloudは評価しています。
Google Cloudは、パケットの順序の入れ替わりとhalf-closeのソケット、善意のセキュリティパッチを同時に存在させるべきではないと総括しています。利用者は本番環境に戻り、Linuxカーネルにはより良い修正が入りました。
次のコードは、新しい接続の直前にnetstatで取得したカーネルのソケット状態です。「2 minutes later」以降は、後続の経過の説明です。
Proto Local Address Foreign Address State
tcp 10.128.0.5:443 10.0.13.77:53426 FIN_WAIT_2
# This socket has been in FIN_WAIT_2 for > 120 seconds.
# tcp_fin_timeout=60 has not fired because the socket is not orphaned.
# Envoy holds it open with SHUT_WR.
# 2 minutes later, Private Service Connect NAT reuses port 53426 for a new pod connection.
# The kernel sees the new SYN on this 5-tuple and sends a challenge ACK.
# USPS drops the challenge ACK. → i/o timeout.
公式資料からの抜粋:When the Kubernetes API went silent: A three-layer networking mystery(Part three: Three bugs, one crime scene / Bug #2: Envoy's half-close and the frozen timer)。対象版・範囲:障害当時のGKE KCP VM。
上記のコードでは、ソケットをEnvoyが保持して孤立ソケットではないため、tcp_fin_timeout=60が働かず、120秒を超えてFIN_WAIT_2に残っています。「2 minutes later」以降は、ポート53426の新しいpod接続への再利用と、challenge ACK破棄によるi/o timeoutを示します。
GKE KCP VMの障害に対する3層の対応
修正は3つの層にまたがり、複数のチームが数週間かけて調整しました。Linuxカーネルのパッチは、Linux 6.9.7にマージされ、6.6.yと6.1.yのLTSブランチへバックポートされ、GKE 1.33.5以降で提供されます。[1]
このパッチを含むCOSイメージを実行するすべてのGKEの版で、不具合はOSレベルで解消しています。本事例は、匿名化した顧客サポート案件と社内のバグ情報に基づく内容です。
3つの層の対応は、以下の通りです。
| 修正の段階 | 対象の層 | 内容 |
|---|---|---|
| 緊急の緩和策(2026年2月) | USPS | 変更をロールバックし、challenge ACKの転送に戻す |
| 正しい動作への修正 | Private Service Connectのproxy protocol層 | challenge ACKの場面を適切に処理する置き換えの変更 |
| 根本原因の修正 | Linuxカーネル | net: tcp: accept old ack during closingのパッチ |
緊急の緩和策の後、利用者のクラスターは3月上旬までに回復しました。正しい動作への修正では、回帰を防ぐPacketDrillテストも追加されました。
本件には2週間で7〜8分野の技術者が関わり、一人では全体を把握できませんでした。ケースノートや共有バグトラッカー、綿密に収集したpcapsが分散したチームを一体にしたとGoogle Cloudは評価しています。
接続が完了しないi/o timeoutの確認点
i/o timeoutで接続が完了しない症状を調べる場合は、1つの層の説明で止めず、複数の層を見比べる方法が考えられます。確認点を編集部が次の図に整理しました。
FIN_WAIT_2に残るソケットを見つけた場合は、ソケットを開いたままのプロセスの有無も確かめます。障害当時のGKE KCP VMでは、tcp_fin_timeoutの対象は孤立ソケットに限られていました。[1]
パケットの順序を調べる場合は、キャプチャを取得できる地点で同時に取得し、地点ごとの順序を比べます。今回は、ホストNICやPIGv、コンテナ内部での同時キャプチャがなければ順序の乱れは見えなかったと、Google Cloudは振り返っています。
修正状況を確かめたい場合、クラスターの回復と根本原因の修正は別の段階の確認対象です。2026年2月の緩和策はUSPSの変更を戻し、GKE 1.33.5以降で提供されるパッチはLinuxカーネル自体を修正します。
Linuxカーネルの修正を確かめる場合は、GKE 1.33.5以降かどうかとCOSイメージを確認します。対象は、パッチを含むCOSイメージを実行する版です。
出典
- ^ Google Cloud. 「When the Kubernetes API went silent: A three-layer networking mystery」. https://cloud.google.com/blog/products/networking/the-three-layer-gke-network-mystery, (参照 26-10-30).
※本記事は公式の一次情報を基に編集しています。内容はAIで確認していますが、誤りや最新情報との差異がある場合は、以下フォームよりご報告ください。
修正・削除・掲載などの依頼はこちら

















