排解 GKE 中狀態為 NotReady 的節點問題

在 Google Kubernetes Engine (GKE) 中,NotReady 狀態代表節點的 kubelet 未正確向控制層回報。由於 Kubernetes 不會在 NotReady 節點上排程新的 Pod,這個問題可能會降低應用程式容量並導致停機。

請參閱這份文件,區分預期 NotReady 狀態和實際問題、診斷根本原因,並找出常見問題的解決方案,例如資源耗盡、網路問題和容器執行階段失敗。

這項資訊適用於負責叢集穩定性的平台管理員和營運人員,以及想瞭解基礎架構相關應用程式行為的應用程式開發人員。如要進一步瞭解我們在內容中提及的常見角色和範例工作,請參閱「常見的 GKE 使用者角色和工作」。 Google Cloud

事前準備

  • 如要取得執行本文件所述工作所需的權限,請要求管理員在 Google Cloud 專案中授予您下列 IAM 角色:

    如要進一步瞭解如何授予角色,請參閱「管理專案、資料夾和組織的存取權」。

    您或許也能透過自訂角色或其他預先定義的角色,取得必要權限。

  • 設定 kubectl 指令列工具,與 GKE 叢集通訊:

    gcloud container clusters get-credentials CLUSTER_NAME \
        --location LOCATION \
        --project PROJECT_ID
    

    更改下列內容:

    • CLUSTER_NAME:叢集名稱。
    • LOCATION:叢集的 Compute Engine 區域或可用區 (例如 us-central1 或 us-central1-a)。
    • PROJECT_ID:您的 Google Cloud 專案 ID。

檢查節點的狀態和條件

