本頁說明如何在 Google Kubernetes Engine (GKE) 中使用先占 VM。
總覽
先占 VM 是 Compute Engine VM 執行個體,價格低於標準 VM,但不保證可用性。先占 VM 的功能與Spot VM 類似,但建立後最多只能持續 24 小時。
在某些情況下,先占 VM 的存續時間可能會超過 24 小時。如果新的 Compute Engine 執行個體啟動速度過快,Kubernetes 無法辨識出已建立不同的 Compute Engine VM,就可能發生這種情況。底層的 Compute Engine 執行個體最長可執行 24 小時,並遵循先占 VM 的預期行為。
與 Spot VM 比較
先占 VM 與 Spot VM 有許多相似之處,包括:
- 在 Compute Engine 需要資源來執行標準 VM 時終止。
- 適用於執行無狀態、批次或容錯工作負載。
- 價格比標準 VM 更低。
- 在執行 GKE 1.20 以上版本的叢集上,預設會啟用節點正常關機。
- 可搭配叢集自動配置器和節點自動佈建功能使用。
與沒有最長到期時間的 Spot VM 不同,先占 VM 建立後最多只能存續 24 小時。
您可以在新的叢集和節點集區上啟用先占 VM,使用 nodeSelector
或節點親和性控管排程,並使用 taint 和容許條件,避免節點遭到先占時發生系統工作負載問題。
終止及按適當流程關閉先占 VM
當 Compute Engine 需要回收先佔 VM 使用的資源時,系統會將先佔通知傳送至 GKE。先占 VM 會在收到終止通知的 30 秒後終止。
根據預設,叢集會使用安全節點關機。 kubelet 會注意到終止通知,並正常終止在節點上執行的 Pod。如果 Pod 屬於受管理的工作負載 (例如 Deployment),控制器會建立並排定新的 Pod,取代終止的 Pod。
Kubelet 會盡量為非系統 Pod 提供 15 秒的正常終止時間,之後系統 Pod (具有 system-cluster-critical
或 system-node-critical
priorityClasses) 會有 15 秒的正常終止時間。在節點正常終止期間,kubelet 會更新 Pod 的狀態,並為終止的 Pod 指派 Failed
階段和 Terminated
原因。
即使您在 Pod 資訊清單的 terminationGracePeriodSeconds
欄位中指定大於 15 秒的值,VM 仍會在終止通知傳送後 30 秒關閉。
當終止的 Pod 數量達到門檻時,垃圾收集會清除 Pod。門檻為:節點少於 100 個的叢集為 1000 個,節點數達 100 個以上的叢集為 5000 個。
您也可以使用下列指令手動刪除已終止的 Pod:
kubectl get pods --all-namespaces | grep -i NodeShutdown | awk '{print $1, $2}' | xargs -n2 kubectl delete pod -n
kubectl get pods --all-namespaces | grep -i Terminated | awk '{print $1, $2}' | xargs -n2 kubectl delete pod -n
Kubernetes 行為的修改
在 GKE 上使用先占 VM 會修改 Kubernetes PodDisruptionBudgets
提供的保證。先占 VM 的回收作業為非自願性,且不在PodDisruptionBudgets
的保證範圍內。您可能會遇到比設定的 PodDisruptionBudget
更高的無法使用率。
限制
- kubelet 節點正常關機功能僅適用於執行 GKE 1.20 以上版本的叢集。如果是 1.20 之前的 GKE 版本,您可以使用 Kubernetes on GCP Node Termination Event Handler,在先占 VM 終止時正常終止 Pod。
- 先占 VM 不支援 Windows Server 節點集區。
- 在 GKE 中,您無法變更節點關閉的寬限期長度。
shutdownGracePeriod
和shutdownGracePeriodCriticalPods
kubelet 設定欄位無法變更。
建立具有先占 VM 的叢集或節點集區
您可以使用 Google Cloud CLI 建立具有先占 VM 的叢集或節點集區。
如要建立具有先占 VM 的叢集,請執行下列指令:
gcloud container clusters create CLUSTER_NAME \
--preemptible
將 CLUSTER_NAME
替換為新叢集的名稱。
如要建立具有先占 VM 的節點集區,請執行下列指令:
gcloud container node-pools create POOL_NAME \
--cluster=CLUSTER_NAME \
--preemptible
將 POOL_NAME
替換為新節點集區的名稱。
使用 nodeSelector 將 Pod 排程到先占 VM
GKE 會將 cloud.google.com/gke-preemptible=true
和 cloud.google.com/gke-provisioning=preemptible
(適用於執行 GKE 1.25.5-gke.2500 以上版本的節點) 標籤新增至使用可搶占 VM 的節點。您可以在部署作業中使用 nodeSelector
,告知 GKE 將 Pod 排程到先占 VM 上。
舉例來說,以下是使用 cloud.google.com/gke-preemptible
標籤篩選先占 VM 的 Deployment:
apiVersion: apps/v1
kind: Deployment
metadata:
name: hello-app
spec:
replicas: 3
selector:
matchLabels:
app: hello-app
template:
metadata:
labels:
app: hello-app
spec:
containers:
- name: hello-app
image: us-docker.pkg.dev/google-samples/containers/gke/hello-app:1.0
resources:
requests:
cpu: 200m
nodeSelector:
cloud.google.com/gke-preemptible: "true"
為先占 VM 使用節點 taint
您可以對使用先占 VM 的節點進行 taint,這樣一來,GKE 就只會將具有對應容許條件的 Pod 放置在這些節點上。
如要為使用先占 VM 的節點集區新增節點 Taint,請在建立節點集區時使用 --node-taints
標記,類似下列指令:
gcloud container node-pools create POOL2_NAME \
--cluster=CLUSTER_NAME \
--node-taints=cloud.google.com/gke-preemptible="true":NoSchedule
現在,只有可容忍節點 Taint 的 Pod 會排程到節點。
如要為 Pod 新增相關容許條件,請修改部署作業,並在 Pod 規格中加入下列內容:
tolerations:
- key: cloud.google.com/gke-preemptible
operator: Equal
value: "true"
effect: NoSchedule
GPU 先占 VM 的節點 Taint
先占 VM 支援使用 GPU。 您應先在叢集中建立至少一個不使用先占 VM 的節點集區,再新增使用先占 VM 的 GPU 節點集區。有了標準節點集區,GKE 就能安全地放置 DNS 等系統元件。
如果您建立的新叢集具有使用先占 VM 的 GPU 節點集區,或是將使用先占 VM 的新 GPU 節點集區新增至沒有標準節點集區的叢集,GKE 不會自動將 nvidia.com/gpu=present:NoSchedule
taint 新增至節點。GKE 可能會將系統 Pod 排程至先占 VM,這可能會導致中斷。此外,GPU 節點比非 GPU 節點昂貴,因此這種行為也會增加資源消耗量。