本页面介绍了如何在 Google Kubernetes Engine (GKE) 中使用抢占式虚拟机。
Spot 虚拟机是最新版本的抢占式虚拟机。我们建议您使用 Autopilot 集群中的 Spot Pod 或 Standard 集群中的 Spot 虚拟机,而不是抢占式虚拟机。GKE 继续支���抢占式虚拟机,它们使用与 Spot 虚拟机相同的价格模式。
概览
抢占式虚拟机是价格低于标准虚拟机但不保证可用性的 Compute Engine 虚拟机实例。抢占式虚拟机提供与 Spot 虚拟机类似的功能,但在创建后最长只能使用 24 小时。
在某些情况下,抢占式虚拟机可能持续超过 24 小时。如果新的 Compute Engine 实例启动速度太快,并且 Kubernetes 无法识别创建的其他 Compute Engine 虚拟机时,可能会发生这种情况。底层 Compute Engine 实例最长持续 24 小时,并遵循预期的抢占式虚拟机行为。
与 Spot 虚拟机比较
抢占式虚拟机与 Spot 虚拟机有许多相似之处,包括:
- 在 Compute Engine 需要资源运行标准虚拟机时会终止。
- 适用于运行无状态、批量或容错工作负载。
- 价格低于标准虚拟机。
- 安全节点关停默认处于启用状态。不过,与 Spot 虚拟机不同,您无法修改正常终止期限的时长。如需了解详情,请参阅终止并正常关停 Spot 虚拟机。
- 支持集群自动扩缩器和节点自动预配。
与没有最长到期时间的 Spot 虚拟机相比,抢占式虚拟机仅在创建后最长只能使用 24 小时。
您可以在新集群和节点池上启用抢占式虚拟机、使用 nodeSelector 或节点亲和性来控制调度,以及使用污点和容忍来避免节点被抢占时系统工作负载出现问题。
终止并正常关闭抢占式虚拟机
当 Compute Engine 需要收回抢占式虚拟机使用的资源时,系统会向 GKE 发送抢占通知。抢占式虚拟机在收到终止通知 30 秒后终止。
默认情况下,集群使用正常节点关停。kubelet 会注意到终止通知,并正常终止节点上运行的 Pod。如果 Pod 是托管式工作负载(例如 Deployment)的一部分,则控制器会创建并调度新 Pod 以替换已终止的 Pod。
kubelet 会尽最大努力为非系统 Pod 提供 15 秒的正常终止时间段,之后系统 Pod(具有 system-cluster-critical 或 system-node-critical priorityClass)将有 15 秒的时间来正常终止。在节点正常终止期间,kubelet 会更新 Pod 的状态,为终止的 Pod 分配 Failed 阶段和 Terminated 原因。
非系统 Pod 的正常终止时长最长为 15 秒。在 Pod 清单的 terminationGracePeriodSeconds 字段中指定大于 15 秒的值没有任何效果。整个虚拟机会在收到抢占通知 30 秒后关停。
对 Kubernetes 行为的修改
在 GKE 上使用抢占式虚拟机会修改 Kubernetes PodDisruptionBudgets 提供的保护。抢占式虚拟机的回收是非自愿的,不在 PodDisruptionBudgets 的保护范围内。相对于已配置的 PodDisruptionBudget,遇到不可用情况的几率可能较大。
限制
- 抢占式虚拟机不支持 Windows Server 节点池。
- 使用抢占式虚拟机时,您无法修改非系统 Pod 的 15 秒宽限期和系统 Pod 的后续 15 秒时长。底层
shutdownGracePeriod和shutdownGracePeriodCriticalPodskubelet配置字段是不可变的。不过,Spot 虚拟机支持修改这些设置。如需了解详情,请参阅终止并安全关停 Spot 虚拟机。
创建具有抢占式虚拟机的集群或节点池
您可以使用 Google Cloud CLI 创建具有抢占式虚拟机的集群或节点池。
如需创建具有抢占式虚拟机的集群,请运行以下命令:
gcloud container clusters create CLUSTER_NAME \
--preemptible
将 CLUSTER_NAME 替换为新集群的名称。
如需创建具有抢占式虚拟机的节点池,请运行以下命令:
gcloud container node-pools create POOL_NAME \
--cluster=CLUSTER_NAME \
--preemptible
将 POOL_NAME 替换为新节点池的名称。
使用 nodeSelector 在抢占式虚拟机上调度 pod
GKE 会将 cloud.google.com/gke-preemptible=true 和 cloud.google.com/gke-provisioning=preemptible 标签添加到使用抢占式虚拟机的节点。您可以在部署中使用 nodeSelector 来指示 GKE 将 Pod 调度到抢占式虚拟机上。
例如,以下 Deployment 会过滤使用 cloud.google.com/gke-preemptible 标签的抢占式虚拟机:
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"
为抢占式虚拟机使用节点污点
您可以为使用抢占式虚拟机的节点设置污点,以便 GKE 只能在这些节点上放置具有相应容忍设置的 Pod。
如需向使用抢占式虚拟机的节点池添加节点污点,请在创建节点池时使用 --node-taints 标志,类似于以下命令:
gcloud container node-pools create POOL2_NAME \
--cluster=CLUSTER_NAME \
--node-taints=cloud.google.com/gke-preemptible="true":NoSchedule
现在,只有能容忍节点污点的 Pod 才会被调度到该节点。
如需向 Pod 添加相关容忍,请修改部署并将以下内容添加到 Pod 规范中:
tolerations:
- key: cloud.google.com/gke-preemptible
operator: Equal
value: "true"
effect: NoSchedule
GPU 抢占式虚拟机的节点污点
抢占式虚拟机支持使用 GPU。在添加使用抢占式虚拟机的 GPU 节点池之前,您应该在集群中至少再创建一个不使用抢占式虚拟机的节点池。具有标准节点池有助于确保 GKE 可以安全地放置 DNS 等系统组件。
如果您创建的新集群中具有使用抢占式虚拟机的 GPU 节点池,或者将使用抢占式虚拟机的新 GPU 节点池添加到尚不具有标准节点池的集群,则 GKE 不会自动将 nvidia.com/gpu=present:NoSchedule 污点添加到节点。GKE 可能会将系统 Pod 调度到抢占式虚拟机上,这可能会导致发生中断。此行为还会增加资源消耗量,因为 GPU 节点比非 GPU 节点成本更高。