创建抢占式实例

ECI支持抢占式实例,对于短时间运行的Job任务,以及部分扩展性和容错率高的无状态应用,使用抢占式实例可以有效地节约实例使用成本。本文介绍在Kubernetes集群中,如何创建抢占式实例类型的ECI Pod。

背景信息

抢占式实例是一种低成本竞价型实例,您可以对阿里云当前闲置的资源出价,获得资源后运行容器,直到出价低于市场价格或者库存不足等原因导致资源回收。

抢占式实例适用于短时间运行的Job任务,以及部分扩展性和容错率高的无状态应用,例如可弹性伸缩的Web站点服务、图像渲染、大数据分析和大规模并行计算等。应用程序的分布度、可扩展性和容错能力越高,越适合使用抢占式实例节省成本和提升吞吐量。更多信息,请参见什么是抢占式实例

基本概念

创建抢占式实例前,您需要了解以下信息:

  • 计费方式

    抢占式实例的市场价格随供需变化而浮动,您需要在创建抢占式实例时指定出价模式,当指定实例规格的实时市场价格低于出价且库存充足时,就能成功创建抢占式实例。创建成功后,在保护期(默认1小时)内按照成交时的市场价格计费。超过保护期后,按照实时的市场价格计费。

    说明

    抢占式实例相对于按量付费实例价格有一定的折扣,实际价格随供求波动,并按实际使用时长进行收费。更多信息,请参见抢占式实例计费

  • 回收机制

    超过保护期后,系统每隔5分钟将自动检测一次实例规格的市场价格和库存。如果某一时刻的市场价格高于出价或实例规格库存不足,抢占式实例会被释放。

    说明
    • 资源回收前约3分钟,系统会产生准备释放的事件。

    • 资源回收后,实例不再收费,但会保留实例信息,且状态会变更为已过期(Expired)。

注意事项

基于抢占式实例的特点,使用抢占式实例时,请注意以下信息:

  • 选择一个合适的实例规格和一个合理的出价。

    您可以通过ECS的OpenAPI接口查询抢占式实例近30天的信息,以便选择实例规格和出价。相关接口如下:

    重要

    您的出价应该足够高,同时充分考虑了市场价格的波动,并且符合您对自身业务评估后的预期。这样才能成功创建抢占式实例,且实例不会因为价格因素被释放,在满足业务需求的同时实现成本节约。

  • 使用不受抢占式实例释放影响的存储介质来保存您的重要数据,例如:云盘(关闭随实例释放)、NAS等。

创建方式

支持指定ECS规格,或者指定vCPU和内存来创建抢占式ECI实例:

  • 指定ECS规格

    计费以指定规格的按量市场价格和实时折扣为准。

  • 指定vCPU和内存

    该方式与指定ECS规格方式的效果相同。系统会自动匹配满足规格和价格要求的ECS规格,并以此规格的市场价格作为计费的原始市场价格,即折扣是基于该ECS规格的市场价,而非对应ECI的vCPU和内存的按量价格。

    该方式仅支持2 vCPU及以上规格,支持指定的vCPU和内存规格如下表所示。如果指定的规格不支持,系统会自动向上规整。

    vCPU

    内存(GiB)

    2

    2、4、8、16

    4

    4、8、16、32

    8

    8、16、32、64

    12

    12、24、48、96

    16

    16、32、64 、128

    24

    24、48、96、192

    32

    32、64、128、256

    52

    96、192、384

    64

    128、256、512

配置说明

您可以在Pod metadata中添加Annotation来创建抢占式实例。相关Annotation如下:

Annotation

示例值

是否必选

说明

k8s.aliyun.com/eci-spot-strategy

SpotAsPriceGo

抢占式实例的出价策略。可根据需要配置为:

  • SpotWithPriceLimit:自定义设置抢占实例价格上限。此时必须通过k8s.aliyun.com/eci-spot-price-limit来指定每小时价格上限。

  • SpotAsPriceGo:系统自动出价,跟随当前市场实际价格。

    重要

    使用SpotAsPriceGo策略时,如果对应可用区规格资源紧张,最高价格可能会达到按量价格。

k8s.aliyun.com/eci-spot-price-limit

"0.5"

抢占式实例的每小时价格上限,最多支持精确到小数点后三位。

仅当k8s.aliyun.com/eci-spot-strategy设置为SpotWithPriceLimit时有效。

k8s.aliyun.com/eci-spot-duration

"0"

抢占式实例的保护期。默认为1,可设置为0,表示无保护期。

k8s.aliyun.com/eci-spot-fallback

"true"

抢占式实例没有库存时,是否自动转为按量付费,以保证实例创建成功。默认为false。

重要
  • Annotation请添加在Pod的metadata下,例如:创建Job时,Annotation需添加在spec>template>metadata下。

  • 仅支持在创建ECI Pod时添加ECI相关Annotation来生效ECI功能,更新ECI Pod时添加或者修改ECI相关Annotation均不会生效。

示例一:指定ECS规格,采用SpotWithPriceLimit策略

apiVersion: batch/v1
kind: Job
metadata:
  name: test
