在 Spot Pod 中以更低的费用运行容错工作负载


本页面介绍如何在 Google Kubernetes Engine (GKE) Autopilot 集群中使用 Spot Pod 以更低的费用运行容错工作负载。

概览

在 GKE Autopilot 集群中,Spot Pod 是在 Compute Engine Spot 虚拟机支持的节点上运行的 Pod。Spot Pod 的价格低于标准 Autopilot Pod,但只要运行标准 Pod 需要计算资源,GKE 就可以逐出。

与将这些工作负载作为标准 Pod 运行相比,Spot Pod 非常适合以较低的费用运行无状态、批处理或容错工作负载。如需在 Autopilot 集群中使用 Spot Pod,请修改 Pod 规范以请求 Spot Pod。

您可以在默认的通用 Autopilot 计算类以及满足特定硬件要求的专用计算类上运行 Spot Pod。如需了解这些计算类,请参阅 Autopilot 中的计算类

如需详细了解 Autopilot 集群中的 Spot Pod 的价格,请参阅 Google Kubernetes Engine 价格

Spot Pod 已从 Autopilot 服务等级协议中排除。

优势

在 Autopilot 集群中使用 Spot Pod 具有以下优势:

  • 价格低于在标准 Autopilot Pod 上运行相同工作负载的价格。
  • GKE 会自动管理自动扩缩和调度功能。
  • GKE 会自动运行 Spot Pod 的节点,以确保标准 Pod(例如关键工作负载)不会被调度到这些节点上。使用 Spot Pod 的部署会自动更新相应的容忍

准备工作

在开始之前,请确保您已执行以下任务:

  • 启用 Google Kubernetes Engine API。
  • 启用 Google Kubernetes Engine API
  • 如果您要使用 Google Cloud CLI 执行此任务,请安装初始化 gcloud CLI。 如果您之前安装了 gcloud CLI,请运行 gcloud components update 以获取最新版本。

请求 Autopilot 工作负载中的 Spot Pod

如需请求您的 Pod 作为 Spot Pod 运行,请在 Pod 规范中的 nodeSelector节点亲和性中使用 cloud.google.com/gke-spot=true 标签。GKE 会自动预配可以运行 Spot Pod 的节点。

比方说,如果 Google Cloud中的其他地方需要计算资源,Spot 可能会随时被逐出和终止。终止时,终止节点上的 Spot Pod 可以在终止之前请求长达 15 秒的宽限期,该时间段通过指定 terminationGracePeriodSeconds 字段。

Spot Pod 在抢占期间提供的最长宽限期为 15 秒。在 terminationGracePeriodSeconds 中请求超过 15 秒不会在抢占期间超过 15 秒。逐出时,您的 Pod 会收到 SIGTERM 信号,并且应采取措施在宽限期内关停。

对于 Autopilot,GKE 还会自动污染为运行 Spot pod 而创建的节点,并使用相应的容忍修改这些工作负载。污点可防止标准 Pod 被调度到运行 Spot Pod 的节点上。

使用 nodeSelector 需要 Spot pod

您可以使用 nodeSelector 要求 Deployment 中的 Spot Pod。将 cloud.google.com/gke-spot=true 标签添加到您的 Deployment,如以下示例所示:

apiVersion: batch/v1
kind: Job
metadata:
  name: pi
spec:
  template:
    metadata:
      labels:
        app: pi
    spec:
      nodeSelector:
        cloud.google.com/gke-spot: "true"
      terminationGracePeriodSeconds: 15
      containers:
      - name: pi
        image: perl:5.34.0
        command: ["perl",  "-Mbignum=bpi", "-wle", "print bpi(2000)"]
      restartPolicy: Never
  backoffLimit: 4

使用节点亲和性请求 Spot Pod