如要確認節點是否處於 NotReady 狀態,並協助您診斷根本原因,請按照下列步驟檢查節點的條件、事件、記錄和資源指標:

  1. 查看節點狀態。如要取得 IP 位址和核心版本等有助於診斷的詳細資料,請使用 -o wide 標記:

    kubectl get nodes -o wide
    

    輸出結果會與下列內容相似:

    NAME                                STATUS     ROLES    AGE   VERSION               INTERNAL-IP  EXTERNAL-IP  OS-IMAGE                             KERNEL-VERSION   CONTAINER-RUNTIME
    gke-cluster-pool-1-node-abc1        Ready      <none>   94d   v1.32.3-gke.1785003   10.128.0.1   1.2.3.4      Container-Optimized OS from Google   6.6.72+          containerd://1.7.24
    gke-cluster-pool-1-node-def2        Ready      <none>   94d   v1.32.3-gke.1785003   10.128.0.2   5.6.7.8      Container-Optimized OS from Google   6.6.72+          containerd://1.7.24
    gke-cluster-pool-1-node-ghi3        NotReady   <none>   94d   v1.32.3-gke.1785003   10.128.0.3   9.10.11.12   Container-Optimized OS from Google   6.6.72+          containerd://1.7.24
    

    在輸出內容中,找出 STATUS 欄中值為 NotReady 的節點,並記下其名稱。

  2. 如要查看特定節點的詳細資訊 (包括狀態、狀況和近期 Kubernetes 事件),請按一下 NotReady 狀態:

    kubectl describe node NODE_NAME
    

    將 NODE_NAME 替換為狀態為 NotReady 的節點名稱。

    在輸出內容中,請著重於 Conditions 區段,瞭解節點的健康狀態,並著重於 Events 區段,瞭解近期問題的記錄。例如:

    Name:                   gke-cluster-pool-1-node-ghi3
    ...
    Conditions:
    Type                          Status    LastHeartbeatTime                 LastTransitionTime                Reason                   Message
    ----                          ------    -----------------                 ------------------                ------                   -------
    NetworkUnavailable            False     Wed, 01 Oct 2025 10:29:19 +0100   Wed, 01 Oct 2025 10:29:19 +0100   RouteCreated             RouteController created a route
    MemoryPressure                Unknown   Wed, 01 Oct 2025 10:31:06 +0100   Wed, 01 Oct 2025 10:31:51 +0100   NodeStatusUnknown        Kubelet stopped posting node status.
    DiskPressure                  Unknown   Wed, 01 Oct 2025 10:31:06 +0100   Wed, 01 Oct 2025 10:31:51 +0100   NodeStatusUnknown        Kubelet stopped posting node status.
    PIDPressure                   False     Wed, 01 Oct 2025 10:31:06 +0100   Wed, 01 Oct 2025 10:29:00 +0100   KubeletHasSufficientPID  kubelet has sufficient PID available
    Ready                         Unknown   Wed, 01 Oct 2025 10:31:06 +0100   Wed, 01 Oct 2025 10:31:51 +0100   NodeStatusUnknown        Kubelet stopped posting node status.
    Events:
    Type     Reason                   Age                  From                                   Message
    ----     ------                   ----                 ----                                   -------
    Normal   Starting                 32m                  kubelet, gke-cluster-pool-1-node-ghi3  Starting kubelet.
    Warning  PLEGIsNotHealthy         5m1s (x15 over 29m)  kubelet, gke-cluster-pool-1-node-ghi3  PLEG is not healthy: pleg was last seen active 5m1.123456789s ago; threshold is 3m0s
    Normal   NodeHasSufficientMemory  5m1s (x16 over 31m)  kubelet, gke-cluster-pool-1-node-ghi3  Node gke-cluster-pool-1-node-ghi3 status is now: NodeHasSufficientMemory
    

    在 Conditions 部分中,任何負面條件的狀態為 True,或 Ready 條件的狀態為 Unknown,都表示有問題。請密切注意這些條件的 Reason 和 Message 欄位,因為這些欄位會說明問題的原因。

    各條件類型代表的意義如下:

    • KernelDeadlock:如果節點的作業系統核心偵測到死結,則為 True。死結是嚴重錯誤,可能會導致節點凍結。
    • FrequentUnregisterNetDevice:True 如果節點經常取消註冊網路裝置,可能是驅動程式或硬體有問題。
    • NetworkUnavailable:True 如果節點的網路設定不正確。
    • OutOfDisk:如果可用磁碟空間完全耗盡,則為 True。這種情況比 DiskPressure 更嚴重。
    • MemoryPressure:如果節點記憶體不足,則為 True。
    • DiskPressure:如果節點的磁碟空間不足,則為 True。
    • PIDPressure:True 如果節點發生程序 ID (PID) 耗盡的情況。
    • Ready:指出節點是否正常運作,並準備好接受 Pod。
      • True (如果節點健康狀態良好)。
      • 如果節點健康狀態不佳且不接受 Pod,則為 False。
      • 如果節點控制器在寬限期內 (預設為 50 秒) 未收到節點的回應,且節點狀態不明,則為 Unknown。

    接著,請查看 Events 部分,其中提供節點動作和觀察結果的記錄,並依時間順序排列。這條時間軸對於瞭解節點變成 NotReady 前的狀況至關重要。尋找有助於找出原因的特定訊息,例如逐出警告 (表示資源壓力)、健康狀態檢查失敗,或節點生命週期事件 (例如因維修而隔離)。

  3. 如要進一步瞭解節點為何處於 NotReady 狀態,請查看節點及其元件的記錄檔。

    1. 查看 kubelet 記錄,瞭解 NotReady 狀態。

      kubelet 是向控制層回報節點狀態的主要代理程式,因此其記錄最有可能找到 NotReady 訊息。這些記錄是診斷 Pod 生命週期事件問題、資源壓力狀況 (例如 MemoryPressure 或 DiskPressure),以及節點與 Kubernetes 控制層連線能力的權威來源。

    2. 前往 Google Cloud 控制台的「Logs Explorer」頁面:

      前往 Logs Explorer

    3. 在查詢窗格中,輸入下列查詢:

      resource.type="k8s_node"
      resource.labels.node_name="NODE_NAME"
      resource.labels.cluster_name="CLUSTER_NAME"
      resource.labels.location="LOCATION"
      log_id("kubelet")
      textPayload=~"(?i)NotReady"
      

      更改下列內容:

      • NODE_NAME:要調查的節點名稱。
      • CLUSTER_NAME:叢集名稱。
      • LOCATION:叢集的 Compute Engine 區域或可用區 (例如 us-central1 或 us-central1-a)。
    4. 按一下「執行查詢」並查看結果。

    5. 如果 kubelet 記錄檔未顯示根本原因,請檢查 container-runtime 和 node-problem-detector 記錄檔。這些元件可能不會直接記錄 NotReady 狀態,但通常會記錄導致問題的根本原因 (例如執行階段失敗或核心錯誤)。

    6. 在 Logs Explorer 查詢窗格中,輸入下列查詢:

      resource.type="k8s_node"
      resource.labels.node_name="NODE_NAME"
      resource.labels.cluster_name="CLUSTER_NAME"
      resource.labels.location="LOCATION"
      log_id("COMPONENT_NAME")
      

      將 COMPONENT_NAME 替換為下列其中一個值:

      • container-runtime:執行階段 (containerd),負責完整的容器生命週期,包括提取映像檔和管理容器執行作業。如要排解容器例項化、執行階段服務錯誤或執行階段設定問題,請務必查看 container-runtime 記錄。
      • node-problem-detector:這項公用程式會主動監控各種節點層級的問題,並向控制平面回報。這些記錄對於找出可能導致節點不穩定的根本系統性問題至關重要,例如核心死結、檔案系統損毀或硬體故障,而其他 Kubernetes 元件可能無法擷取這些問題。
    7. 按一下「執行查詢」並查看結果。

  4. 使用 Metrics Explorer 尋找節點變成 NotReady 時的資源耗盡情形:

    1. 前往 Google Cloud 控制台的「指標探索器」頁面:

      前往 Metrics Explorer

    2. 在 Metrics Explorer 中,檢查節點的基礎 Compute Engine 執行個體是否資源耗盡。著重於 CPU、記憶體和磁碟 I/O 相關指標。例如:

      • GKE 節點指標:從以 kubernetes.io/node/ 為前置字元的指標開始,例如 kubernetes.io/node/cpu/allocatable_utilization 或 kubernetes.io/node/memory/allocatable_utilization。這些指標會顯示 Pod 使用的節點可用資源量。可用量不包括 Kubernetes 為系統負荷預留的資源。
      • 客體 OS 指標:如要查看節點作業系統內部的資料,請使用以 compute.googleapis.com/guest/ 為前置字元的指標,例如 compute.googleapis.com/guest/cpu/usage 或 compute.googleapis.com/guest/memory/bytes_used。
      • Hypervisor 指標:如要從 Hypervisor 層級查看 VM 的效能,請使用前置字元為 compute.googleapis.com/instance/ 的指標,例如 compute.googleapis.com/instance/cpu/utilization 或磁碟 I/O 指標,例如 compute.googleapis.com/instance/disk/read_bytes_count。

      如要查看客體 OS 和管理程序指標,請依基礎 Compute Engine 執行個體名稱 (而非 Kubernetes 節點名稱) 進行篩選。如要找出節點的執行個體名稱,請執行 kubectl describe node NODE_NAME 指令,並在輸出內容中尋找 ProviderID 欄位。執行個體名稱是該值的最後一部分。例如:

      ...
      Spec:
      ProviderID: gce://my-gcp-project-123/us-central1-a/gke-my-cluster-default-pool-1234abcd-5678
      ...
      

      在本範例中,執行個體名稱為 gke-my-cluster-default-pool-1234abcd-5678。