spec:
  template:
    metadata:
      labels:
        app: perl
        alibabacloud.com/eci: "true" 
      annotations:
        k8s.aliyun.com/eci-use-specs : "ecs.c6.large"           #指定ECS实例规格
        k8s.aliyun.com/eci-spot-strategy: "SpotWithPriceLimit"  #采用自定义设置价格上限的策略
        k8s.aliyun.com/eci-spot-price-limit: "0.25"            #设置每小时价格上限
    spec:
      containers:
      - name: pi
        image: registry.cn-shanghai.aliyuncs.com/eci_open/perl:5
        command: ["perl",  "-Mbignum=bpi", "-wle", "print bpi(2000)"]
      restartPolicy: Never

以上YAML示例可创建一个ecs.c6规格的抢占式实例。

  • 创建时,如果没有满足规格和价格上限要求的库存,则创建失败。

  • 创建后,可以稳定使用1小时,超出1小时保护期后,如果某一时刻的市场价格高于出价或实例规格库存不足,抢占式实例会被释放。

示例二:指定vCPU和内存,采用SpotAsPriceGo策略

  • 通过pod.spec.resources指定vCPU和内存规格

    apiVersion: batch/v1
    kind: Job
    metadata:
      name: test
    spec:
      template:
        metadata:
          labels:
            app: perl
            alibabacloud.com/eci: "true" 
          annotations:
            k8s.aliyun.com/eci-spot-strategy: "SpotAsPriceGo"  #采用系统自动出价,跟随当前市场实际价格
        spec:
          containers:
          - name: pi
            image: registry.cn-shanghai.aliyuncs.com/eci_open/perl:5
            command: ["perl",  "-Mbignum=bpi", "-wle", "print bpi(2000)"]
            resources:
              limits:              #指定pi容器的vCPU为2 vCPU,内存为4 GiB
                cpu: 2000m
                memory: 4096Mi
          restartPolicy: Never
  • 通过Annotation指定vCPU和内存规格

    apiVersion: batch/v1
    kind: Job
    metadata:
      name: test
    spec:
      template:
        metadata:
          labels:
            app: perl
            alibabacloud.com/eci: "true" 
          annotations:
            k8s.aliyun.com/eci-use-specs : "2-4Gi"             #指定vCPU和内存,仅支持2 vCPU及以上规格
            k8s.aliyun.com/eci-spot-strategy: "SpotAsPriceGo"  #采用系统自动出价,跟随当前市场实际价格
        spec:
          containers:
          - name: pi
            image: registry.cn-shanghai.aliyuncs.com/eci_open/perl:5
            command: ["perl",  "-Mbignum=bpi", "-wle", "print bpi(2000)"]
          restartPolicy: Never

以上YAML示例可创建一个2 vCPU,4 GiB内存的抢占式实例。

  • 创建时,如果没有满足规格要求的库存,则创建失败。

  • 创建后,可以稳定使用1小时,超出1小时保护期后,如果某一时刻的市场价格高于出价或实例规格库存不足,抢占式实例会被释放。

示例三:设置无保护期

apiVersion: batch/v1
kind: Job
metadata:
  name: test
spec:
  template:
    metadata:
      labels:
        app: perl
        alibabacloud.com/eci: "true" 
      annotations:
        k8s.aliyun.com/eci-use-specs : "2-4Gi"             #指定vCPU和内存,仅支持2 vCPU及以上规格
        k8s.aliyun.com/eci-spot-strategy: "SpotAsPriceGo"  #采用系统自动出价,跟随当前市场实际价格
        k8s.aliyun.com/eci-spot-duration: "0"              #设置无保护期
    spec:
      containers:
      - name: pi
        image: registry.cn-shanghai.aliyuncs.com/eci_open/perl:5
        command: ["perl",  "-Mbignum=bpi", "-wle", "print bpi(2000)"]
      restartPolicy: Never

以上YAML示例可创建一个2 vCPU,4 GiB内存的抢占式实例。

  • 创建时,如果没有满足规格要求的库存,则创建失败。

  • 创建后,没有稳定使用的保护期,只要某一时刻的市场价格高于出价或实例规格库存不足,抢占式实例就会被释放。

示例四:设置没有库存时自动转为按量付费

apiVersion: batch/v1
kind: Job
metadata:
  name: test
spec:
  template:
    metadata:
      labels:
        app: perl
        alibabacloud.com/eci: "true" 
      annotations:
        k8s.aliyun.com/eci-use-specs : "ecs.c6.large"           #指定ECS实例规格
        k8s.aliyun.com/eci-spot-strategy: "SpotWithPriceLimit"  #采用自定义设置价格上限的策略
        k8s.aliyun.com/eci-spot-price-limit: "0.05"            #设置每小时价格上限
        k8s.aliyun.com/eci-spot-fallback: "true"                #当抢占式实例没有库存时,自动转为按量付费
    spec:
      containers:
      - name: pi
        image: registry.cn-shanghai.aliyuncs.com/eci_open/perl:5
        command: ["perl",  "-Mbignum=bpi", "-wle", "print bpi(2000)"]
      restartPolicy: Never

