本頁說明如何在 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。
- 適用於執行無狀態、批次或容錯工作負載。
- 價格比標準 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 節點昂貴,因此這種行為也會增加資源消耗量。