依據症狀找出原因

如果您已找出特定徵兆,例如記錄訊息、節點條件或叢集事件,請參閱下表,瞭解疑難排解建議:

類別 症狀或記錄訊息 可能原因 疑難排解步驟
節點條件 NetworkUnavailable: True 節點至控制層的連線問題,或容器網路介面 (CNI) 外掛程式故障。 排解網路連線問題
MemoryPressure: True 節點記憶體不足。 排解節點資源短缺問題
DiskPressure: True 節點的磁碟空間不足。 排解節點資源短缺問題
PIDPressure: True 節點可用的程序 ID 不足。 排解節點資源不足問題
事件和記錄訊息 PLEG is not healthy CPU/IO 使用率過高或 Pod 數量過多,導致 Kubelet 負載過重。 解決 PLEG 問題
Out of memory: Kill process
sys oom event
節點記憶體已完全用盡。 解決系統層級 OOM 事件
leases.coordination.k8s.io...is forbidden kube-node-lease 命名空間終止作業停滯。 解決 kube-node-lease 命名空間的問題
Container runtime not ready
runtime is down
參照 /run/containerd/containerd.sock 或 docker.sock 時發生錯誤
Containerd 或 Docker 服務失敗或設定錯誤。 解決容器執行階段問題
Pod 停滯在 Terminating
Kubelet 記錄檔顯示「kill container」DeadlineExceeded
containerD 記錄檔顯示重複的 Kill container 訊息
程序卡在不可中斷的磁碟休眠狀態 (D 狀態),通常與 I/O 有關。 解決處於 D 狀態的程序
叢集層級症狀 DaemonSet 推出作業完成後,多個節點發生故障。 DaemonSet 會干擾節點作業。 解決第三方 DaemonSet 造成的問題
compute.instances.preempted 稽核記錄。 Spot VM 遭到先占,這是預期行為。 確認節點先占
kube-system Pod 停滯在 Pending 狀態。 Admission Webhook 封鎖重要元件。 解決准入 Webhook 造成的問題
exceeded quota: gcp-critical-pods 配額設定錯誤,導致系統 Pod 遭到封鎖。 解決資源配額導致的問題

檢查預期的 NotReady 事件

NotReady 狀態不一定代表有問題。在節點集區升級等預定作業期間,或使用特定類型的虛擬機器時,可能會發生這種情況。

確認節點生命週期作業

症狀:

在特定生命週期事件期間,節點會暫時顯示 NotReady 狀態。

原因:

在幾個常見的生命週期事件中,節點的狀態會暫時變成 NotReady。每當建立或重新建立節點時,都會出現這種預期行為,例如在下列情況:

  • 節點集區升級:升級期間,系統會排空並更換每個節點。新的升級節點完成初始化並加入叢集前,狀態為 NotReady。
  • 節點自動修復:GKE 替換故障節點時,替換節點在佈建期間會維持 NotReady 狀態。
  • 叢集自動配置器擴充:新增節點後,節點會先處於 NotReady 狀態,完全佈建並加入叢集後,才會變成 Ready 狀態。
  • 手動變更執行個體範本:套用範本變更時,GKE 會重新建立節點。新節點在啟動階段會處於 NotReady 狀態。

解決方法:

節點應該只會短暫處於 NotReady 狀態。如果狀態持續超過 10 分鐘,請調查其他原因。

確認節點先占

如果節點是在 Spot VM 或先占 VM 上執行,Compute Engine 可能會突然終止節點,以回收資源。這是這類短期虛擬機器的預期行為,並非錯誤。

問題:

如果發現下列症狀,節點的 NotReady 狀態可能是預期的 Spot VM 先占所致:

  • 節點在叢集自動配置器刪除並重新建立前,意外進入 NotReady 狀態。
  • Cloud 稽核記錄會顯示基礎 VM 執行個體的 compute.instances.preempted 事件。

原因:

節點是在 Spot VM 或先占 VM 執行個體上執行,而 Compute Engine 已將這些運算資源回收用於其他工作。Spot VM 可能隨時中斷,但通常會提供 30 秒的終止通知。

解析度:

請只將 Spot VM 或先占 VM 用於容錯、無狀態或批次工作負載,這些工作負載的設計可妥善處理頻繁終止的情況。如果正式環境或有狀態工作負載無法容忍突然中斷,請使用標準隨選 VM 佈建節點集區。

排解節點資源不足的問題

節點通常會因為缺乏 CPU、記憶體或磁碟空間等基本資源,而變成 NotReady。如果節點沒有足夠的這些資源,重要元件就無法正常運作,導致應用程式不穩定和節點沒有回應。以下各節將說明這些短缺情況的各種表現方式,從一般壓力狀況到更嚴重的全系統事件都有。

解決節點資源壓力

如果節點的 CPU、記憶體、磁碟空間或程序 ID (PID) 不足,無法執行工作負載,就會發生資源耗盡情形。這個問題可能會導致 NotReady 狀態。

問題:

如果觀察到下列節點條件和記錄,資源耗盡可能是節點 NotReady 狀態的原因:

  • 在 kubectl describe node 指令的輸出內容中,您會看到 OutOfDisk、MemoryPressure、DiskPressure 或 PIDPressure 等條件的 True 狀態。
  • kubelet 記錄檔可能包含記憶體不足 (OOM) 事件,表示系統的 OOM Killer 已遭叫用。

原因:

節點上的工作負載集體要求的資源超出節點可提供的資源。

解析度:

如果是 Standard 叢集,請嘗試下列解決方案:

如果是 Autopilot 叢集,您無法直接控管節點機型或開機磁碟大小。系統會根據 Pod 要求自動管理節點容量。請確保工作負載資源要求符合 Autopilot 限制,並準確反映應用程式的需求。如果資源問題持續發生,可能表示需要最佳化 Pod 要求,或在極少數情況下,可能表示平台有問題,需要 Cloud Customer Care 團隊協助。