或者,您可以使用节点亲和性来请求 Spot Pod。节点亲和性为您提供了一种可扩展的方法来选择节点来运行工作负载。例如,您可以组合多个选择条件,以便更精细地控制 Pod 的运行位置。使用节点亲和性请求 Spot Pod 时,您可以指定要使用的节点亲和性类型,如下所示:

  • requiredDuringSchedulingIgnoredDuringExecution:必须使用 Spot Pod。
  • preferredDuringSchedulingIgnoredDuringExecution:尽力使用 Spot Pod。

如需使用节点亲和性来要求在 Deployment 中使用 Spot Pod,请将以下 nodeAffinity 规则添加到 Deployment 清单中:

apiVersion: batch/v1
kind: Job
metadata:
  name: pi
spec:
  template:
    metadata:
      labels:
        app: pi
    spec:
      terminationGracePeriodSeconds: 15
      affinity:
        nodeAffinity:
          requiredDuringSchedulingIgnoredDuringExecution:
            nodeSelectorTerms:
            - matchExpressions:
              - key: cloud.google.com/gke-spot
                operator: In
                values:
                - "true"
      containers:
      - name: pi
        image: perl:5.34.0
        command: ["perl",  "-Mbignum=bpi", "-wle", "print bpi(2000)"]
      restartPolicy: Never
  backoffLimit: 4

尽力请求 Spot Pod

如需使用节点亲和性尽力请求 Spot Pod,请使用 preferredDuringSchedulingIgnoredDuringExecution。当您首选请求 Spot Pod 时,GKE 会根据以下顺序安排 Pod:

  1. 可以运行具有可用可分配容量的 Spot pod 的现有节点。
  2. 具有可用可分配容量的现有标准节点。
  3. 可以运行 Spot pod 的新节点(如果计算资源可用)。
  4. 新的标准节点。

由于 GKE 首选具有可分配容量的现有标准节点,而不是为 Spot Pod 创建新节点,因此您可能会发现作为标准 Pod 运行的 Pod 比 Spot Pod 多,这会阻止您充分利用 Spot Pod 的价格更低。

针对可抢占式 Pod 的请求

Autopilot 集群使用 cloud.google.com/gke-preemptible 选择器支持抢占式 Pod 的请求。使用此选择器的 Pod 会自动迁移到 Spot Pod,并且选择器会更改为 cloud.google.com/gke-spot

查找和删除已终止的 Pod

在安全 Pod 终止期间,kubelet 会为终止的 Pod 分配 Failed 状态和 Shutdown 原因。当终止的 Pod 数量达到 1000 时,垃圾回收将会清理 Pod。您还可以使用以下命令手动删除关停 Pod:

kubectl get pods --all-namespaces | grep -i shutdown | awk '{print $1, $2}' | xargs -n2 kubectl delete pod -n

停止使用 Spot Pod 的工作负载

如果您有现有的 Spot Pod,并且想要更新为标准 Pod,可以使用以下方法之一:

  • 重新创建工作负载:删除部署,移除清单中选择 Spot Pod 的行,然后将更新后的部署清单应用于集群。
  • 修改工作负载:在 Pod 在集群中运行时修改 Deployment 规范。

使用这两种方法时,您可能会遇到轻微的工作负载中断。

重新创建工作负载

以下步骤演示了如何删除现有的部署,并将更新后的清单应用于集群。您还可以将这些步骤用于其他类型的 Kubernetes 工作负载,例如作业。