以上YAML示例可创建一个ecs.c6规格的抢占式实例。

  • 创建时,如果有满足规格和价格上限要求的库存,则会创建一个抢占式实例。创建后,可以稳定使用1小时,超出1小时保护期后,如果某一时刻的市场价格高于出价或实例规格库存不足,抢占式实例会被释放。

  • 创建时,如果没有满足规格和价格上限要求的库存,则会创建一个按量付费的实例。创建后,系统不会主动释放实例。

    实例创建成功后,您可以通过kubectl describe pod命令查看对应Pod的事件来确认是否转为按量付费实例,如果看到SpotDegraded事件,则表明已转为按量付费实例。

    spot转按量事件..png

释放说明

抢占式实例创建成功后,在保护期内可以正常运行。超出保护期后,如果市场价格高于出价或者资源库存不足,抢占式实例会被释放。您可以通过以下信息了解抢占式实例的释放情况。

  • 预释放事件

    抢占式实例在释放前约3分钟,会产生SpotToBeReleased事件。

    重要

    ECI会通过Kubernetes Events事件通知的方式告知您抢占式实例将被释放。在此期间,您可以做一定的处理来确保业务不受实例释放所影响。更多信息,请参见优雅下线

    • 通过kubectl describe命令查看Pod详细信息,在返回信息的Events中可以看到预释放事件。示例如下:

      Events:
        Type     Reason            Age    From          Message
        ----     ------            ----   ----          -------
        Warning  SpotToBeReleased  3m32s  kubelet, eci  Spot ECI will be released in 3 minutes
    • 通过kukubectl get events命令查看事件信息,在返回信息中可以看到预释放事件。示例如下:

      LAST SEEN   TYPE      REASON             OBJECT         MESSAGE
      3m39s       Warning   SpotToBeReleased   pod/pi-frmr8   Spot ECI will be released in 3 minutes
  • 释放后Pod状态

    抢占式实例释放后,实例信息仍会保留,状态变更为Failed,Failed原因为BidFailed。

    • 通过kubectl get pod命令查看Pod信息,在返回信息中可以看到Pod状态已变更。示例如下:

      NAME       READY   STATUS      RESTARTS   AGE
      pi-frmr8   1/1     BidFailed   0          3h5m
    • 通过kubectl describe命令查看Pod详细信息,在返回信息中可以看到Pod状态信息。示例如下:

      Status:             Failed
      Reason:             BidFailed
      Message:            The pod is spot instance, and have been released at 2020-04-08T12:36Z

优雅下线

抢占式实例在释放前约3分钟,会产生SpotToBeReleased事件,同时会将Pod Conditions中的ContainerInstanceExpired字段置为true。为尽量避免抢占式实例回收导致的业务中断,您可以基于这些通知机制,进行抢占实例的优雅退出和Pod轮转等处理。

目前虚拟节点已支持配置ECI抢占式实例优雅下线的功能。您可以为抢占式实例类型的ECI Pod添加k8s.aliyun.com/eci-spot-release-strategy: api-evict的Annotation,实现当虚拟节点收到SpotToBeReleased事件时,会调用Eviction API来驱逐该抢占式实例。

重要

ACK Virtual Node需要升级到v2.11.0及以上版本,才支持通过Pod Conditions进行抢占实例中断通知以及配置Eviction API来驱逐抢占式实例。更多信息,请参见ACK Virtual Node

API发起的驱逐将遵从您的PodDisruptionBudget(PDB)和terminationGracePeriodSeconds配置。使用API创建Eviction对象,类似于对Pod执行策略控制的DELETE操作。相关流程如下:

  1. 调用API请求

    虚拟节点接收到SpotToBeReleased Event,调用Eviction API。

  2. PDB检查

    API服务器验证与目标Pod关联的PodDisruptionBudget。

  3. 驱逐执行

    如果API服务器允许驱逐,Pod将按照如下方式删除。

    1. API服务器中的Pod资源会更新删除时间戳,之后API服务器会认为此Pod资源将被终止。 此Pod资源还会标记上配置的宽限期。

    2. 本地运行状态的Pod所处节点上的kubelet注意到Pod资源被标记为终止,并开始优雅停止本地Pod。

    3. 当kubelet停止Pod时,控制面从Endpoint和EndpointSlice对象中移除该Pod。因此,控制器不再将此Pod视为有用对象。

    4. Pod的宽限期到期后,kubelet强制终止本地Pod。

    5. kubelet告知API服务器要删除Pod资源。

    6. API服务器删除Pod资源。

  4. 负载Reconcile

    如果目标Pod是由控制器(如ReplicaSet、StatefulSet,以及设置了容错的Job、sparkApplication、Workflow)管理的,控制器通常会创建一个新的Pod来替代被驱逐的Pod。

说明

如果PodDisruptionBudget配置错误,或者调用Eviction API时工作负载存在大量尚未Ready的Pod, 则会导致Eviction阻塞。在抢占式实例到期前,如果仍未完成Eviction动作,抢占式实例会被直接释放。