亚马逊AWS官方博客

Docker、Amazon ECS 和 Spot 队列:天作之合

来自于 AWS Container 精英 Tung Nguyen 的客座博文。Tung 是 BoltOps 的总裁和创始人,这是一家专注于 AWS 上的云基础架构和软件的咨询公司。他还喜欢为 BoltOps Nuts and Bolts 博客写稿。

EC2 Spot 实例让我可以以极低的折扣使用备用计算容量。将 Amazon ECS 与 Spot 实例一起使用可能是在 AWS 上运行我的工作负载的最佳方式之一。通过使用 Spot 实例,我可以在 Amazon EC2 实例上节省 50-90%。您可能会认为人们会像在黑色星期五特卖期间一样好好利用这个机会。但是,大多数人似乎不了解 Spot 实例或正在犹豫不决。这可能是由于一些对 Spot 的错误认识造成的。

关于 Spot 的错误认识

对于 Spot 模式,AWS 可以随时删除实例。这可能是由于维护升级;对该实例类型的高需求;较旧的实例类型;或出于任何原因。

因此,对于 Spot,人们会感到担心和产生误解,会问:

可以随时替换实例是什么意思? 哦不,意思肯定是说实例在启动的 20 分钟后会被终止。

我最初也是这么想的。Spot Instance Advisor 网站实际上写道:

所有区域和实例类型的平均中断频率小于 5%。

在我自己实际的使用过程中,我遇到过实例连续运行几周的情况。需要证明吗? 这是我们其中一个生产集群中的实例的屏幕截图。

如果您想知道那是多少天……

是的,连续 228 天。您可能无法实现这么长的运行时间,但它反驳了关于 Spot 实例的错误认识,Spot 实例并不会经常在启动的 20 分钟后出现中断。

Spot 队列

对于 Spot 实例,我对特定的可用区中的特定实例发出单个请求。对于 Spot 队列,我可以要求提供满足我要求的各种实例类型,而不是请求单个实例类型。对于许多工作负载而言,只要 CPU 和 RAM 足够接近,许多实例类型都差不多。

因此,我可以通过 Spot 队列将实例分散到各个实例类型和多个区域中。在已经提到的低中断率的基础上,使用 Spot 队列可以显著提高系统的稳健性。此外,我可以运行按需集群以提供额外的保障能力。

ECS 和 Spot 队列:天作之合

这是我运行工作负载最喜欢的方式之一,因为它以极低的成本为我提供了可扩展的系统。这些技术非常契合,人们可能会以为它们是为彼此而开发的。

  1. Docker 为部署提供了一致的标准二进制格式。如果它可以在一个 Docker 环境中使用,那么也可以在另一个 Docker 环境中使用。容器可以在几秒钟内下拉完成,使它们非常适用于 Spot 实例,因为在中断期间实例可能会进行移动。
  2. ECS 提供了一个运行 Docker 容器的强大生态系统。ECS 支持名为连接实例耗尽的功能,该功能允许我告诉 ECS 将 Docker 容器转移到其他 EC2 实例。
  3. Spot 实例会提前两分钟发出警告信号,告知我即将终止该实例。

这些是我在 Spot 队列之上构建 ECS 集群所必需的部分。我利用这两分钟的警告时间来调用 ECS 连接耗尽,ECS 会自动将容器转移到队列中的另一个实例。

这是一个实现此目的的 CloudFormation 模板:ecs-ec2-spot-fleet。由于重点是介绍 Spot 队列,因此对 VPC 做了简化处理。

该模板在 Spot 队列中指定了两种实例类型:t3.small 和 t3.medium,分别具有 2 GB 和 4 GB 的 RAM。在该模板中,t3.medium 的权重是 t3.small 的两倍。从本质上讲,Spot 队列 TargetCapacity 值等于为 ECS 集群预置的总 RAM。因此,如果我指定为 8,Spot 队列服务可能会预置四个 t3.small 实例或两个 t3.medium 实例。集群合计至少为 8 GB 的 RAM。

要启动堆栈运行,我运行以下命令:

aws cloudformation create-stack --stack-name ecs-spot-demo --template-body file://ecs-spot-demo.yml --capabilities CAPABILITY_IAM

CloudFormation 堆栈默认启动容器实例,并将其注册到名为 development ECS 集群。我可以使用 EcsCluster 参数对其进行更改。有关参数的更多信息,请参阅 README模板源

当我部署应用程序时,部署工具会自行创建 ECS 集群。以下是 EC2 控制台中的 Spot 实例。

部署演示应用程序

Spot 集群启动后,我可以在其上部署演示应用程序。我编写了一个名为 Ufo 的工具,可用于以下这些任务:

  1. 构建 Docker 映像。
  2. 注册 ECS 任务定义。
  3. 注册并部署 ECS 服务。
  4. 创建负载均衡器。

Docker 应作为先决条件先进行安装。首先,我创建 ECR 储存库并设置一些变量:

ECR_REPO=$(aws ecr create-repository --repository-name demo/sinatra | jq -r '.repository.repositoryUri')
VPC_ID=$(aws ec2 describe-vpcs --filters Name=tag:Name,Values="demo vpc" | jq -r '.Vpcs[].VpcId')

现在我准备克隆演示储存库,并使用 ufo 将示例应用程序部署到 ECS。

git clone https://github.com/tongueroo/demo-ufo.git demo
cd demo
ufo init --image $ECR_REPO --vpc-id $VPC_ID
ufo current --service demo-web
ufo ship # deploys to ECS on the Spot Fleet cluster

这是运行的 ECS 服务:

然后我从控制台或使用 ufo ps 获取 Elastic Load Balancing 端点。

$ ufo ps
Elb: develop-Elb-12LHJWU4TH3Q8-597605736.us-west-2.elb.amazonaws.com
$

现在使用 curl 进行测试:

$ curl develop-Elb-12LHJWU4TH3Q8-597605736.us-west-2.elb.amazonaws.com
42

应用程序成功返回“42”(表示正在运行)。就这么简单! 我现在有一个在 ECS 上的 Spot 队列实例中运行的应用程序。

寄语

使用 Spot 的另一个好处是它鼓励我从高度可用的角度思考架构。Spot 存在的“诸多限制”反倒是实现了更有效的夜间休眠,因为系统必须设计为可自我修复。

希望这篇文章能够为您开启在 Spot 实例上运行 ECS 之门。它是 BoltOps 在自己的生产系统和提供给客户的系统上运行的系统的核心部分。时至今日我仍然对这个设置感到兴奋。如果您对 Spot 架构感兴趣,请通过 BoltOps 与我联系。

最后一点:Auto Scaling 组还支持运行多个实例类型和购买选项。Jeff 在他的帖文中提到,权重支持计划在未来版本中发布。这令人兴奋,因为它可以进一步简化 Spot 与 ECS 的结合使用。