排解 Autopilot 叢集問題

Google Kubernetes Engine (GKE) Autopilot 叢集的問題可能會影響應用程式的可用性和作業效率。這些問題可能會中斷應用程式的整個生命週期,從初始部署到負載下的資源調度都可能受到影響。

您可以在這個頁面診斷及解決 Autopilot 叢集的常見問題。瞭解如何排解叢集建立問題 (防止叢集佈建)、資源調度問題 (例如 out of resources 錯誤),以及工作負載專屬問題 (例如臨時儲存空間錯誤或 Pod 卡在 Pending 狀態)。

這項資訊對於應用程式開發人員來說非常重要,因為他們需要確保應用程式能順利部署及執行;對於平台管理員和營運人員來說也很重要,因為他們負責 Autopilot 叢集的整體健康狀態和資源管理。如要進一步瞭解 Google Cloud 內容中提及的常見角色和工作範例,請參閱「常見的 GKE 使用者角色和工作」。

叢集問題

無法建立叢集:已註冊 0 個節點

如果您嘗試使用已停用或沒有必要權限的 IAM 服務帳戶建立 Autopilot 叢集,就會發生下列問題。建立叢集失敗,並顯示下列錯誤訊息:

All cluster resources were brought up, but: only 0 nodes out of 2 have registered.

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

  1. 檢查預設的 Compute Engine 服務帳戶或要使用的自訂 IAM 服務帳戶是否已停用:

    gcloud iam service-accounts describe SERVICE_ACCOUNT
    

    將 SERVICE_ACCOUNT 替換成服務帳戶電子郵件地址,例如 my-iam-account@my-first-project.iam.gserviceaccount.com。

    如果服務帳戶已停用,輸出結果會與下列內容相似:

    disabled: true
    displayName: my-service-account
    email: my-service-account@my-project.iam.gserviceaccount.com
    ...
    
  2. 如果服務帳戶已停用,請啟用:

    gcloud iam service-accounts enable SERVICE_ACCOUNT
    

如果服務帳戶已啟用,但錯誤仍存在,請授予服務帳戶 GKE 的最低必要權限:

gcloud projects add-iam-policy-binding PROJECT_ID \
    --member "serviceAccount:SERVICE_ACCOUNT" \
    --role roles/container.defaultNodeServiceAccount

叢集節點數量為 0 時,命名空間卡在「Terminating」狀態

如果叢集縮減至零個節點,然後您刪除叢集中的命名空間,就會發生下列問題。metrics-server 元件無法接受命名空間刪除要求,因為該元件沒有任何副本。

如要診斷這個問題,請執行下列指令:

kubectl describe ns/NAMESPACE_NAME

將 NAMESPACE_NAME 替換為命名空間名稱。

輸出內容如下:

Discovery failed for some groups, 1 failing: unable to retrieve the complete
list of server APIs: metrics.k8s.io/v1beta1: the server is currently unable to
handle the request

如要解決這個問題,請調高任一工作負載的規模,觸發 GKE 建立新節點。節點就緒後,系統會自動完成命名空間刪除要求。GKE 刪除命名空間後,請將工作負載縮減至原先大小。

資源調度問題

節點擴充作業失敗:Pod 可能無法排定

如果Google Cloud 專案停用序列埠記錄功能,就會發生下列問題。GKE Autopilot 叢集需要序列埠記錄功能,才能有效偵錯節點問題。如果停用序列埠記錄功能,Autopilot 就無法佈建節點來執行工作負載。

Kubernetes 事件記錄中的錯誤訊息類似於下列內容:

LAST SEEN   TYPE      REASON          OBJECT                          MESSAGE
12s         Warning   FailedScaleUp   pod/pod-test-5b97f7c978-h9lvl   Node scale up in zones associated with this pod failed: Internal error. Pod is at risk of not being scheduled

機構政策可能會強制執行compute.disableSerialPortLogging限制,導致機構層級的序列埠記錄功能遭到停用。您也可以在專案或虛擬機器 (VM) 執行個體層級停用序列埠記錄功能。

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

  1. 請要求 Google Cloud 組織政策管理員,在 Autopilot 叢集所在的專案中移除 compute.disableSerialPortLogging 限制。
  2. 如果沒有強制執行這項限制的組織政策,請嘗試在專案中繼資料中啟用序列埠記錄功能。必須具備 compute.projects.setCommonInstanceMetadata IAM 權限,才能執行這項操作。

節點無法向上擴充:Compute Engine 資源不足