解決系統層級的 OOM 事件

如果節點的總記憶體用盡,就會發生系統層級的記憶體不足 (OOM) 事件,導致 Linux 核心強制終止程序,以釋放資源。這與容器層級的 OOM 事件不同,後者是指單一 Pod 超出記憶體限制。

症狀:

如果發現下列症狀,節點不穩定可能是因為系統層級的 OOM 事件:

  • 您會在節點的序列控制台記錄中看到 Out of memory: Kill process 訊息。
  • kubelet 記錄包含 oom_watcher 事件,表示 kubelet 已偵測到系統層級的 OOM 事件。
  • 各種程序 (包括可能重要的系統精靈或工作負載 Pod) 非預期的終止,不一定是記憶體用量最高的程序。

原因:

節點的整體記憶體已用盡。這個問題可能是因為系統服務發生錯誤、工作負載設定錯誤導致耗用過多記憶體,或是節點太小,無法滿足所有執行中 Pod 的記憶體需求。

解決方法:

如要解決系統層級的 OOM 事件,請診斷原因,然後減少記憶體需求或增加節點容量。詳情請參閱「排解 OOM 事件」。

解決 PLEG 問題

Pod 生命週期事件產生器 (PLEG) 是 kubelet 中的元件。它會定期檢查節點上所有容器的狀態,並將任何變更回報給 kubelet。

如果 PLEG 發生效能問題,就無法及時更新 kubelet,導致節點不穩定。

問題:

如果發現下列徵兆,表示 PLEG 可能無法正常運作:

  • 節點的 kubelet 記錄包含類似 PLEG is not healthy 的訊息。
  • 節點的狀態經常在 Ready 和 NotReady 之間變更。

原因:

PLEG 問題通常是由效能問題引起,導致 kubelet 無法及時接收容器執行階段的更新。常見原因包括:

  • CPU 負載過高:節點的 CPU 飽和,導致 kubelet 和容器執行階段無法取得所需的處理能力。
  • I/O 節流:節點的開機磁碟正在執行大量 I/O 作業,這可能會導致所有磁碟相關工作變慢。
  • Pod 數量過多:單一節點上的 Pod 數量過多可能會超出 kubelet 和容器執行階段的負荷,導致資源爭用。

解決方法:

如果是 Standard 叢集,請減輕節點資源的負擔:

如果是 Autopilot 叢集,雖然您無法直接變更現有節點的大小或磁碟類型,但可以透過自訂 ComputeClass,影響工作負載執行的硬體。 這項功能可讓您在工作負載資訊清單中指定需求,例如 CPU 和記憶體數量下限,或特定機器系列,藉此引導 Pod 的排程位置。

如果未使用 ComputeClasses,請調整工作負載部署作業 (例如副本計數和資源要求或限制),並確保這些作業符合 Autopilot 限制。如果最佳化工作負載後,PLEG 問題仍未解決,請與 Cloud Customer Care 團隊聯絡。

解決處於 D 狀態的程序

如果程序卡在不可中斷的磁碟休眠狀態 (D 狀態),節點可能會沒有回應。這個問題會導致 Pod 無法終止,並可能造成 containerd 等重要元件故障,進而導致 NotReady 狀態。

症狀:

  • Pod (尤其是使用 NFS 等網路儲存空間的 Pod) 長時間處於 Terminating 狀態。
  • 嘗試停止容器時,Kubelet 記錄會顯示 DeadlineExceeded 錯誤。
  • 節點的序列控制台記錄可能會顯示 hung tasks 相關核心訊息,或工作遭封鎖超過 120 秒。

原因:

程序等待 I/O 作業完成時會進入 D 狀態,且無法中斷。常見原因包括:

  • 遠端檔案系統速度緩慢或沒有回應,例如設定錯誤或過度負載的 NFS 共用區。
  • 節點本機磁碟的磁碟效能嚴重降低,或發生硬體 I/O 錯誤。

解決方法:

如要解決 D 狀態程序的問題,請找出 I/O 來源,然後選取下列任一選項來清除狀態:

標準叢集

  1. 找出卡住的程序,並判斷該程序正在等待什麼:

    1. 使用 SSH 連線至受影響的節點:

      gcloud compute ssh NODE_NAME \
          --zone ZONE \
          --project PROJECT_ID
      

      更改下列內容:

      • NODE_NAME:要連線的節點名稱。
      • ZONE:節點的 Compute Engine 可用區。
      • PROJECT_ID:您的專案 ID。
    2. 找出 D 狀態的任何程序:

      ps -eo state,pid,comm,wchan | grep '^D'
      

      輸出結果會與下列內容相似:

      D  12345  my-app      nfs_wait
      D  54321  data-writer io_schedule
      

      輸出內容不會有標頭。各欄依序代表:

      • 狀態
      • 程序 ID (PID)
      • 指令
      • 等待管道 (wchan)
    3. 檢查 wchan 欄,找出 I/O 來源:

      • 如果 wchan 欄包含 nfs 或 rpc 等字詞,表示程序正在等待 NFS 共用區。
      • 如果 wchan 欄包含 io_schedule、jbd2 或 ext4 等字詞,表示程序正在等待節點的本機開機磁碟。
    4. 如要進一步瞭解程序等待的哪些核心函式,請檢查程序的核心呼叫堆疊:

      cat /proc/PID/stack
      

      將 PID 替換為上一個步驟中找到的程序 ID。

  2. 重新啟動節點。重新啟動通常是清除 D 狀態程序最有效的方法。

    1. 清空節點。
    2. 刪除基礎 VM 執行個體。 GKE 通常會建立新的 VM 來取代。
  3. 清除立即問題後,請調查基礎儲存系統,避免問題再次發生。

    • 網路儲存空間 (NFS) 問題:使用儲存空間供應商的監控工具,檢查 GKE 節點與 NFS 伺服器之間是否有高延遲、伺服器端錯誤或網路問題。

    • 本機磁碟問題:在 Cloud Monitoring 查看 Compute Engine 執行個體的 compute.googleapis.com/instance/disk/throttled_read_ops_count 和 compute.googleapis.com/instance/disk/throttled_write_ops_count 指標,確認是否有 I/O 節流。

