排解 GKE Standard 節點集區問題


本頁說明如何解決 GKE 標準模式節點集區的問題。

節點集區建立問題

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

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

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

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

  1. 前往 Google Cloud 控制台的「記錄檔探索工具」:

    前往「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 \
    --node-locations=ZONE1,ZONE2,... \
    --machine-type=MACHINE_TYPE
    --best-effort-provision \
    --min-provision-nodes=MINIMUM_NODES

更改下列內容:

  • NODE_POOL_NAME:新節點集區的名稱。
  • 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 \
    --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-templatekube-labelskubelet-configkubeconfigcluster-nameconfigure-shcluster-uid 等),節點或整個節點集區可能會進入不穩定狀態,因為這些值對 GKE 作業至關重要。

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

如要瞭解是誰在何時編輯執行個體中繼資料,可以查看 Compute Engine 稽核記錄資訊,或使用記錄檔探索工具執行類似下列的搜尋查詢,找出相關記錄:

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 cordonkubectl drain 指令,封鎖及排空節點。

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

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

  1. 將節點集區新增至叢集

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

    gcloud container node-pools list --cluster CLUSTER_NAME
    
  2. 如要停用現有節點集區的自動調度資源功能 (如果已啟用),請執行下列指令:

    gcloud container clusters update CLUSTER_NAME
        --region=CLUSTER_REGION \
        --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
    

後續步驟