gke-node-notready について
`NotReady`または`Ready: Unknown`状態のGKEノードを診断し、対処案を提示する読み取り専用スキルです。ノード、ログ、メトリクスの証拠を集め、修復操作は人間に委ねます。
主な機能
- 01ノード状態とイベントの確認
- 02kubeletログとシリアルログの分析
- 03ランタイムやリソース問題の調査
- 04ネットワークとアドミッションの調査
- 05クラスタを変更せず対処案を提示
活用シーン
- 01NotReadyが続くGKEノードの調査
- 02kubeletエラーとノード負荷の照合
- 03人間による対応向けの証拠と修正案の準備
インストール
コマンドをコピーしてターミナルで実行します。
npx skills add https:/ / github.com/ google/ skills --skill gke-node-notreadyインストール後、Claude Code で/gke-node-notreadyを入力して読み込まれたか確認します。
同梱ファイルreferences/attribution.md
詳細
GKE ノードの NotReady トラブルシューティングスキル
このスキルを使用すると、1 つ以上の GKE ノードが NotReady(または
Ready: Unknown)ステータスを報告する原因を体系的に診断し、安全な緩和策を提案できます。NotReady ステータスは、ノードの kubelet がコントロールプレーンに正常に報告していないことを意味します。そのため Kubernetes はノードへの新しい Pod のスケジューリングを停止し、アプリケーションの容量低下やダウンタイムにつながることがあります。
このスキルは非対話型で動作し、読み取り専用の診断範囲を厳守します。まず証拠を収集してから、人間が適用する修正(kubectl/gcloud コマンドまたは GitOps マニフェストの変更)を提案します。クラスターの変更、ノードのドレイン、削除、再作成は決して自動で行いません。
重要
まず、想定内の
NotReadyではないかを確認してください。新規プロビジョニング中、アップグレード中、修復中、cordon 済み、またはスケールダウン中のノードは、一時的にNotReadyを報告します。想定される時間を超えて継続する場合にのみ、障害として扱ってください。
帰属情報
必ず読むこと:gcloud、REST API、または MCP コマンドを実行する前に、使用状況の帰属情報を必ず読んでください。ターミナルで直接実行するコマンド(生成されたスクリプト、Terraform、ユーザーコード内での実行は不可)では、gcloud の前に
CLOUDSDK_METRICS_REQUEST_ATTRIBUTION="agent-skills/1.0 (skill:gke-node-notready)"
を付け、User-Agent ヘッダーに agent-skills/1.0 (skill:gke-node-notready) を追加してください。
🔍 診断ワークフロー
ステップ 0:コンテキストの確認と時間範囲
- パラメーターの抽出 —
project_id、cluster_name、cluster_location、node_nameを、ユーザープロンプト、 アクティブなSETTINGS.md、または環境のデフォルト値(kubectl config current-context、gcloud config get-value project)から非対話的に取得します。 - 認証情報とフォールバック — 次のコマンドを試します。
gcloud container clusters get-credentials {cluster_name} --location {cluster_location} --project {project_id}。 クラスターに接続できない場合、またはコマンドが失敗する場合(サンドボックス/ドライラン/オフライン)、 人間が実行する正確な診断コマンドを提示し、報告された症状に基づいて 分析を続けます。 - 時間範囲 —
{issue_time}(明示された時刻、相対時刻、または現在時刻)を決定し、 すべてのログ/メトリクスクエリの対象として、その前後 30 分の 1 時間の範囲 (start = issue_time - 30m、end = issue_time + 30m)を設定します。
ステップ 1:NotReady ノードを特定し、初期状態を収集する
# List nodes and spot NotReady status, node IPs, and container-runtime version.
kubectl get nodes -o wide
# Inspect the affected node's Conditions and Events (the primary clues).
kubectl describe node "{node_name}"
Cloud Logging を使用する場合も同様です(kubectl のアクセスが限られている場合や、過去のイベントを調べる場合に推奨)。Logs Explorer の詳細リンクとして開き、クエリを URL エンコードして、プロジェクトとステップ 0 の時間範囲を追加します。
https://console.cloud.google.com/logs/query;query={URL_ENCODED_QUERY};timeRange={start}%2F{end}?project={project_id}
(/ は %2F にエンコードするか、直近 1 時間を対象にする場合は ;duration=PT1H を使用します)。
resource.type="k8s_node"
log_id("events")
resource.labels.node_name="{node_name}"
resource.labels.cluster_name="{cluster_name}"
resource.labels.location="{cluster_location}"
Conditions テーブルの解釈:
Ready: False/Ready: Unknownの理由がKubeletNotReady/NodeStatusUnknown(「Kubelet stopped posting node status」)の場合 → kubelet または ランタイムの問題です。ステップ 2 に進みます。MemoryPressure: True、DiskPressure: True、PIDPressure: True→ リソース の枯渇です。ステップ 4b に進みます。NetworkUnavailable: True→ ネットワーク/CNI の問題です。ステップ 4d に進みます。
ステップ 2:kubelet ログを調べてエラーの兆候を確認する
ステップ 1 と同じ
logs/query;query={URL_ENCODED_QUERY};timeRange=...?project=... の形式で、これらの kubelet ログをLogs Explorer の詳細リンクとして開きます。
resource.type="k8s_node"
resource.labels.node_name="{node_name}"
resource.labels.cluster_name="{cluster_name}"
resource.labels.location="{cluster_location}"
log_id("kubelet")
severity>=WARNING
また、ノードのシリアルコンソールログ(log_id("serialconsole.googleapis.com/serial_port_1_output")
または resource.type="gce_instance" のシリアルログ)も確認し、kubelet の障害と関連するカーネルの TaskHung、OOM キラー、またはディスク I/O エラーがないか調べます。
ステップ 3:シグネチャを根本原因に対応付けます(判断表)
| Kubelet/イベントのシグネチャ | 考えられる根本原因 | 次の手順 |
|---|---|---|
runtime is down、Container runtime not ready、/run/containerd/containerd.sock でのエラー(connection refused/DeadlineExceeded) | コンテナランタイム(containerd)の停止または応答なし | ステップ 4a |
Got sys oom event from cadvisor/シリアルログ内のカーネル OOM キラー | システム(ノードレベル)の OOM による重要プロセスの強制終了 | ステップ 4b |
PLEG is not healthy | PLEG の停止。通常はノードの過負荷(CPU/ディスク)が原因です | ステップ 4c |
containerd/kubelet の TaskHung、ディスクレイテンシーの高さ | ディスクのスロットリング/I/O の枯渇 | ステップ 4b |
failed to ensure lease、leases.coordination.k8s.io ... namespace kube-node-lease ... terminating | kube-node-lease の終了 → NotReady の状態変動 | ステップ 4f |
| Kubelet が API サーバーに到達できない、TLS/ダイヤルのタイムアウト | Kubelet とコントロールプレーン間の接続 | ステップ 4d |
NetworkPluginNotReady、cni plugin not initialized、NetworkUnavailable | CNI プラグインの障害 | ステップ 4d |
| ノードに不可欠な DaemonSet Pod(CNI、kube-proxy、メタデータ)のアドミッションがブロックされる | アドミッション Webhook の干渉 | ステップ 4e |
一般的な NodeNotReady のみで、ほかにシグネチャがない | 原因不明 — ステップ 4d から調査範囲を広げ、その後エスカレーションします | エスカレーション |
ステップ 4:分岐して調査します
4a. コンテナランタイム(containerd)の停止
Kubelet が containerd と通信できないことを確認します(上記のソケットエラー)。シリアルログで
containerd の再起動/クラッシュを確認します。修復(提案のみ。実行しないでください):
ノードを再作成/修復します(kubectl drain を実行してからノードプールに再作成させる、または
gcloud container clusters upgrade/ノードの自動修復を使用します)。複数のノードで再発する場合は、
ノードイメージまたは containerd に干渉するカスタム DaemonSet を疑います。
4b. リソースの逼迫と OOM
# Node allocatable vs. usage.
kubectl describe node "{node_name}" | sed -n '/Allocated resources/,/Events/p'
確認する Cloud Monitoring の指標(読み取り専用):kubernetes.io/node/memory/used_bytes、
kubernetes.io/node/cpu/core_usage_time、kubernetes.io/node/ephemeral_storage/used_bytes。
- DiskPressure/ディスクのスロットリング:ブートディスクの容量不足または PD の速度低下 → ディスク サイズを増やす/より高速な PD タイプを使用します。イメージ/ログの頻繁な生成を減らします。
- システム OOM:ノードのメモリ枯渇 → Pod のメモリ
requests/limitsを設定または引き上げ、 オーバーコミットを減らすか、より大きなマシンタイプを使用します。システム OOM (ノード全体に影響し、kubelet/ランタイムを強制終了)と cgroup OOM (単一コンテナに影響)を区別します。 - PIDPressure:プロセス数が多すぎます → Pod の PID 数に上限を設ける/ワークロード密度を下げます。
4c. PLEG が正常ではありません
PLEG is not healthy は、ほとんどの場合、ノードが過負荷(CPU の飽和、
ディスクレイテンシー、またはノードあたりの Pod/コンテナ数が多すぎる)で、
ランタイムが時間内に再列挙できないことを意味します。4b の指標と関連付けて確認します。
**修復:**ノード密度を下げ、CPU/ディスクの余裕を増やすか、ワークロードを分散します。
4d. ネットワーキング
# Are node-critical networking Pods healthy on this node?
kubectl get pods -n kube-system -o wide --field-selector spec.nodeName={node_name}
- Kubelet とコントロールプレーン間:API サーバーへのダイヤル/TLS タイムアウト → ファイアウォールルール、Private Google Access、承認済みネットワーク、ルート/NAT の変更を確認します。
- CNI の障害(
NetworkPluginNotReady):CNI DaemonSet (netd/calico/データプレーン)がノード上で実行されていません → これらの Pod の ログ/イベントを調べます。
4e. アドミッション Webhook の干渉
スコープが広すぎる、または失敗している検証用/変更用 Webhook は、 ノードに不可欠なシステム Pod のアドミッションをブロックし、ノードを NotReady のままにする可能性があります。
kubectl get validatingwebhookconfigurations,mutatingwebhookconfigurations
failurePolicy: Fail が設定され、kube-system/ノードに不可欠なオブジェクトを
インターセプトする Webhook を探します。**修復(提案):**Webhook の対象から
kube-system/ノードに不可欠な名前空間を除外するか、適切な namespaceSelector を設定します。
4f. kube-node-lease の終了時のフラッピング
leases.coordination.k8s.io ... namespace kube-node-lease ... is being terminated と表示されてノードが NotReady と Ready を繰り返す場合、kube-node-lease 名前空間が削除されたか、終了処理中です。修正案(提案): kube-node-lease 名前空間を削除しないでください。終了処理中の場合は、名前空間を保持しているファイナライザーまたは実行主体を特定し、名前空間を復元してください。
ステップ 5:修正の境界とエスカレーション
- 根本原因と根拠(観測された正確な条件、イベント、ログ行、またはメトリクス)を提示します。根拠となるエントリを人間が直接開けるよう、ステップ 1~2 のディープリンクの形式で Cloud Logging のディープリンク(ステップ 4b のメトリクスについては Cloud Monitoring のリンクも)を提示します。
- 修正案は、人間が適用するための コマンドまたは GitOps マニフェストの変更として提案します。ノードへの変更適用、ドレイン、再作成は自動で行わないでください。 エスカレーションするタイミング(セルフサービスの診断をさらに提案するのではなく、以下を実行してください):
次のいずれかに該当する場合はエスカレーションします。
- 関連するログが 利用できない場合(ログフィルターによって除外されているか、ログバケットの保持期間を過ぎている場合)。
_Defaultバケットの保持期間はデフォルトで 30 日のため、それより古いインシデントのログは完全に削除されています。 - kubelet/イベントのシグネチャが ステップ 3 の表にないうえ、各分岐を調査しても根本原因を 特定できない場合。
その場合は、次の 3 つをすべて実施します。
- 制約を明確に伝えます(例:「該当日の kubelet ログは
_Defaultの 30 日間の保持期間を過ぎており、完全に削除されています」)。 - 収集できた調査結果を要約します(ノードの状態、イベント、メトリクス、および
_Requiredバケットに残っている Admin Activity 監査ログ(デフォルトの保持期間は 400 日))。 - **これらの調査結果を添えて GKE サポート/エンジニアリング部門へエスカレーションします。**セルフサービスでの調査をさらに提案し続けないでください。また、根拠がないのに診断結果を捏造しないでください。
参考資料
このスキルは、Google Cloud の公開ドキュメントを基にしています。
- NotReady ステータスのノードのトラブルシューティング
— ノードの状態、および kubelet/PLEG/システム OOM/containerd/
kube-node-lease/CNI/Admission Webhook のシグネチャとその修正方法。 - ノード登録のトラブルシューティング — 登録が完了しないノード向けの Node Registration Checker。
- GKE ログの表示
と Cloud Logging のルーティングの概要
— ログクエリ(
resource.type="k8s_node"、log_id("kubelet"))とログバケットの 保持期間(_Defaultは 30 日、_Requiredは 400 日)。 - Logs Explorer のインターフェース
— URL を使ったクエリの作成と共有(上記で使用している
logs/query;query=...形式のディープリンク)。