Autopilot 叢集

  1. 嘗試找出封鎖來源:

    在 Autopilot 叢集中,無法直接透過 SSH 存取節點,也無法執行 ps 或 cat /proc 等指令。您必須依據記錄和指標。

    1. 檢查節點記錄:在 Cloud Logging 中,分析受影響節點的記錄。依節點名稱和問題時間範圍篩選。尋找指出 I/O 錯誤、儲存空間逾時 (例如磁碟或 NFS) 或 CSI 驅動程式訊息的核心訊息。
    2. 檢查工作負載記錄:檢查在受影響節點上執行的 Pod 記錄。應用程式記錄檔可能會顯示與檔案作業、資料庫呼叫或網路儲存空間存取權相關的錯誤。
    3. 使用 Cloud Monitoring:雖然無法取得程序層級的詳細資料,但可以檢查節點層級的 I/O 問題。
  2. 觸發節點替換作業,清除狀態。

    您無法手動刪除基礎 VM。如要觸發替換作業,請排空節點。這項操作會封鎖節點並撤除 Pod。

    GKE 會自動偵測健康狀態不良的節點並啟動修復作業,通常是更換基礎 VM。

    如果節點在排空後仍處於停滯狀態,且未自動更換,請與 Cloud Customer Care 聯絡。

  3. 清除立即問題後,請調查基礎儲存系統,避免問題再次發生。

    • 本機磁碟問題:在 Cloud Monitoring 中查看 compute.googleapis.com/instance/disk/throttled_read_ops_count 和 compute.googleapis.com/instance/disk/throttled_write_ops_count 指標,確認是否有 I/O 節流。您可以針對節點集區的基礎執行個體群組篩選這些指標,但個別執行個體是由 Google 管理。
    • 網路儲存空間 (NFS) 問題:使用儲存空間供應商的監控工具,檢查 GKE 節點與 NFS 伺服器之間是否有高延遲、伺服器端錯誤或網路問題。在 Cloud Logging 中查看所有 CSI 驅動程式 Pod 的記錄。

排解核心元件故障問題

排除預期原因和資源不足後,問題可能出在節點的軟體或核心 Kubernetes 機制。如果容器執行階段等重要元件發生故障,就會出現 NotReady 狀態。如果核心 Kubernetes 健康狀態檢查機制 (例如節點租用系統) 發生故障,也可能導致這種情況。

解決容器執行階段問題

容器執行階段 (例如 containerd) 的問題可能會導致 kubelet 無法在節點上啟動 Pod。

問題:

如果 kubelet 記錄中出現下列訊息,節點的 NotReady 狀態很可能是由容器執行階段問題所導致:

  • Container runtime not ready
  • Container runtime docker failed!
  • docker daemon exited
  • 連線至執行階段通訊端時發生錯誤 (例如 unix:///var/run/docker.sock 或 unix:///run/containerd/containerd.sock)。

原因:

容器執行階段運作異常、設定錯誤,或陷入重新啟動迴圈。

解決方法:

如要解決容器執行階段問題,請按照下列步驟操作:

  1. 分析容器執行階段記錄:

    1. 前往 Google Cloud 控制台的「Logs Explorer」頁面。

      前往 Logs Explorer

    2. 如要在受影響的節點上查看所有容器執行階段的警告和錯誤記錄,請在查詢窗格中輸入下列內容:

      resource.type="k8s_node"
      resource.labels.node_name="NODE_NAME"
      resource.labels.cluster_name="CLUSTER_NAME"
      resource.labels.location="LOCATION"
      log_id("container-runtime")
      severity>=WARNING
      

      更改下列內容:

      • NODE_NAME:要調查的節點名稱。
      • CLUSTER_NAME:叢集名稱。
      • LOCATION:叢集的 Compute Engine 區域或可用區 (例如 us-central1 或 us-central1-a)。
    3. 按一下「Run query」(執行查詢),然後查看輸出內容,找出指出執行階段失敗原因的特定錯誤訊息。Cloud Logging 的 containerd 記錄中,如果出現 failed to load TOML 等訊息,通常表示檔案格式不正確。

    4. 如要檢查執行階段是否卡在重新啟動迴圈中,請執行查詢來搜尋啟動訊息。如果短時間內出現大量這類訊息,就表示經常重新啟動。

      resource.type="k8s_node"
      resource.labels.node_name="NODE_NAME"
      resource.labels.cluster_name="CLUSTER_NAME"
      resource.labels.location="LOCATION"
      log_id("container-runtime")
      ("starting containerd" OR "Containerd cri plugin version" OR "serving..."
      OR "loading plugin" OR "containerd successfully booted")
      

      如果服務經常重新啟動,通常表示有潛在問題,例如設定檔損毀或資源壓力,導致服務不斷異常終止。

  2. 檢查 containerd 設定是否有修改:設定有誤可能會導致容器執行階段失敗。您可以透過節點系統設定檔進行設定變更,也可以透過具有提升權限的工作負載直接修改設定。

    1. 判斷節點集區是否使用節點系統設定檔:

      gcloud container node-pools describe NODE_POOL_NAME \
          --cluster CLUSTER_NAME \
          --location LOCATION \
          --format="yaml(config.containerdConfig)"
      

      更改下列內容:

      • NODE_POOL_NAME:節點集區名稱。
      • CLUSTER_NAME:叢集名稱。
      • LOCATION:叢集的 Compute Engine 區域或可用區。

      如果輸出內容顯示 containerdConfig 區段,則表示 GKE 正在管理這些自訂設定。如要修改或還原設定,請按照「在 GKE 節點中自訂 containerd 設定」一文中的操作說明進行。

    2. 如果 GKE 代管的自訂設定未啟用,或您懷疑有其他變更,請尋找可能直接修改節點檔案系統的工作負載。尋找具有提升權限 (securityContext.privileged: true) 的 DaemonSet,或裝載 hostPath 磁碟區的 DaemonSet,這類磁碟區會裝載 /etc 等機密目錄。

      如要檢查設定,請以 YAML 格式列出所有 DaemonSet:

      kubectl get daemonsets --all-namespaces -o yaml
      

      查看輸出內容,並檢查任何可疑 DaemonSet 的記錄。

    3. 如果是 Standard 叢集,請直接檢查設定檔。在 Autopilot 叢集中,您無法使用 SSH 存取權,也無法手動檢查檔案,因為 Google 會管理執行階段設定。如果持續發生執行階段問題,請向 Google Cloud Customer Care 團隊回報。

      如果您使用的是 Standard 叢集,請檢查檔案:

      1. 使用 SSH 連線至節點:

        gcloud compute ssh NODE_NAME \
            --zone ZONE \
            --project PROJECT_ID
        

        更改下列內容:

        • NODE_NAME:要連線的節點名稱。
        • ZONE:節點的 Compute Engine 可用區。
        • PROJECT_ID:您的專案 ID。
      2. 顯示 containerd 設定檔的內容:

        sudo cat /etc/containerd/config.toml
        
      3. 如要查看近期修改,請列出檔案詳細資料:

        ls -l /etc/containerd/config.toml
        
    4. 比較這個檔案的內容與您在上一個步驟中執行的 gcloud node-pools describe 指令所產生的 containerdConfig 輸出內容。/etc/containerd/config.toml 中不在 gcloud 輸出內容中的任何設定,都是未受管理的變更。

    5. 如要修正任何設定錯誤,請移除未透過節點系統設定套用的變更。

  3. 排解常見的執行階段問題:如需更多疑難排解步驟,請參閱「排解容器執行階段問題」。

解決 kube-node-lease 命名空間的問題

kube-node-lease 命名空間中的資源負責維護節點健康狀態。請勿刪除這個命名空間。如果嘗試刪除這個命名空間,命名空間會卡在 Terminating 狀態。如果 kube-node-lease 命名空間停滯在 Terminating 狀態,kubelet 就無法續訂健康狀態檢查租約。這個問題會導致控制層將節點視為不健全,進而造成叢集範圍的問題,節點會在 Ready 和 NotReady 狀態之間交替。

症狀:

如果出現下列症狀,叢集範圍的不穩定性很可能是由 kube-node-lease 命名空間的問題所導致:

  • 每個節點上的 kubelet 記錄檔都會顯示類似下列內容的持續性錯誤:

    leases.coordination.k8s.io NODE_NAME is forbidden: unable to create new content in namespace kube-node-lease because it is being terminated
    
  • 叢集中的節點會反覆在 Ready 和 NotReady 狀態之間切換。

原因:

kube-node-lease 命名空間 (負責管理節點心跳) 異常停滯在 Terminating 狀態。這項錯誤會導致 Kubernetes API 伺服器禁止在命名空間內建立或修改物件。因此,kubelet 無法更新 Lease 物件,而這些物件是向控制層發出活躍度信號的必要條件。如果沒有這些狀態更新,控制層就無法確認節點是否健康,導致節點狀態在 Ready 和 NotReady 之間交替。

kube-node-lease 命名空間本身可能停滯在 Terminating 狀態的根本原因包括:

  • 具有終結器的資源:雖然系統 kube-node-lease 命名空間 (主要包含 Lease 物件) 較少發生這種情況,但其中的資源可能具有終結器。Kubernetes 終結器是金鑰,可發出訊號,指出控制器必須先執行清理工作,才能刪除資源。如果負責移除終結器的控制器無法正常運作,資源就不會遭到刪除,命名空間刪除程序也會停止。
  • 匯總 API 服務不健康或沒有回應:如果用於註冊匯總 API 伺服器的 APIService 物件連結至命名空間,且變得不健康,命名空間終止作業可能會遭到封鎖。控制層可能會等待匯總 API 伺服器正常關閉或清除,但如果服務沒有回應,就不會發生這種情況。
  • 控制層或控制器問題:在極少數情況下,Kubernetes 控制層 (尤其是命名空間控制器) 內的錯誤或問題,可能會導致垃圾回收和命名空間刪除作業失敗。

解析度:

請按照「排解命名空間卡在終止狀態的問題」中的指引操作。

疑難排解網路連線

網路問題可能會導致節點無法與控制層通訊,或導致 CNI 外掛程式等重要元件無法運作,進而造成 NotReady 狀態。

問題:

如果發現下列症狀,則節點的 NotReady 狀態可能是網路問題所致:

  • NetworkNotReady 條件為 True。
  • 節點上的 Kubelet 記錄檔會顯示類似下列的錯誤:
    • connection timeout to the control plane IP address
    • network plugin not ready
    • CNI plugin not initialized
    • 嘗試連線至控制層 IP 位址時,會收到 connection refused 或 timeout 訊息。
  • Pod (尤其是 kube-system 命名空間中的 Pod) 會停留在 ContainerCreating,並發生 NetworkPluginNotReady 等事件。

原因:

網路相關症狀通常表示下列其中一個領域發生故障:

  • 連線能力問題:節點無法與 Kubernetes 控制層建立穩定的網路連線。
  • CNI 外掛程式故障:負責設定 Pod 網路的 CNI 外掛程式未正確執行,或初始化失敗。
  • Webhook 問題:設定錯誤的許可控制 Webhook 可能會干擾 CNI 外掛程式相關資源,導致網路無法正確設定。

解決方法:

如要解決網路問題,請按照下列步驟操作:

  1. 解決暫時性 NetworkNotReady 狀態:在新建立的節點上,看到短暫的 NetworkNotReady 事件是正常現象。CNI 外掛程式和其他元件初始化時,這個狀態應該會在一兩分鐘內解決。如果狀態仍為「已取消」,請繼續執行下列步驟。

  2. 驗證節點至控制層的連線能力和防火牆規則:確認節點和控制層之間的網路路徑已開啟,且運作正常:

    1. 檢查防火牆規則:確認虛擬私有雲防火牆規則允許 GKE 節點與控制層之間必要的流量。如要瞭解 GKE 節點與控制層通訊所需的規則,請參閱「自動建立的防火牆規則」。
    2. 測試連線能力:使用 Network Intelligence Center 的Connectivity Tests,驗證節點內部 IP 位址與控制層端點 IP 位址在通訊埠 443 之間的網路路徑。Not Reachable 的結果通常有助於找出封鎖通訊的防火牆規則或轉送問題。
  3. 調查 CNI 外掛程式狀態和記錄:如果節點網路尚未就緒,可能是 CNI 外掛程式發生錯誤。

    1. 檢查 CNI Pod 狀態:找出使用的 CNI 外掛程式 (例如 netd 或 calico-node),並檢查 kube-system 命名空間中 Pod 的狀態。您可以使用下列指令篩選特定節點:

      kubectl get pods \
          -n kube-system \
          -o wide \
          --field-selector spec.nodeName=NODE_NAME \
          | grep -E "netd|calico|anetd"
      
    2. 檢查 CNI Pod 記錄:如果 Pod 無法正常運作,請在 Cloud Logging 中查看記錄,瞭解詳細錯誤訊息。如要查詢特定節點上的 netd Pod,請使用類似下列的查詢:

      resource.type="k8s_container"
      resource.labels.cluster_name="CLUSTER_NAME"
      resource.labels.location="LOCATION"
      resource.labels.namespace_name="kube-system"
      labels."k8s-pod/app"="netd"
      resource.labels.node_name="NODE_NAME"
      severity>=WARNING
      
    3. 解決特定 CNI 錯誤:

      • 如果記錄顯示 Failed to allocate IP address,表示 Pod IP 位址範圍可能已用盡。確認 Pod IP 位址使用率,並檢查叢集的 CIDR 範圍。
      • 如果記錄檔顯示 NetworkPluginNotReady 或 cni plugin not initialized,請確認節點的 CPU 和記憶體資源是否充足。您也可以嘗試刪除 CNI Pod,讓 DaemonSet 重新建立 Pod,藉此重新啟動 CNI Pod。
      • 如果您使用 GKE Dataplane V2,且記錄顯示 Cilium API client timeout exceeded,請重新啟動節點上的 anetd Pod。
    4. 檢查准入 Webhook 干擾:故障的 Webhook 可能會導致 CNI Pod 無法啟動,使節點處於 NetworkNotReady 狀態。

    5. 檢查 API 伺服器記錄:在 Cloud Logging 中檢查 API 伺服器記錄,找出與 Webhook 呼叫相關的錯誤。如要判斷 Webhook 是否會封鎖 CNI 資源建立作業,請搜尋類似 failed calling webhook 的訊息。

      如果 Webhook 造成問題,您可能需要找出有問題的 ValidatingWebhookConfiguration 或 MutatingWebhookConfiguration,並暫時停用,讓節點準備就緒。詳情請參閱「解決因准入 Webhook 造成的相關問題」。

疑難排解叢集設定錯誤問題

以下各節將協助您稽核部分叢集範圍的設定,這些設定可能會干擾正常的節點作業。

解決因准入 Webhook 導致的問題

如果准入 Webhook 設定錯誤、無法使用或速度過慢,可能會封鎖重要 API 要求,導致必要元件無法啟動,或節點無法加入叢集。

症狀:

如果發現下列跡象,可能是因為准入 Webhook 設定錯誤或無法使用,導致重要的叢集作業無法執行:

  • Pod (尤其是 kube-system 命名空間中的 Pod,例如 CNI 或儲存空間 Pod) 卡在 Pending 或 Terminating 狀態。
  • 新節點無法加入叢集,通常會因逾時而顯示 NotReady 狀態。

原因:

設定錯誤或沒有回應的許可控制 Webhook 可能會封鎖重要的叢集作業。

解析度:

請檢查 Webhook 設定,確保設定具有彈性且範圍適當。為避免服務中斷,請將非重要 Webhook 的 failurePolicy 欄位設為 Ignore。對於重要 Webhook,請確保其後端服務具有高可用性,並使用 namespaceSelector 排除 kube-system 命名空間的 Webhook 監督,避免控制層死結。詳情請參閱「使用 Webhook 時確保控制層穩定性」。

解決資源配額導致的問題

如果 kube-system 命名空間中的資源配額計算有誤,GKE 就無法建立重要的系統 Pod。由於網路 (CNI) 和 DNS 等元件遭到封鎖,這個問題可能會導致新節點無法成功加入叢集。

症狀:

  • kube-system 命名空間中的重要 Pod (例如 netd、konnectivity-agent 或 kube-dns) 停留在 Pending 狀態。
  • 叢集記錄或 kubectl describe pod 輸出內容中的錯誤訊息會顯示 exceeded quota: gcp-critical-pods 等失敗情形。

原因:

當 Kubernetes 資源配額控制器停止準確更新 ResourceQuota 物件中的用量計數時,就會發生這個問題。常見原因是第三方准入 Webhook 故障,導致控制器無法更新,配額用量因此會比實際用量高出許多。

解決方法:

  1. 由於有問題的 Webhook 最可能是根本原因,請按照「解決因准入 Webhook 導致的問題」一節中的指引,找出並修正可能封鎖系統元件的 Webhook。修正 Webhook 通常會自動解決配額問題。
  2. 確認配額記錄的用量與實際執行的 Pod 數量不同步。這個步驟會確認 ResourceQuota 物件數量是否不正確:

    1. 檢查配額的預定用途:

      kubectl get resourcequota gcp-critical-pods -n kube-system -o yaml
      
    2. 查看實際的 Pod 數量:

      kubectl get pods -n kube-system --no-headers | wc -l
      
  3. 如果 ResourceQuota 中的使用次數似乎不正確 (例如遠高於實際的 Pod 數量),請刪除 gcp-critical-pods 物件。GKE 控制層的設計目的,是使用正確的已調和用量計數,自動重新建立這個物件:

    kubectl delete resourcequota gcp-critical-pods -n kube-system
    
  4. 監控 kube-system 命名空間幾分鐘,確保物件已重新建立,且待處理的 Pod 開始排程。

解決第三方 DaemonSet 造成的問題

新部署或更新的第三方 DaemonSet (通常用於安全性、監控或記錄) 有時可能會導致節點不穩定。如果 DaemonSet 干擾節點的容器執行階段或網路,耗用過多系統資源,或進行非預期的系統修改,就可能發生這個問題。

症狀:

如果出現下列徵兆,可能是最近部署或修改的第三方 DaemonSet 導致節點故障:

  • DaemonSet 部署或更新後不久,叢集中可能有多個節點進入 NotReady 狀態。
  • 受影響節點的 Kubelet 記錄會回報類似下列的錯誤:
    • container runtime is down
    • Failed to create pod sandbox
    • 連線至容器執行階段通訊端時發生錯誤 (例如 /run/containerd/containerd.sock)。
  • Pod (包括系統 Pod 或 DaemonSet 自己的 Pod) 卡在 PodInitializing 或 ContainerCreating 狀態。
  • 應用程式的容器記錄顯示異常錯誤,例如 exec format error。
  • 節點問題偵測工具可能會回報與執行階段健康狀態或資源壓力相關的條件。

原因:

第三方 DaemonSet 可能會影響節點穩定性,原因如下:

  • 耗用過多 CPU、記憶體或磁碟 I/O,影響重要節點元件的效能。
  • 干擾容器執行階段的運作。
  • 與節點的網路設定或容器網路介面 (CNI) 外掛程式發生衝突。
  • 以非預期的方式更改系統設定或安全性政策。

解決方法:

如要判斷 DaemonSet 是否為原因,請隔離並測試:

  1. 找出 DaemonSet:列出叢集中執行的所有 DaemonSet:

    kubectl get daemonsets --all-namespaces
    

    請密切注意不屬於預設 GKE 安裝項目的 DaemonSet。

    您可以查看下列項目,找出這些 DaemonSet:

    • 命名空間:預設 GKE 元件通常會在 kube-system 命名空間中執行。其他命名空間中的 DaemonSet 可能是第三方或自訂項目。
    • 命名:預設 DaemonSet 通常會命名為 gke-metrics-agent、netd 或 calico-node。第三方代理程式的名稱通常會反映產品。
  2. 關聯部署時間:檢查 NotReady 節點的出現時間是否與特定第三方 DaemonSet 的部署或更新時間一致。

  3. 在單一節點上測試:

    1. 選擇一個受影響的節點。
    2. 限制並清空節點。
    3. 暫時禁止 DaemonSet 在這個節點上排程:
      • 套用臨時節點標籤,並在 DaemonSet 的資訊清單中設定節點親和性或反親和性。
      • 刪除該特定節點上的 DaemonSet Pod。
    4. 重新啟動節點的虛擬機器執行個體。
    5. 觀察節點是否會變成 Ready,並在 DaemonSet 未於節點上執行時保持穩定。如果重新導入 DaemonSet 後問題再次出現,則很可能是造成問題的原因。
  4. 諮詢供應商:如果懷疑第三方代理程式是造成問題的原因,請查看供應商的文件,瞭解已知的相容性問題,或在 GKE 上執行代理程式的最佳做法。如需進一步支援,請與軟體供應商聯絡。

確認節點已復原

套用可能的解決方案後,請按照下列步驟確認節點已成功復原且穩定:

  1. 查看節點狀態:

    kubectl get nodes -o wide
    

    在輸出內容中找出受影響的節點。Status 欄現在應會顯示 Ready 值。套用修正措施後,狀態可能需要幾分鐘才會更新。如果狀態仍顯示 NotReady 或在不同狀態之間循環,表示問題尚未完全解決。

  2. 檢查節點的 Conditions 區段:

    kubectl describe node NODE_NAME
    

    在 Conditions 區段中,確認下列值:

    • Ready 條件的狀態為 True。
    • 先前狀態為 True 的負面條件 (例如 MemoryPressure 或 NetworkUnavailable),現在狀態為 False。這些情況的 Reason 和 Message 欄位應指出問題已解決。
  3. 測試 Pod 排程。如果節點先前無法執行工作負載,請檢查是否已在節點上排程新的 Pod,以及現有 Pod 是否正常執行:

    kubectl get pods --all-namespaces -o wide --field-selector spec.nodeName=NODE_NAME
    

    節點上的 Pod 應處於 Running 或 Completed 狀態。Pod 不應卡在 Pending 或其他錯誤狀態。

後續步驟