排解 GKE Standard 節點集區的疑難

管理 Google Kubernetes Engine (GKE) Standard 叢集時,節點集區的問題可能會中斷重要作業。這些問題可能會導致您無法擴充工作負載來滿足需求,或執行重要的基礎架構升級,進而影響應用程式的可靠性。

請參閱本頁內容,排解這些常見的節點集區問題。瞭解如何確認資源是否不足、使用盡力佈建等功能建立節點,以及安全地遷移工作負載,避免造成中斷。

這項資訊對負責管理叢集基礎架構的平台管理員和營運人員非常重要。此外,應用程式開發人員也能藉此瞭解節點集區限制對應用程式部署作業的影響。如要進一步瞭解我們在 Google Cloud 內容中提及的常見角色和範例工作,請參閱「常見的 GKE 使用者角色和工作」。

節點集區建立問題

本節列出在標準叢集中建立新節點集區時可能會發生的問題,並提供相應的修正建議。

問題:資源不足,因此無法建立節點集區

在 Google Cloud 區域中建立具有特定硬體的節點集區時,如果該區域的可用硬體不足以滿足您的需求,就會發生下列問題。

如要驗證節點集區建立作業失敗是否是因為區域資源不足,請檢查記錄檔中是否有相關錯誤訊息。

  1. 前往 Google Cloud 控制台的「Logs Explorer」:

    前往「Logs Explorer」頁面

  2. 在「Query」(查詢) 欄位中,指定下列查詢:

    log_id(cloudaudit.googleapis.com/activity)
    resource.labels.cluster_name="CLUSTER_NAME"
    protoPayload.status.message:("ZONE_RESOURCE_POOL_EXHAUSTED" OR "does not have enough resources available to fulfill the request" OR "resource pool exhausted" OR "does not exist in zone")
    

    將 CLUSTER_NAME 替換為 GKE 叢集的名稱。

  3. 點選「執行查詢」。

你可能會看到下列其中一則錯誤訊息:

  • resource pool exhausted
  • The zone does not have enough resources available to fulfill the request. Try a different zone, or try again later.
  • ZONE_RESOURCE_POOL_EXHAUSTED
  • ZONE_RESOURCE_POOL_EXHAUSTED_WITH_DETAILS
  • Machine type with name 'MACHINE_NAME' does not exist in zone 'ZONE_NAME'

如要解決這個問題,請嘗試下列建議:

  • 確認所選 Google Cloud 區域或地區有您需要的特定硬體。請參閱 Compute Engine 可用性表,確認特定區域是否支援特定硬體。為節點選擇其他Google Cloud 區域或可用區,這些區域或可用區可能提供您需要的硬體,且可用性較高。
  • 使用較小的機型建立節點集區。增加節點集區中的節點數量,讓總運算容量維持不變。
  • 使用 Compute Engine 容量預留項目預先預留資源。
  • 如果系統能從要求數量中,佈建至少指定數量的節點,請使用下一節所述的盡力佈建功能,順利建立節點集區。

盡力佈建

對於特定硬體,您可以使用「盡量佈建」,這會告知 GKE,如果可以佈建至少指定數量的節點,就成功建立節點集區。GKE 會持續嘗試佈建其餘節點,以滿足原始要求。如要告知 GKE 使用盡量供應資源的機制,請使用下列指令:

gcloud container node-pools create NODE_POOL_NAME \
    --cluster=CLUSTER_NAME \
    --location=CONTROL_PLANE_LOCATION \
    --node-locations=ZONE1,ZONE2,... \
    --machine-type=MACHINE_TYPE
    --best-effort-provision \
    --min-provision-nodes=MINIMUM_NODES

更改下列內容:

  • NODE_POOL_NAME:新節點集區的名稱。
  • CONTROL_PLANE_LOCATION:叢集控制層的 Compute Engine 位置。如果是地區叢集,請提供區域;如果是區域叢集,請提供可用區。
  • ZONE1,ZONE2,...:節點的 Compute Engine 區域。這些可用區必須支援所選硬體。
  • MACHINE_TYPE:節點的 Compute Engine 引擎機型。例如:a2-highgpu-1g。
  • MINIMUM_NODES:GKE 佈建節點並成功建立節點集區時,節點數量下限。如未填寫此欄位,則預設值為 1。

舉例來說,假設您需要在 us-central1-c 中使用 10 個節點,並附加 NVIDIA A100 40GB GPU。根據「GPU 位置」,這個區域支援 A100 GPU。如要避免因沒有 10 部 GPU 電腦而無法建立節點集區,請使用盡力佈建。

gcloud container node-pools create a100-nodes \
    --cluster=ml-cluster \
    --location=us-central1 \
    --node-locations=us-central1-c \
    --num-nodes=10 \
    --machine-type=a2-highgpu-1g \
    --accelerator=type=nvidia-tesla-a100,count=1 \
    --best-effort-provision \
    --min-provision-nodes=5

即使 us-central1-c 中只有五個 GPU 可用,GKE 仍會建立節點集區。隨著時間推移,GKE 會嘗試佈建更多節點,直到節點集區中有 10 個節點為止。

錯誤:執行個體不含「instance-template」中繼資料

如果節點集區無法升級、調度資源或執行自動節點修復作業,您可能會看到下列錯誤訊息:

Instance INSTANCE_NAME does not contain 'instance-template' metadata

這項錯誤表示 GKE 分配的 VM 執行個體中繼資料已損毀。如果自訂的自動化程序或指令碼嘗試新增執行個體中繼資料 (例如 block-project-ssh-keys),但除了新增或更新值之外,還刪除現有中繼資料,通常就會發生這種情況。如要瞭解 VM 執行個體中繼資料,請參閱「設定自訂中繼資料」。