如果工作負載要求的資源量超過 Compute Engine 區域或可用區的可用資源量,就會發生下列問題。Pod 可能會維持在 Pending 狀態。

  • 檢查 Pod 事件:

    kubectl events --for='pod/POD_NAME' --types=Warning
    

    將 RESOURCE_NAME 替換為待處理 Kubernetes 資源的名稱。例如 pod/example-pod。

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

    LAST SEEN         TYPE            REASON                  OBJECT                   Message
    19m               Warning         FailedScheduling        pod/example-pod          gke.io/optimize-utilization-scheduler  0/2 nodes are available: 2 node(s) didn't match Pod's node affinity/selector. preemption: 0/2 nodes are available: 2 Preemption is not helpful for scheduling.
    14m               Warning         FailedScheduling        pod/example-pod          gke.io/optimize-utilization-scheduler  0/2 nodes are available: 2 node(s) didn't match Pod's node affinity/selector. preemption: 0/2 nodes are available: 2 Preemption is not helpful for scheduling.
    12m (x2 over 18m) Warning         FailedScaleUp           cluster-autoscaler       Node scale up in zones us-central1-f associated with this pod failed: GCE out of resources. Pod is at risk of not being scheduled.
    34s (x3 over 17m) Warning         FailedScaleUp           cluster-autoscaler       Node scale up in zones us-central1-b associated with this pod failed: GCE out of resources. Pod is at risk of not being scheduled.
    

如要解決這個問題,請嘗試下列做法:

  • 在其他區域或可用區部署 Pod。如果 Pod 有區域限制 (例如拓撲選取器),請盡可能移除限制。如需操作說明,請參閱「將 GKE Pod 放在特定可用區」。
  • 在其他區域建立叢集,然後重新部署。
  • 請改用其他運算類別。如果運算類別採用較小的 Compute Engine 機型,就越有可能有可用資源。舉例來說,Autopilot 的預設機型可用性最高。如需運算類別和對應機器類型的清單,請參閱「何時使用特定運算類別」。
  • 如果您執行 GPU 工作負載,要求的 GPU 可能無法在節點位置使用。請嘗試在其他位置部署工作負載,或要求其他類型的 GPU。

為避免日後因資源可用性而發生擴充問題,請考慮採用下列方法:

節點無法擴充資源:Pod 可用區資源超出上限

如果新節點會違反資源限制,Autopilot 就不會為特定可用區中的 Pod 佈建新節點,進而導致下列問題。

