使用抢占式虚拟机运行容错工作负载

本页面介绍了如何在 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 虚拟机有许多相似之处,包括:

与没有最长到期时间的 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 和 shutdownGracePeriodCriticalPods kubelet 配置字段是不可变的。不过,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 节点成本更高。

后续步骤