为了确保 GKE 将更新后的 Pod 放置在正确类型的节点上,您必须将 Kubernetes API 服务器中的工作负载的现有状态导出到文件中,然后修改该文件。

  1. 将工作负载规范写入 YAML 文件:

    kubectl get deployment DEPLOYMENT_NAME -o yaml > DEPLOYMENT_NAME-on-demand.yaml
    

    DEPLOYMENT_NAME 替换为您的部署名称。对于其他类型的工作负载(例如作业或 Pod),请在 kubectl get 命令中使用相应的资源名称,例如 kubectl get pod

  2. 在文本编辑器中打开 YAML 文件:

    vi DEPLOYMENT_NAME-on-demand.yaml
    
  3. 从文件中移除 Spot Pod 的 nodeSelector GKE 为 Spot Pod 添加的容忍设置:

    apiVersion: apps/v1
    kind: Deployment
    metadata:
      annotations:
      # lines omitted for clarity
    spec:
      progressDeadlineSeconds: 600
      replicas: 6
      revisionHistoryLimit: 10
      selector:
        matchLabels:
          pod: nginx-pod
      strategy:
        rollingUpdate:
          maxSurge: 25%
          maxUnavailable: 25%
        type: RollingUpdate
      template:
        metadata:
        # lines omitted for clarity
        spec:
          containers:
          - image: nginx
            imagePullPolicy: Always
            name: web-server
            resources:
              limits:
                ephemeral-storage: 1Gi
              requests:
                cpu: 500m
                ephemeral-storage: 1Gi
                memory: 2Gi
            securityContext:
              capabilities:
                drop:
                - NET_RAW
            terminationMessagePath: /dev/termination-log
            terminationMessagePolicy: File
          dnsPolicy: ClusterFirst
          nodeSelector:
            cloud.google.com/gke-spot: "true"
          restartPolicy: Always
          schedulerName: default-scheduler
          securityContext:
            seccompProfile:
              type: RuntimeDefault
          terminationGracePeriodSeconds: 15
          tolerations:
          - effect: NoSchedule
            key: kubernetes.io/arch
            operator: Equal
            value: amd64
          - effect: NoSchedule
            key: cloud.google.com/gke-spot
            operator: Equal
            value: "true"
    status:
      #lines omitted for clarity
    

    您必须同时移除容忍设置和 nodeSelector,以向 GKE 指明 Pod 必须在按需节点(而非 Spot 节点)上运行。

  4. 保存更新后的清单。

  5. 删除 Deployment 清单并将其重新应用于集群:

    kubectl replace -f DEPLOYMENT_NAME-on-demand.yaml
    

    此操作的持续时间取决于 GKE 需要终止和清理的 Pod 数量。

就地修改工作负载

以下步骤介绍了如何对正在运行的部署进行就地修改,以向 GKE 指明 Pod 必须在按需节点上运行。您还可以将这些步骤用于其他类型的 Kubernetes 工作负载,例如 Jobs。

您必须在 Kubernetes API 中修改工作负载对象,因为 GKE 会在工作负载接纳期间自动向工作负载规范添加针对 Spot Pod 的容忍设置。

  1. 打开工作负载清单,以便在文本编辑器中进行修改:

    kubectl edit deployment/DEPLOYMENT_NAME
    

    DEPLOYMENT_NAME 替换为该 Deployment 的名称。对于其他类型的工作负载(例如作业或 Pod),请在 kubectl edit 命令中使用相应的资源名称,例如 kubectl edit pod/POD_NAME

  2. 在文本编辑器中,删除 Spot Pod 的节点选择器或节点亲和性规则,以及 GKE 添加到清单中的容忍度,如以下示例所示:

    apiVersion: apps/v1
    kind: Deployment
    metadata:
      name: example-deployment
      namespace: default
    spec:
      replicas: 1
      selector:
        matchLabels:
          type: dev
      template:
        metadata:
          labels:
            type: dev
        spec:
          nodeSelector:
            cloud.google.com/gke-spot: "true"
          tolerations:
          - effect: NoSchedule
            key: cloud.google.com/gke-spot
            operator: Equal
            value: "true"
          containers:
          - name: nginx
            image: nginx
            ports:
            - containerPort: 80
    
  3. 保存更新后的清单,然后关闭文本编辑器。更新后的对象配置会向 GKE 指明 Pod 必须在按需节点上运行。GKE 会重新创建 Pod,以将其放置到新的按需节点上。

验证工作负载是否在按需节点上运行

如需验证更新后的工作负载是否不再在 Spot Pod 上运行,请检查工作负载并查找 Spot Pod 容忍度:

  • 检查工作负载:

    kubectl describe deployment DEPLOYMENT_NAME
    

输出不会在 spec.tolerations 字段中显示 cloud.google.com/gke-spot 的条目。

后续步骤