EKS 与 EC2 Spot 最佳实践

前段时间去参加了 KubeCon 2019,听了胖虎老师的演讲,非常棒,在这里分享一下,希望给大家一些启发。

EC2 Spot

EC2 Spot 实例可以利用 AWS 云中未使用的 EC2 资源。与按需实例的价格相比,使用 Spot 实例最高可以享受 90%的折扣。可以将 Spot 实例用于各种无状态、容错或者灵活的应用程序,例如大数据、容器化工作负载、CI/CD、Web服务器、高性能计算 (HPC) 以及其他测试和开发工作负载。Spot 实例与 Auto Scaling、EMR、ECS、CloudFormation、Data Pipeline 和 AWS Batch 等 AWS 服务紧密集成,因此可以选择如何启动和维护 Spot 实例上运行的应用程序。

EKS 结合 EC2 Spot

由于 Kubernetes 维持副本期望状态,Spot 特别适合来创建一个高可用兼顾费用优化的 Kubernetes 集群。我们会利用 Auto Scaling Group多个实例类型与购买选项的新特性,将一个数量的 on-demand 实例与 Spot 实例混合在 一个 Auto Scaling Group 当中,除了保证具有一定的基线数量(baseline)由 on-demand 支撑之外,整个集群的横向扩展则由 Spot 与指定比例的 on-demand 来进行扩展。

架构图

upload successful

  • 使用 ASG 创建一个 node group,并且注册到 EKS 的 control plane。
  • 这个 ASG 由若干个数量的 on-demand 与 spot 组成。
  • Spot 一旦面临关机事件,会触发一个关机事件处理机制(termination handing),提前对 Spot 实例进行 node draining,确保上面运行的 Pod 可以提前被重新调度(reschedule)到其他节点。
创建 EKS 集群
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
---
apiVersion: eksctl.io/v1alpha5
kind: ClusterConfig

metadata:
name: eksdemo
region: ap-northeast-1

nodeGroups:
- name: ng-1
minSize: 4
maxSize: 8
instancesDistribution:
instanceTypes: ["t3.small", "t3.medium", "t3.large"] # At least two instance types should be specified
onDemandBaseCapacity: 2
onDemandPercentageAboveBaseCapacity: 0
spotInstancePools: 2

通过以上配置清单利用 eksctl 就可以在 ap-northeast-1 region 创建一个名为 eksdemo 的 EKS 集群,同时建立起一个名为 ng-1的nodegroup ,当中由多种 instance types 组成,其中 OnDemand 基线(baseline)为 2,意味着保证会有两台 on-demand 实例,而其他的实例则由 ondemand+spot 组成,但由于我们定义了 onDemandPercentageAboveBaseCapacity 为 0, 意味着额外需要的两台实例(minSize-onDemandBaseCapacity)全部由 spot 来满足。关于 ASG 更多参数可以参考该 链接,更多的 cluster YAML 配置示例可以参考 weaveworks 的 github

使用 eks-refarch 模板创建

除了使用 eksctl 之外,也可以透过 aws-samples/amazon-eks-refarch-cloudformation 来创建这样的混合集群,amazon-eks-refarch-cloudformation 使用100%的 cloudformation 模版,并且提供丰富的特性。

node labels, taints and tolerations

通过 eks-templates 模版创建的混合集群,会自动将 ondemand 与 spot 实例都打上不同的 node labels,同时也会对 Spot 打上相应的 taints。

验证集群

通过 kubectl get nodes –show-labels 列出所有节点,可以看到 ondemand 与 Spot 各自带上了不同的 lifecycle 标签。
upload successful
在 EC2 Console,查看 Auto Scaling Group,会看到相应的配置。
upload successful

部署 eks-lambda-drainer

Spot 实例当面临资源回收,强迫被关机的时候,系统会提前两分钟收到通知,我们可以借由 CloudWatch Event 捕捉到这个通知信息出发一个外部调度的 Lambda function 对这个节点进行 node draining。eks-lambda-drainer 可以帮助我们部署一个完全 serverless 独立于 Kubernetes 集群之外的无服务器时间响应 handler,并且监听整个 VPC 内的 Spot实例关机信号,一旦提前两分钟获得关机信号就会对这个节点进行 kubectl drain 操作,确保节点上的Pod 能被及时重新调度到其他节点上运行。

关于 eks-lambda-drainer 的部署方式,可以参考这个 Github

测试 Spot实例 关机事件处理

eks-lambda-drainer 部署完成,当 Spot 实例准备关机的时候,eks-lambda-drainer 会开始进行相应处理,从 Lambda Log 可以看到如下的信息,表示确实对 node 节点进行了 kubectl drain 的操作。

总结

EKS 结合 EC2 Spot 是一个非常好的组合,常见的部署模式是把重要的controller 或 agent 指定部署到 on demand 节点,而其他应用则部署到 Spot 实例,甚至也可以全部都部署到 Spot 实例。只要在 ASG 里面选择多种节点类型,并且同时选择至少三个 AZ,如此 ASG 就会尽可能维护所需要的节点数量保证一定的高可用性。

公开案例

知名在线旅游服务商 Skyscanner 在 This is My Architecture系列影片当中揭露了他们在 AWS上面构建 Kubernetes 集群,横跨全球多个区域,多个集群,尖峰时间支撑每秒 60-75K QPS,以及每个月8千万个月独立用户,全部100% 使用 EC2 Spot 实例构建 Kubernetes 集群。

SkyScanner: Building Highly-Available, Multi-Region Kubernetes Clusters on 100% Amazon EC2 Spot
upload successful

-------------本文结束感谢您的阅读-------------