mcpField
G
gke-node-notready

gke-node-notready

github.com/googleクラウド・DevOps21.6k2.9k 回インストール今日更新
リポジトリ

gke-node-notready について

`NotReady`または`Ready: Unknown`状態のGKEノードを診断し、対処案を提示する読み取り専用スキルです。ノード、ログ、メトリクスの証拠を集め、修復操作は人間に委ねます。

主な機能

  1. 01ノード状態とイベントの確認
  2. 02kubeletログとシリアルログの分析
  3. 03ランタイムやリソース問題の調査
  4. 04ネットワークとアドミッションの調査
  5. 05クラスタを変更せず対処案を提示

活用シーン

  1. 01NotReadyが続くGKEノードの調査
  2. 02kubeletエラーとノード負荷の照合
  3. 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:コンテキストの確認と時間範囲
  1. パラメーターの抽出 — project_id、cluster_name、 cluster_location、node_name を、ユーザープロンプト、 アクティブな SETTINGS.md、または環境のデフォルト値(kubectl config current-context、 gcloud config get-value project)から非対話的に取得します。
  2. 認証情報とフォールバック — 次のコマンドを試します。 gcloud container clusters get-credentials {cluster_name} --location {cluster_location} --project {project_id}。 クラスターに接続できない場合、またはコマンドが失敗する場合(サンドボックス/ドライラン/オフライン)、 人間が実行する正確な診断コマンドを提示し、報告された症状に基づいて 分析を続けます。
  3. 時間範囲 — {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 healthyPLEG の停止。通常はノードの過負荷(CPU/ディスク)が原因ですステップ 4c
containerd/kubelet の TaskHung、ディスクレイテンシーの高さディスクのスロットリング/I/O の枯渇ステップ 4b
failed to ensure lease、leases.coordination.k8s.io ... namespace kube-node-lease ... terminatingkube-node-lease の終了 → NotReady の状態変動ステップ 4f
Kubelet が API サーバーに到達できない、TLS/ダイヤルのタイムアウトKubelet とコントロールプレーン間の接続ステップ 4d
NetworkPluginNotReady、cni plugin not initialized、NetworkUnavailableCNI プラグインの障害ステップ 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 つをすべて実施します。

  1. 制約を明確に伝えます(例:「該当日の kubelet ログは _Default の 30 日間の保持期間を過ぎており、完全に削除されています」)。
  2. 収集できた調査結果を要約します(ノードの状態、イベント、メトリクス、および _Required バケットに残っている Admin Activity 監査ログ(デフォルトの保持期間は 400 日))。
  3. **これらの調査結果を添えて GKE サポート/エンジニアリング部門へエスカレーションします。**セルフサービスでの調査をさらに提案し続けないでください。また、根拠がないのに診断結果を捏造しないでください。

参考資料

このスキルは、Google Cloud の公開ドキュメントを基にしています。

コメント