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

本页面介绍了如何在 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 节点成本更高。

后续步骤