- 云原生
- 容器编排
- DevOps
【免费下载链接】eksctl
The official CLI for Amazon EKS
导读
本文围绕 eksctl 对 Amazon EKS 集群中EC2 Spot 实例的完整支持展开:既涵盖通过EKS 托管节点组(Managed Nodegroups)一键创建 Spot 节点池的--spot工作流,也深入讲解自管节点组(Unmanaged Nodegroups)借助 Auto Scaling 的 MixedInstancesPolicy 实现 Spot/On-Demand 混合部署的配置方法。读完后你将掌握spot、instancesDistribution系列字段的语义、默认值与校验规则,能在配置文件与命令行之间自由切换,并学会利用node-lifecycle标签区分两类节点。文中所有参数说明均结合 eksctl 仓库源码(类型定义、校验逻辑、CloudFormation 生成器)进行佐证。
背景:EKS 对 Spot 工作节点的支持方式
EC2 Spot 实例以显著低于按需(On-Demand)的价格提供备用计算容量,适合容错型工作负载。eksctl 从两个维度支持 Spot:
- 托管节点组:EKS 官方托管节点组能力直接支持 Spot。EKS 会按照 Spot 最佳实践配置并启动一个 Spot 实例的 Auto Scaling 组,并在实例被 AWS 回收(中断)之前自动排空(drain)Spot 工作节点,无需用户自行处理中断流程。该特性没有额外收费,用户只需按实际使用的 AWS 资源(Spot 实例、EBS 卷等)付费。
- 自管节点组:eksctl 通过 Auto Scaling 组的MixedInstancesPolicy(混合实例策略)支持 Spot,由用户自行控制 Spot 与 On-Demand 的混合比例与分配策略。
托管节点组使用 Spot 实例
通过命令行创建
在创建集群时传入--spot标志,并可选地通过--instance-types指定一个实例类型列表(逗号分隔):
$ eksctl create cluster --spot --instance-types=c3.large,c4.large,c5.large在已有集群上创建 Spot 托管节点组:
$ eksctl create nodegroup --cluster=<clusterName> --spot --instance-types=c3.large,c4.large,c5.large这两个标志在命令行层的定义可参见 nodegroup_flags.go:
--spot:Create a spot nodegroup (managed nodegroups only),即该标志仅对托管节点组有效。--instance-types:逗号分隔的实例类型列表,例如--instance-types=c3.large,c4.large,c5.large。
eksctl 会校验这两个标志的适用范围:在 configfile.go 的validateManagedNGFlags中,spot、instance-types等标志被列入flagsValidOnlyWithMNG,一旦在未指定--managed的情况下使用,会直接报错--spot is only valid with managed nodegroups (--managed),这一点也被 create/nodegroup_test.go 的测试用例覆盖。
通过配置文件创建
更推荐的做法是把 Spot 配置写进 ClusterConfig 配置文件,可完整复现、可版本化:
# spot-cluster.yaml apiVersion: eksctl.io/v1alpha5 kind: ClusterConfig metadata: name: spot-cluster region: us-west-2 managedNodeGroups: - name: spot instanceTypes: ["c3.large","c4.large","c5.large","c5d.large","c5n.large","c5a.large"] spot: true # `instanceTypes` defaults to [`m5.large`] - name: spot-2 spot: true # On-Demand instances - name: on-demand instanceTypes: ["c3.large", "c4.large", "c5.large"]$ eksctl create cluster -f spot-cluster.yaml上述示例对应的完整文件见 examples/26-managed-nodegroup-spot-instances.yaml。要点:
spot: true声明该托管节点组使用 Spot 容量;instanceTypes是可选的实例类型列表;不指定时默认使用m5.large;- 同一配置文件内可以同时定义 Spot 与 On-Demand 节点组(如示例中的
on-demand),按需混布。
注意:自管节点组不支持
spot与instanceTypes字段,应改用instancesDistribution字段配置 Spot(见下文)。
底层实现:CapacityType 如何生效
在 ManagedNodeGroup 类型定义 中,Spot bool与InstanceTypes []string是托管节点组的两个独立字段。当生成底层 CloudFormation 模板时,managed_nodegroup.go 会把spot: true翻译为托管节点组资源的CapacityType: SPOT:
if m.nodeGroup.Spot { managedResource.CapacityType = gfnt.NewString("SPOT") }CapacityType最终会写入 CloudFormation 资源的属性(见 beta.go),对应生成的模板样例可参考 testdata/launch_template/spot.json。也就是说,--spot/spot: true本质上是让 EKS 以 Spot 容量类型来创建和托管节点组。
自管节点组使用 Spot 实例(MixedInstancesPolicy)
自管节点组的 Spot 支持建立在 Auto Scaling 的MixedInstancesPolicy之上。核心配置字段是instancesDistribution,它内嵌在nodeGroups中。使用该字段时,不应再设置nodeGroups.X.instanceType(若一定要设置,只能是"mixed",否则校验直接拒绝,见下文)。
经典场景一:50% Spot + 50% On-Demand 混合
nodeGroups: - name: ng-1 minSize: 2 maxSize: 5 instancesDistribution: maxPrice: 0.017 instanceTypes: ["t3.small", "t3.medium"] # At least one instance type should be specified onDemandBaseCapacity: 0 onDemandPercentageAboveBaseCapacity: 50 spotInstancePools: 2这个配置对应完整示例 examples/08-spot-instances.yaml:
minSize: 2/maxSize: 5:节点组容量范围为 2~5;maxPrice: 0.017:单个 Spot 实例愿意支付的最高价格(美元/小时);instanceTypes:参与混合的实例类型列表,至少指定一个实例类型;onDemandBaseCapacity: 0:On-Demand 基础容量为 0;onDemandPercentageAboveBaseCapacity: 50:基础容量之上,On-Demand 与 Spot 的比例为 50/50;spotInstancePools: 2:在 2 个 Spot 实例池之间分散容量。
经典场景二:GPU 实例全 Spot
nodeGroups: - name: ng-gpu instanceType: mixed desiredCapacity: 1 instancesDistribution: instanceTypes: - g5.xlarge - g5.8xlarge - g5.16xlarge maxPrice: 0.50这里展示了instanceType: mixed的合法用法:当使用instancesDistribution时,instanceType要么不设置,要么显式设为mixed。g5 系列是支持 GPU 加速的实例,配合较高的maxPrice: 0.50提高中断风险下的竞价竞争力。
经典场景三:capacity-optimized 分配策略
nodeGroups: - name: ng-capacity-optimized minSize: 2 maxSize: 5 instancesDistribution: maxPrice: 0.017 instanceTypes: ["t3.small", "t3.medium"] # At least one instance type should be specified onDemandBaseCapacity: 0 onDemandPercentageAboveBaseCapacity: 50 spotAllocationStrategy: "capacity-optimized"经典场景四:capacity-optimized-prioritized 分配策略
nodeGroups: - name: ng-capacity-optimized-prioritized minSize: 2 maxSize: 5 instancesDistribution: maxPrice: 0.017 instanceTypes: ["t3a.small", "t3.small"] # At least two instance types should be specified onDemandBaseCapacity: 0 onDemandPercentageAboveBaseCapacity: 0 spotAllocationStrategy: "capacity-optimized-prioritized"capacity-optimized-prioritized的使用要点:按优先级从高到低排列instanceTypes列表(列表中第一个为最高优先级),EC2 Auto Scaling 会在尽力尊重实例类型优先级的同时优先保障容量。它适合"既要最小化中断可能性、又对某些实例类型有偏好"的工作负载。
约束规则:设置spotAllocationStrategy时,不能同时设置spotInstancePools;若spotAllocationStrategy未指定,EC2 默认使用lowest-price策略。
最小示例
nodeGroups: - name: ng-1 instancesDistribution: instanceTypes: ["t3.small", "t3.medium"] # At least one instance type should be specified只提供instancesDistribution.instanceTypes即可让节点组以 Spot 为主运行,其余参数全部走默认值(见下文参数表)。
底层实现:instancesDistribution 如何映射到 CloudFormation
在 nodegroup.go 的mixedInstancesPolicy函数中,instancesDistribution的每个字段被逐一对齐到 Auto Scaling 的 MixedInstancesPolicy:
instanceTypes生成LaunchTemplate.Overrides列表(每个实例类型一个 override);maxPrice→InstancesDistribution.SpotMaxPrice(仅当显式指定时写入,否则 AWS 默认采用 On-Demand 价格);onDemandBaseCapacity→InstancesDistribution.OnDemandBaseCapacity;onDemandPercentageAboveBaseCapacity→InstancesDistribution.OnDemandPercentageAboveBaseCapacity;spotInstancePools→InstancesDistribution.SpotInstancePools;spotAllocationStrategy→InstancesDistribution.SpotAllocationStrategy。
此外,capacityRebalance: true会在生成模板时被写入 ASG 资源的CapacityRebalance属性(见 nodegroup.go),用于开启 Spot 容量再平衡,对应测试用例见 nodegroup_test.go。托管节点组一侧则不支持instancesDistribution字段(见 nodegroup-managed.md)。
instancesDistribution 参数详解
以下参数定义与默认值出自 NodeGroupInstancesDistribution 结构体:
| 参数 | 是否必填 | 默认值 | 取值范围/说明 |
|---|---|---|---|
instanceTypes | 是(+required) | 无 | 参与混合的实例类型列表,至少指定一个实例类型 |
maxPrice | 否 | On-Demand 价格 | Spot 实例愿意支付的最高小时价格;不设置时 AWS 默认按 On-Demand 价格竞价 |
onDemandBaseCapacity | 否 | 0 | 混合策略中 On-Demand 基础容量(台数) |
onDemandPercentageAboveBaseCapacity | 否 | 100 | 基础容量之上 On-Demand 所占百分比,范围0-100 |
spotInstancePools | 否 | 2 | Spot 实例池数量,范围1-20;与spotAllocationStrategy互斥 |
spotAllocationStrategy | 否 | EC2 默认lowest-price | 支持lowest-price、capacity-optimized、capacity-optimized-prioritized等 |
capacityRebalance | 否 | false | 是否开启 Spot 容量再平衡 |
完整的 JSON Schema 可从配置文档 userdocs/src/usage/schema.md 了解入口;该 schema 现已迁移到 AWS 文档体系,可通过
eksctl utils schema在本地直接获取原始 JSON Schema。
校验规则(源码级)
validateInstancesDistribution 是这一切约束的"裁判",核心规则如下:
- 使用
instancesDistribution(或 instance selector)时,instanceType必须为空或等于"mixed",否则报错instanceType should be "mixed" or unset when using the instances distribution feature; instanceTypes不能为空,且去重后的数量不能超过 20;onDemandBaseCapacity必须大于等于 0;onDemandPercentageAboveBaseCapacity必须在 0~100 之间;spotInstancePools必须在 1~20 之间;- 设置
spotInstancePools的同时设置spotAllocationStrategy为capacity-optimized或capacity-optimized-prioritized会直接报错(两个策略互斥); spotAllocationStrategy的合法值由 validateSpotAllocationStrategy 对照 AWS SDK 的SpotAllocationStrategy枚举校验(包含lowest-price、diversified、capacity-optimized、capacity-optimized-prioritized、price-capacity-optimized等)。
上述规则均有对应的 Ginkgo 测试用例佐证,见 validation_test.go,例如:
spotInstancePools should be between 1 and 20;percentageAboveBase should be between 0 and 100;spotInstancePools cannot be specified when also specifying spotAllocationStrategy: capacity-optimized(-prioritized);spotAllocationStrategy should be one of: [lowest-price diversified capacity-optimized capacity-optimized-prioritized price-capacity-optimized]。
用 node-lifecycle 标签区分 Spot 与 On-Demand 节点
在混合部署场景中,调度层(如 cluster-autoscaler、拓扑感知调度)往往需要知道一个节点到底是 Spot 还是 On-Demand。eksctl 会在节点引导阶段自动打上 Kubernetes 标签node-lifecycle,其值为spot或on-demand。
该逻辑实现在节点引导脚本 bootstrap.helper.sh 中:
INSTANCE_LIFECYCLE="$(get_metadata instance-life-cycle)" ... NODE_LABELS="${NODE_LABELS},node-lifecycle=${INSTANCE_LIFECYCLE},alpha.eksctl.io/instance-id=${INSTANCE_ID}"脚本通过 IMDSv2 获取instance-life-cycle元数据(spot/on-demand),并将其注入 kubelet 的--node-labels参数。因此,你可以放心地在工作负载的 nodeSelector / nodeAffinity 中使用node-lifecycle: spot或node-lifecycle: on-demand来精确控制 Pod 落到哪类节点上,这是处理 Spot 中断、实现"关键任务走 On-Demand、弹性任务走 Spot"的常用手段。
CLI 与配置文件的兼容性边界
使用命令行时还有几点值得注意(同样有源码依据):
--spot、--instance-types是托管节点组专属标志;自管节点组只能通过配置文件中的instancesDistribution表达 Spot 需求,命令行上并没有等价的 Spot 标志;- 当命令行标志与配置文件同时使用时,configfile.go 将
spot、instance-types、nodes、node-type等列入commonNGFlagsIncompatibleWithConfigFile,即这些标志不能与-f配置文件混用,防止"双源配置"产生歧义。
小结
- 托管节点组:
--spot或spot: true+ 可选instanceTypes(默认m5.large),底层映射为 EKS 的CapacityType: SPOT,由 EKS 自动完成 Spot 中断前的节点排空,零增量成本; - 自管节点组:通过
instancesDistribution驱动 MixedInstancesPolicy,可精细控制 Spot/On-Demand 比例、竞价上限、实例池数量与分配策略(lowest-price/capacity-optimized/capacity-optimized-prioritized); - 字段互斥:
spotInstancePools与spotAllocationStrategy(capacity 类)互斥,instanceType与instancesDistribution互斥(仅允许"mixed"); - 节点识别:
node-lifecycle: spot|on-demand标签由 eksctl 引导脚本自动注入,可作为工作负载调度的可靠依据。
推荐从 examples/08-spot-instances.yaml 与 examples/26-managed-nodegroup-spot-instances.yaml 两个最小可用示例起步,先eksctl create cluster -f <file> --dry-run查看将要生成的资源,再实际落地到你的集群。
- 云原生
- 容器编排
- DevOps
【免费下载链接】eksctl
The official CLI for Amazon EKS
相关推荐
eksctl 0.33.0 发布解析:EKS 托管 Addon 支持与托管节点组 Spot 实例
eksctl 0.33.0 发布解析:EKS 托管 Addon 支持与托管节点组 Spot 实例 导读 本文围绕 eksctl 0.33.0 版本的两大核心特性
云原生容器编排DevOpseksctl v0.124.0 版本解读:Windows 托管节点组、Add-on 配置 Schema 查询与 Spot 分配策略
eksctl v0.124.0 版本解读:Windows 托管节点组、Add on 配置 Schema 查询与 Spot 分配策略 本文基于 eksctl 仓库
云原生容器编排DevOpseksctl v0.151.0 版本解读:为 Windows 自管节点组与 Ubuntu 托管节点组带来自定义 AMI 支持
eksctl v0.151.0 版本解读:为 Windows 自管节点组与 Ubuntu 托管节点组带来自定义 AMI 支持 本文基于 eksctl 仓库中的官
云原生容器编排DevOps
创作声明:本文部分内容由AI辅助生成(AIGC),仅供参考