如果刪除任何重要中繼資料值 (包括 instance-template、kube-labels、kubelet-config、kubeconfig、cluster-name、configure-sh、cluster-uid 等),節點或整個節點集區可能會進入不穩定狀態,因為這些值對 GKE 作業至關重要。

如果執行個體中繼資料已損毀,建議您重新建立含有損毀 VM 執行個體的節點集區,藉此復原中繼資料。您必須在叢集中新增節點集區,並增加新節點集區的節點數量,同時限制並移除其他節點集區的節點。請參閱這篇文章的操作說明,瞭解如何在節點集區之間遷移工作負載。

如要瞭解執行個體中繼資料的編輯者和編輯時間,請查看 Compute Engine 稽核記錄資訊,或使用 Logs Explorer 執行類似下列的搜尋查詢,找出相關記錄:

resource.type="gce_instance_group_manager"
protoPayload.methodName="v1.compute.instanceGroupManagers.setInstanceTemplate"

您可以在記錄中找到要求發起者的 IP 位址和使用者代理程式。例如:

requestMetadata: {
  callerIp: "REDACTED"
  callerSuppliedUserAgent: "google-api-go-client/0.5 GoogleContainerEngine/v1"
}

在節點集區之間遷移工作負載

請按照下列操作說明,將工作負載從一個節點集區遷移至另一個節點集區。如要變更節點集區中節點的機器屬性,請參閱變更節點機器屬性以垂直擴展。

瞭解如何將 Pod 遷移至新的節點集區

如要將 Pod 遷移至新的節點集區,請執行下列步驟:

  1. 隔離現有節點集區中的節點:此作業會將現有節點集區中的節點標示為「不可排程」。當節點被標示為「不可排程」時,Kubernetes 即會停止將新 Pod 排入這些節點中。

  2. 清空現有節點集區中的節點:此作業會正常清空在現有節點集區的節點上執行的工作負載。

針對每個節點個別執行這些步驟,可讓現有節點集區中執行的 Pod 正常終止。Kubernetes 會將 Pod 重新排程到其他可用的節點上。

為確保 Kubernetes 會正常終止您的應用程式,您的容器需處理 SIGTERM 信號。使用這種方法可關閉連到用戶端的作用中連線,並乾淨地執行或回溯資料庫交易。在 Pod 資訊清單中,您可以使用 spec.terminationGracePeriodSeconds 欄位,指定 Kubernetes 在停止 Pod 中的容器之前必須等待的時間長度。預設為 30 秒。請參閱 Kubernetes 說明文件,進一步瞭解終止 Pod。

您可以使用 kubectl cordon 和 kubectl drain 指令,封鎖及排空節點。

建立節點集區並遷移工作負載

如要將工作負載遷移至新的節點集區,請建立新的節點集區,然後封鎖並清空現有節點集區中的節點:

  1. 為叢集新增節點集區。

    執行下列指令,確認新的節點集區已建立:

    gcloud container node-pools list --cluster CLUSTER_NAME \
        --location=CONTROL_PLANE_LOCATION
    

    更改下列內容:

    • CLUSTER_NAME:叢集名稱。
    • CONTROL_PLANE_LOCATION:叢集控制層的 Compute Engine 位置。如果是地區叢集,請提供區域;如果是區域叢集,請提供可用區。
  2. 如要停用現有節點集區的自動調度資源功能 (如果已啟用),請執行下列指令:

    gcloud container clusters update CLUSTER_NAME
        --location=CONTROL_PLANE_LOCATION \
        --no-enable-autoscaling \
        --node-pool=EXISTING_NODE_POOL_NAME
    
  3. 執行以下指令,查看 Pod 目前在哪個節點上執行 (請見 NODE 欄):

    kubectl get pods -o=wide
    
  4. 取得現有節點集區中的節點清單,並將 EXISTING_NODE_POOL_NAME 取代為名稱:

    kubectl get nodes -l cloud.google.com/gke-nodepool=EXISTING_NODE_POOL_NAME
    
  5. 執行 kubectl cordon NODE 指令 (將 NODE 換成在上個指令取得的名稱),以下殼層指令會查看現有節點集區中的每個節點,並將節點標示為不可排程:

    for node in $(kubectl get nodes -l cloud.google.com/gke-nodepool=EXISTING_NODE_POOL_NAME -o=name); do
      kubectl cordon "$node";
    done
    
  6. 您可以視需要更新現有節點集區上執行的工作負載,為標籤 cloud.google.com/gke-nodepool:NEW_NODE_POOL_NAME 新增 nodeSelector,其中 NEW_NODE_POOL_NAME 是新節點集區的名稱。這有助於確保 GKE 將這些工作負載放置在新節點集區的節點上。

  7. 清空每個節點,方法是在 10 秒的終止寬限期後移除所有 Pod:

    for node in $(kubectl get nodes -l cloud.google.com/gke-nodepool=EXISTING_NODE_POOL_NAME -o=name); do
      kubectl drain --force --ignore-daemonsets --delete-emptydir-data --grace-period=GRACEFUL_TERMINATION_SECONDS  "$node";
    done
    

    將 GRACEFUL_TERMINATION_PERIOD_SECONDS 替換為正常終止所需的時長。

  8. 執行下列指令,確認現有節點集區中的節點在節點清單中處於 SchedulingDisabled 狀態:

    kubectl get nodes
    

    此外,您應該會看到 Pod 現在已在新節點集區的節點上執行:

    kubectl get pods -o=wide
    
  9. 刪除現有的節點集區 (如不需要):

    gcloud container node-pools delete default-pool --cluster CLUSTER_NAME \
        --location=CONTROL_PLANE_LOCATION
    

後續步驟