記錄中的錯誤訊息大致如下:

    "napFailureReasons": [
            {
              "messageId": "no.scale.up.nap.pod.zonal.resources.exceeded",
              ...

這項錯誤是指noScaleUp事件,其中自動佈建節點功能並未針對可用區內的 Pod 佈建任何節點群組。

如果遇到這項錯誤,請確認下列事項:

工作負載排定在舊版機器系列上執行,或因儲存空間不相容而處於 Pending 狀態

如果有狀態工作負載使用較早的 Persistent Disk 磁碟區類型,例如標準永久磁碟 (pd-standard) 或 SSD 永久磁碟 (pd-ssd) 磁碟區,就會發生這個問題。這些磁碟區類型與 C3 或 E4 等較新的機器系列不相容。

這個問題會以以下兩種方式呈現:

  • 症狀 1:您預期在較新的一般用途機器系列 (例如 C3) 上執行的工作負載,卻自動排定在 E2 節點上。
  • 徵兆 2:明確要求較新機器系列的 Pod (例如使用 nodeSelector 欄位或自訂 ComputeClass) 仍處於 Pending 狀態。

根本原因

GKE Autopilot 會強制執行所要求儲存空間類型與節點機器系列的相容性。較新的機器系列 (例如 C3 和 E4) 需要 Google Cloud Hyperdisk 儲存空間 (例如 hyperdisk-balanced 磁碟類型)。這些機器系列不支援較早的永久磁碟磁碟區類型,例如標準永久磁碟 (pd-standard) 或 SSD 永久磁碟 (pd-ssd) 磁碟區。

  • 如果未指定機器系列,GKE Autopilot 會自動將工作負載排程至 E2 節點,因為 E2 節點支援這些永久磁碟磁碟區類型。工作負載會自動從預設的新硬體改回舊硬體。
  • 如果您明確要求使用較新的機器系列 (例如 C3 或 E4),但附加較早的永久磁碟區類型 (例如標準永久磁碟 (pd-standard) 或 SSD 永久磁碟 (pd-ssd) 磁碟區),GKE Autopilot 就無法同時滿足這兩項要求。Pod 會卡在 Pending 狀態。

驗證

如要確認工作負載是否受到這項相容性限制影響,請執行下列步驟:

  1. 檢查 Pod 的磁碟區設定,確認是否使用較舊的 Persistent Disk 磁碟區類型,例如標準永久磁碟 (pd-standard) 或 SSD 永久磁碟 (pd-ssd) 磁碟區。
  2. 如果 Pod 停滯在 Pending 狀態,請檢查叢集自動配置器可視性記錄。尋找節點自動佈建 (NAP) 評估記錄,類似於下列內容:

    NAP: injected node groups for requirements...
    
  3. 檢查 families="..." 清單的記錄訊息,檢查清單中是否缺少較新的機器系列 (例如 e4 或 c3 ID)。如果缺少 ID,表示 GKE 在排程期間因儲存空間需求而篩除這些家庭。e4 ID 用於 E4 機器系列的內部記錄。

解析度

如要解決這個問題,請採取下列任一做法:

  • 使用 Hyperdisk 儲存空間:更新 StorageClass 或磁碟區定義,改用與新版機器系列相容的 Google Cloud Hyperdisk 儲存空間 (例如 hyperdisk-balanced 磁碟類型)。
  • 允許在舊版系列上排程:如要使用較舊的 Persistent Disk 磁碟區類型 (例如標準永久磁碟 (pd-standard) 或 SSD 永久磁碟 (pd-ssd) 磁碟區),請移除對較新機器系列的任何明確要求 (例如 nodeSelector 欄位或自訂 ComputeClass)。移除這些要求後,GKE Autopilot 就能在 E2 等相容節點上排定 Pod。

工作負載問題

工作負載因臨時儲存空間錯誤而卡住

如果 Pod 暫時性儲存空間要求超過 GKE 1.28.6-gke.1317000 以上版本 Autopilot 的 10GiB 上限,GKE 就不會建立 Pod。

如要診斷這個問題,請說明工作負載控制器,例如 Deployment 或 Job:

kubectl describe CONTROLLER_TYPE/CONTROLLER_NAME

更改下列內容:

  • CONTROLLER_TYPE:工作負載控制器類型,例如 replicaset 或 daemonset。如需控制器類型清單,請參閱「工作負載管理」。
  • CONTROLLER_NAME:停滯的工作負載名稱。

如果 Pod 因暫時性儲存空間要求超出上限而未建立,輸出內容會類似於下列內容:

# lines omitted for clarity

Events:

{"[denied by autogke-pod-limit-constraints]":["Max ephemeral-storage requested by init containers for workload '' is higher than the Autopilot maximum of '10Gi'.","Total ephemeral-storage requested by containers for workload '' is higher than the Autopilot maximum of '10Gi'."]}

如要解決這個問題,請更新臨時儲存空間要求,確保工作負載容器和 Webhook 插入的容器要求的臨時儲存空間總量,小於或等於允許的上限。如要進一步瞭解上限,請參閱「Autopilot 中的資源要求」一文,瞭解工作負載設定。

Pod 卡在「Pending」狀態

如果您選取特定節點供 Pod 使用,但 Pod 和必須在節點上執行的 DaemonSet 中的資源要求總和,超過節點可分配的最大容量,Pod 可能會停滯在 Pending 狀態。這可能會導致 Pod 進入 Pending 狀態,且仍未排定。

為避免發生這個問題,請評估已部署工作負載的大小,確保這些工作負載符合 Autopilot 的資源要求上限。

您也可以先排定 DaemonSet,再排定一般工作負載 Pod。

特定節點的工作負載效能持續不穩定

在 GKE 1.24 以上版本中,如果特定節點上的工作負載持續發生中斷、當機或類似的不穩定行為,您可以使用下列指令封鎖該節點,向 GKE 回報問題:

kubectl drain NODE_NAME --ignore-daemonsets

將 NODE_NAME 替換為有問題的節點名稱。您可以執行 kubectl get nodes 找出節點名稱。

GKE 會執行下列動作:

  • 從節點中剔除現有工作負載,並停止在該節點上排定工作負載。
  • 自動在其他節點上,重新建立由控制器 (例如 Deployment 或 StatefulSet) 管理的任何遭逐出工作負載。
  • 終止節點上剩餘的任何工作負載,並在一段時間後修復或重新建立節點。
  • 如果您使用 Autopilot,GKE 會立即關閉並更換節點,並忽略任何已設定的 PodDisruptionBudget。

Pod 在空白叢集上排定的時間超出預期

當您將工作負載部署至沒有其他工作負載的 Autopilot 叢集時,就會發生這個事件。Autopilot 叢集一開始沒有可用的節點,如果叢集是空的,則會縮減至零個節點,避免叢集中有未使用的運算資源。在節點數為零的叢集中部署工作負載,會觸發擴充事件。

如果發生這種情況,表示 Autopilot 運作正常,您不需採取任何行動。新節點啟動後,工作負載就會如預期部署。

檢查 Pod 是否在等待新節點:

  1. 描述待處理的 Pod:

    kubectl describe pod POD_NAME
    

    將 POD_NAME 替換為待處理 Pod 的名稱。

  2. 檢查輸出內容的 Events 區段。如果 Pod 正在等待新節點,輸出內容會與下列內容相似:

    Events:
      Type     Reason            Age   From                                   Message
      ----     ------            ----  ----                                   -------
      Warning  FailedScheduling  11s   gke.io/optimize-utilization-scheduler  no nodes available to schedule pods
      Normal   TriggeredScaleUp  4s    cluster-autoscaler                     pod triggered scale-up: [{https://www.googleapis.com/compute/v1/projects/example-project/zones/example-zone/instanceGroups/gk3-example-cluster-pool-2-9293c6db-grp 0->1 (max: 1000)} {https://www.googleapis.com/compute/v1/projects/example-project/zones/example-zone/instanceGroups/gk3-example-cluster-pool-2-d99371e7-grp 0->1 (max: 1000)}]
    

    TriggeredScaleUp 事件顯示叢集正在擴充,從零個節點增加到執行已部署工作負載所需的節點數量。

系統 Pod 無法在空白叢集上排程

當叢集中沒有任何工作負載執行時,就會發生這個事件,導致叢集縮減至零個節點。Autopilot 叢集一開始沒有可用的節點,如果叢集中沒有執行任何工作負載,則會縮減至零個節點。這項行為可盡量減少叢集中浪費的運算資源。

當叢集縮減至零個節點時,GKE 系統工作負載不會排程,並會維持在 Pending 狀態。這是預設行為,無須採取任何行動。下次將工作負載部署至叢集時,GKE 會擴充叢集,而待處理的系統 Pod 則會在這些節點上執行。

如要檢查系統 Pod 是否因叢集空白而處於待處理狀態,請執行下列操作:

  1. 檢查叢集是否有任何節點:

    kubectl get nodes
    

    輸出內容如下,表示叢集有零個節點:

    No resources found
    
  2. 檢查系統 Pod 的狀態:

    kubectl get pods --namespace=kube-system
    

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

    NAME                                                       READY   STATUS    RESTARTS   AGE
    antrea-controller-horizontal-autoscaler-6d97f7cf7c-ngfd2   0/1     Pending   0          9d
    egress-nat-controller-84bc985778-6jcwl                     0/1     Pending   0          9d
    event-exporter-gke-5c5b457d58-7njv7                        0/2     Pending   0          3d5h
    event-exporter-gke-6cd5c599c6-bn665                        0/2     Pending   0          9d
    konnectivity-agent-694b68fb7f-gws8j                        0/2     Pending   0          3d5h
    konnectivity-agent-7d659bf64d-lp4kt                        0/2     Pending   0          9d
    konnectivity-agent-7d659bf64d-rkrw2                        0/2     Pending   0          9d
    konnectivity-agent-autoscaler-5b6ff64fcd-wn7fw             0/1     Pending   0          9d
    konnectivity-agent-autoscaler-cc5bd5684-tgtwp              0/1     Pending   0          3d5h
    kube-dns-65ccc769cc-5q5q7                                  0/5     Pending   0          3d5h
    kube-dns-7f7cdb9b75-qkq4l                                  0/5     Pending   0          9d
    kube-dns-7f7cdb9b75-skrx4                                  0/5     Pending   0          9d
    kube-dns-autoscaler-6ffdbff798-vhvkg                       0/1     Pending   0          9d
    kube-dns-autoscaler-8b7698c76-mgcx8                        0/1     Pending   0          3d5h
    l7-default-backend-87b58b54c-x5q7f                         0/1     Pending   0          9d
    metrics-server-v1.31.0-769c5b4896-t5jjr                    0/1     Pending   0          9d
    
  3. 查看系統 Pod 處於 Pending 狀態的原因:

    kubectl describe pod --namespace=kube-system SYSTEM_POD_NAME
    

    將 SYSTEM_POD_NAME 替換為前一個指令輸出內容中的任何系統 Pod 名稱。

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

    ...
    Events:
    Type     Reason            Age                       From               Message
    ----     ------            ----                      ----               -------
    Warning  FailedScheduling  4m35s (x27935 over 3d5h)  default-scheduler  no nodes available to schedule pods
    ...
    

    在輸出內容中,FailedScheduling 事件的 Message 欄位中的 no nodes available to schedule pods 值表示系統 Pod 未排程,因為叢集是空的。

在 GKE Autopilot 叢集中,您無法存取基礎節點。因此,您必須從 Pod 內執行 tcpdump 公用程式,然後使用 kubectl cp 指令複製。如果您通常從 GKE Autopilot 叢集的 Pod 內執行 tcpdump 公用程式,可能會看到下列錯誤:

    tcpdump: eth0: You don't have permission to perform this capture on that device
    (socket: Operation not permitted)

這是因為 GKE Autopilot 預設會將安全環境套用至所有 Pod,捨棄 NET_RAW 功能,以降低潛在安全漏洞風險。例如:

apiVersion: v1
kind: Pod
metadata:
  labels:
    app: tcpdump
  name: tcpdump
spec:
  containers:
  - image: nginx
    name: nginx
    resources:
      limits:
        cpu: 500m
        ephemeral-storage: 1Gi
        memory: 2Gi
      requests:
        cpu: 500m
        ephemeral-storage: 1Gi
        memory: 2Gi
    securityContext:
      capabilities:
        # This section drops NET_RAW to mitigate security vulnerabilities
        drop:
        - NET_RAW

為解決這個問題,如果工作負載需要 NET_RAW 功能,可以重新啟用:

  1. 在 Pod 的 YAML 規格的 securityContext 區段中新增 NET_RAW 功能:

    securityContext:
      capabilities:
        add:
        - NET_RAW
    
  2. 從 Pod 內執行 tcpdump:

    tcpdump port 53 -w packetcap.pcap
    tcpdump: listening on eth0, link-type EN10MB (Ethernet), snapshot length 262144 bytes
    
  3. 使用 kubectl cp 指令將檔案複製到本機電腦,以便進一步分析:

    kubectl cp POD_NAME:/PATH_TO_FILE/FILE_NAME/PATH_TO_FILE/FILE_NAME
    
  4. 使用 kubectl exec 執行 tcpdump 指令,擷取網路封包並重新導向輸出內容:

    kubectl exec -it POD_NAME -- bash -c "tcpdump port 53 -w -" > packet-new.pcap
    

由於 NRI RunPodSandbox 失敗,Pod 無法在節點上執行

在極少數情況下,預設、Balanced、Scale-Out、autopilot 和 autopilot-spot 運算類別中的 Autopilot 節點可能會進入某種狀態,導致系統 Pod (例如 anetd) 和指派給該節點的使用者 Pod 無法轉換為執行中狀態。如果 anetd 無法轉換為執行中狀態,表示節點上的 Pod 網路部分或完全中斷。只有在特定叢集控制層升級期間,才會觸發這個錯誤狀態。

如果發現這個問題,可以按照緩解特定節點上不可靠的工作負載效能程序,在特定節點上緩解這個問題。

為避免問題再次發生,請手動將叢集升級至下列任一 GKE 修補程式版本:

  • 1.35:所有修補程式版本
  • 1.34:1.34.1-gke.3899000 以上版本
  • 1.33:1.33.5-gke.2392000 以上版本

如果懷疑節點處於這項錯誤狀態,請按照下列步驟確認:

  1. 找出在疑似有問題的節點上執行的 efficiency-daemon Pod:

    DAEMON_POD_NAME=$(kubectl get pods \
      --namespace kube-system \
      --selector k8s-app=efficiency-daemon \
      --field-selector spec.nodeName=NODE_NAME \
      --output custom-columns=":metadata.name" \
      --no-headers)
    echo $DAEMON_POD_NAME
    

    如果節點上沒有 efficiency-daemon Pod,表示節點不受這個特定問題影響。

  2. 檢查 efficiency-daemon Pod 是否有特定錯誤:

    kubectl logs -n kube-system $DAEMON_POD_NAME | grep "connect: operation not permitted" | wc -l
    

    如果輸出內容大於 10,節點很可能受到這個問題影響。

如果指派給節點的 Pod 持續在 Pod 事件中顯示下列錯誤訊息,表示節點受到這個問題影響:Failed to create pod sandbox: rpc error: code = Unknown desc = NRI RunPodSandbox failed: rpc error: code = Unknown desc = internal error: reconciliation failed。

後續步驟