在 Spinnaker 中构建多元化且成本优化的 EC2 服务器组

作者: 希拉·布瑟 | 2023 年 3 月

这篇博客文章由高级专业容器股份公司桑迪普·帕拉瓦拉萨和软件开发工程师 Prathibha Datta-Kumar 撰写

Spinnaker 是 Netflix 创建的开源持续交付平台,用于快速可靠地发布软件变更。它使团队能够自动部署到管道中,每当发布新版本时,管道就会运行,这些管道采用久经考验的 部署策略 ,更快、更可靠,停机时间为零。对于许多 亚马逊云科技 客户来说,Spinnaker 是一项关键技术,它允许开发人员在不同的 亚马逊云科技 托管服务上安全可靠地部署应用程序。

在听取客户对 Spinnaker 开源项目 和亚马逊 EC2 竞价型实例集成路线图 的要求后 ,我们进一步增强了 Spinnaker 在 亚马逊弹性计算云 (Amazon EC2)上的部署能力。 这些增强功能可以更轻松地将竞价型实例与 按需 预留 储蓄计划 实例相结合,从而优化工作负载成本和性能。在灵活使用实例类型和可用区的情况下,使用具有 分配策略 和主动 竞价容量再平衡等功能的竞价 型实例时 ,可以提高工作负载的可用性。将亚马逊 EC2 与 Spinnaker 结合使用时,这些功能的组合可提供最佳体验。

在这篇文章中,我们将详细介绍最近的增强功能,以及如何按照 最佳实践 使用它们。

亚马逊 EC2 竞价型实例

EC2 竞价型实例 是 亚马逊云科技 云中的备用计算容量,与 按需实例价格 相比,可享受高达 90% 的大幅折扣 。按需实例和竞价型实例之间的主要区别在于,当 Amazon EC2 需要恢复容量时,Amazon EC2 可以通过两分钟通知来 中断 竞价型实例。现在, 当竞价型实例的中断风险较高时,Amazon EC2 会发送 再平衡建议通知 。该信号可能比两分钟的中断通知更早到达。这使您可以在竞价型实例中断之前主动更换竞价型实例。

遵守竞价最佳 实践 和实例队列管理 的最佳 方法是使用 Amazon EC2 Auto Scaling 组。在 Auto Scaling 组 中使用竞价型实例 时,启用 容量再平衡 功能可通过在 Amazon EC2 中断正在运行的实例之前主动使用新的竞价型实例来增强队列来帮助您保持工作负载可用性。

三角帆概念

Spinnaker 使用三个关键 概念 来描述您的服务,包括 应用程序 集群 服务器组 ,您的服务如何向用户公开,用负载均衡器和防火墙来表达。

应用程序是集群的集合,集群是服务器组的集合,服务器组标识可部署的项目和基本配置设置,例如实例数量、自动扩展策略、元数据等。这与 亚马逊云科技 中的 Aut o Scaling 组 相对应。在这篇文章中,我们将交替使用 Auto Scaling 组和服务器组。

三角帆和亚马逊 EC2 集成

2020 年年中,我们开始研究 Spinnaker 支持的亚马逊 EC2 功能集中的客户请求和差距。大约在同一时间,Spinnaker OSS 增加了对 亚马逊 EC2 启动模板 的支持。 在他们的努力下,我们可以跟踪和扩展 Spinnaker 中支持的 Amazon EC2 功能集。现在我们已经了解了新功能,让我们在下面的教程 s pinnak er.io 中看看如何使用其中的一些功能。

以下是最近贡献的一些功能亮点:

Feature Why use it? (Example use cases)
  Multiple Instance Types   Tap into multiple capacity pools to achieve and maintain the desired scale using Spot Instances.
  Combining On-Demand and Spot Instances

— 控制在服务器组中启动的按需和竞价型实例的比例。

— 将竞价型实例与 Amazon EC2 预留实例或储蓄计划相结合。

  Amazon EC2 Auto Scaling allocation strategies   Reduce overall Spot interruptions by launching from Spot pools that are optimally chosen based on the available Spot capacity, using capacity-optimized Spot allocation strategy.
  Capacity rebalancing   Improve your workload availability by proactively shifting your Spot capacity to optimal pools by enabling capacity rebalancing along with capacity-optimized allocation strategy.
  Improved support for burstable performance instance types with custom credit specification   Reduce costs by preventing wastage of CPU cycles.

我们建议 API 用户使用 Spinnaker 稳定版 1.28.x,用户界面用户使用 1.29.x。这是相关 PR 和功能版本 的 Git 问题

现在我们已经了解了新功能,让我们在下面的教程中看看如何使用其中的一些功能。

示例教程:使用按需和竞价型实例在自动扩展组上部署演示 Web 应用程序

在本示例教程中,我们将 Spinnaker 设置为部署到 Amazon EC2,创建 应用程序负载均衡器 ,并在具有多种实例类型和购买选项的服务器组上部署演示应用程序,本例中为按需和竞价型实例。

在整个教程中,我们将利用 Spinnaker 的 API 来创建新资源,并提供有关如何使用 Spinnaker UI(Deck)部署相同资源并利用 UI 查看资源的快速指南。

先决条件

作为完成本教程的先决条件,您必须拥有一个具有 亚马逊云科技 身份和访问管理 (IAM) 用户的 A WS 账户 ,该用户将管理员访问配置为与 A WS 命令行接口 (亚马逊云科技 CLI) 一起 使用。

1。三角帆设置

我们将使用 亚马逊云科技 CloudFormation 模板 setup-spinnaker-with-deployment-vpc.yml 来设置 Spinnaker 和所需的资源

1.1 创建用于连接 Spinnaker 和 Spinnaker 启动的 EC2 实例的安全外壳 (SSH) 密钥对。

AWS_REGION=us-west-2 # Change the region where you want Spinnaker deployed
EC2_KEYPAIR_NAME=spinnaker-blog-${AWS_REGION}
aws ec2 create-key-pair --key-name ${EC2_KEYPAIR_NAME} --region ${AWS_REGION} --query KeyMaterial --output text > ~/${EC2_KEYPAIR_NAME}.pem
chmod 600 ~/${EC2_KEYPAIR_NAME}.pem

1.2 部署 Cloudformation 堆栈。

STACK_NAME=spinnaker-blog
SPINNAKER_VERSION=1.29.1 # Change the version if newer versions are available
NUMBER_OF_AZS=3
AVAILABILITY_ZONES=${AWS_REGION}a,${AWS_REGION}b,${AWS_REGION}c
ACCOUNT_ID=$(aws sts get-caller-identity --query "Account" --output text)
S3_BUCKET_NAME=spin-persitent-store-${ACCOUNT_ID}

# Download template
curl -o setup-spinnaker-with-deployment-vpc.yml https://raw.githubusercontent.com/awslabs/ec2-spot-labs/master/ec2-spot-spinnaker/setup-spinnaker-with-deployment-vpc.yml

# deploy stack
aws cloudformation deploy --template-file setup-spinnaker-with-deployment-vpc.yml \
    --stack-name ${STACK_NAME} \
    --parameter-overrides NumberOfAZs=${NUMBER_OF_AZS} \
    AvailabilityZones=${AVAILABILITY_ZONES} \
    EC2KeyPairName=${EC2_KEYPAIR_NAME} \
    SpinnakerVersion=${SPINNAKER_VERSION} \
    SpinnakerS3BucketName=${S3_BUCKET_NAME} \
    --capabilities CAPABILITY_NAMED_IAM --region ${AWS_REGION}

1.3 连接到三角帆

1.3.1 获取 SSH 命令转发 Deck(基于浏览器的用户界面(9000)和 Gate(API Gateway(8084)的端口转发,以访问 Spinnaker 用户界面和 API。

SPINNAKER_INSTANCE_DNS_NAME=$(aws cloudformation describe-stacks --stack-name ${STACK_NAME} --region ${AWS_REGION} --query "Stacks[].Outputs[?OutputKey=='SpinnakerInstance'].OutputValue" --output text)
echo 'ssh -A -L 9000:localhost:9000 -L 8084:localhost:8084 -L 8087:localhost:8087 -i ~/'${EC2_KEYPAIR_NAME}' ubuntu@$'{SPINNAKER_INSTANCE_DNS_NAME}''

1.3.2 打开一个新终端并使用 SSH 命令(上一个命令的输出)连接到 Spinnaker 实例。 通过 SSH 成功连接到 Spinnaker 实例后,请在此处访问 Spinnaker 用户界面, 在此处 访问 API。

2。部署演示 Web 应用程序

在继续操作之前,让我们确保在 shell 中拥有所需的环境变量。如果你使用与以前相同的终端窗口,那么你可能已经有了这些变量。

STACK_NAME=spinnaker-blog
亚马逊云科技_REGION=us-west-2 # use the same region as before
EC2_KEYPAIR_NAME=spinnaker-blog-${亚马逊云科技_REGION}
VPC_ID=$(aws cloudformation describe-stacks --stack-name ${STACK_NAME} --region ${亚马逊云科技_REGION} --query "Stacks[].Outputs[?OutputKey=='VPCID'].OutputValue" --output text)

2.1 创建三角帆应用程序

我们首先在 Spinnaker 中创建一个应用程序,它是我们部署的服务的占位符。

curl 'http://localhost:8084/tasks' \
-H 'Content-Type: application/json;charset=utf-8' \
--data-raw \
'{
   "job":[
      {
         "type":"createApplication",
         "application":{
            "cloudProviders":"aws",
            "instancePort":80,
            "name":"demoapp",
            "email":"test@test.com",
            "providerSettings":{
               "aws":{
                  "useAmiBlockDeviceMappings":true
               }
            }
         }
      }
   ],
   "application":"demoapp",
   "description":"Create Application: demoapp"
}'

Spin Create Server Group

2.2 创建应用程序负载均衡器

让我们创建一个应用程序负载均衡器和端口 80 的目标组,跨越公有子网中的三个可用区。我们使用防火墙 演示-ALB-SecurityGroup 来允许公众通过端口 80 访问 ALB。

由于竞价型实例会中断并发出两分钟警告,因此您必须将目标组的 取消注册延迟 调整 为稍微缩短的时间。建议值为 90 秒 或更短。这使正在运行的请求有时间在实例中断之前完成并正常关闭现有连接。

curl 'http://localhost:8084/tasks' \
-H 'Content-Type: application/json;charset=utf-8' \
--data-binary \
'{
   "application":"demoapp",
   "description":"Create Load Balancer: demoapp",
   "job":[
      {
         "type":"upsertLoadBalancer",
         "name":"demoapp-lb",
         "loadBalancerType":"application",
         "cloudProvider":"aws",
         "credentials":"my-aws-account",
         "region":"'"${AWS_REGION}"'",
         "vpcId":"'"${VPC_ID}"'",
         "subnetType":"public-subnet",
         "idleTimeout":60,
         "targetGroups":[
            {
               "name":"demoapp-targetgroup",
               "protocol":"HTTP",
               "port":80,
               "targetType":"instance",
               "healthCheckProtocol":"HTTP",
               "healthCheckPort":"traffic-port",
               "healthCheckPath":"/",
               "attributes":{
                  "deregistrationDelay":90
               }
            }
         ],
         "regionZones":[
            "'"${AWS_REGION}"'a",
            "'"${AWS_REGION}"'b",
            "'"${AWS_REGION}"'c"
         ],
         "securityGroups":[
            "Demo-ALB-SecurityGroup"
         ],
         "listeners":[
            {
               "protocol":"HTTP",
               "port":80,
               "defaultActions":[
                  {
                     "type":"forward",
                     "targetGroupName":"demoapp-targetgroup"
                 }
               ]
            }
         ]
      }
   ]
}'

Spin Create ALB

2.3 创建服务器组

在创建服务器组(Auto Scaling 组)之前,以下是示例中 使用的 功能 的简要概述:

      • onDemandBaseCapacity (默认为 0): 必须由按需实例提供的 ASG 的最低容量(也可以应用于预留实例或储蓄计划)。该示例使用三个 OnDemandBas eCapacity。
      • OnDemandPercentageAboveBaseCapacity ( 默认 100) :超出 OnDemandBaseCapacity 额外容量的按需实例和竞价型实例的百分比。 该示例使用了 10%(即 90 % 现货)的 onDemandPercentageAboveBase Capacity。
      • SpotAllocationSt rategy :这表明您希望如何在每个可用区的竞价型实例池中分配实例。该示例使用推荐的 容量优化 策略。实例是从最佳竞价池中启动的,这些池是根据启动的实例数量的可用竞价容量选择的。
      • launchTemplateOverridesforInstanceType :适用于您的工作负载的实例类型列表。指定多个实例类型可以利用多个可用区中的多个实例池,旨在增强服务的可用性。您可以使用 ec2-instance-selec tor(一种开源 亚马逊云科技 命令行接口 (CLI) 工具)根据 vcpus 和内存等资源标准来缩小实例类型的范围。
      • 容量再平衡 :启用后,此功能会利用新的 EC2 实例 再平衡建议主动管理 EC 2 竞价型实例 生命周期。 通过在 ASG 中断竞价型实例被 Amazon EC2 中断之前,自动尝试替换 ASG 中的竞价型实例,从而提高了对可用性的重视。我们在这个例子中启用了这个功能。

了解有关 sp innaker.io 的更多信息 : 功能描述 用例以及 API 请求示例。

让我们创建一个服务器组,其所需容量为 12 个实例,涵盖当前和上一代实例类型,附加之前创建的 ALB,使用仅允许来自 ALB 的 http 流量的防火墙的 demo-ec2-SecurityGrou p,使用以下 bash 脚本安装 http,并将实例元 数据添加 到 index.html 中。

2.3.1 将用户数据 bash 脚本保存到 user-date.sh 文件中。

请注意,三角帆仅支持 base64 编码的用户数据。在下一步中,我们将使用 b ase64 b ash 命令对文件内容进行编码。

cat << "EOF" > user-data.sh
#!/bin/bash
yum update -y
yum install httpd -y
echo "<html>
    <head>
        <title>Demo Application</title>
        <style>body {margin-top: 40px; background-color: #Gray;} </style>
    </head>
    <body>
        <h2>You have reached a Demo Application running on</h2>
        <ul>
            <li>instance-id: <b> `curl http://169.254.169.254/latest/meta-data/instance-id` </b></li>
            <li>instance-type: <b> `curl http://169.254.169.254/latest/meta-data/instance-type` </b></li>
            <li>instance-life-cycle: <b> `curl http://169.254.169.254/latest/meta-data/instance-life-cycle` </b></li>
            <li>availability-zone: <b> `curl http://169.254.169.254/latest/meta-data/placement/availability-zone` </b></li>
        </ul>
    </body>
</html>" > /var/www/html/index.html
systemctl start httpd
systemctl enable httpd
EOF

2.3.2 通过运行以下命令创建服务器组。请注意,我们使用创建的 KeypairName 作为先决条件的一部分。

curl 'http://localhost:8084/tasks' \
-H 'Content-Type: application/json;charset=utf-8' \
-d \
'{
   "job":[
      {
         "type":"createServerGroup",
         "cloudProvider":"aws",
         "account":"my-aws-account",
         "application":"demoapp",
         "stack":"",
         "credentials":"my-aws-account",
	"healthCheckType": "ELB",
	"healthCheckGracePeriod":600,
	"capacityRebalance": true,
         "onDemandBaseCapacity":3, 
         "onDemandPercentageAboveBaseCapacity":10,
         "spotAllocationStrategy":"capacity-optimized",
         "setLaunchTemplate":true,
         "launchTemplateOverridesForInstanceType":[
            {
               "instanceType":"m4.large"
            },
            {
               "instanceType":"m5.large"
            },
            {
               "instanceType":"m5a.large"
            },
            {
               "instanceType":"m5ad.large"
            },
            {
               "instanceType":"m5d.large"
            },
            {
               "instanceType":"m5dn.large"
            },
            {
               "instanceType":"m5n.large"
            }

         ],
         "capacity":{
            "min":6,
            "max":21,
            "desired":12
         },
         "subnetType":"private-subnet",
         "availabilityZones":{
            "'"${AWS_REGION}"'":[
               "'"${AWS_REGION}"'a",
               "'"${AWS_REGION}"'b",
               "'"${AWS_REGION}"'c"
            ]
         },
         "keyPair":"'"${EC2_KEYPAIR_NAME}"'",
         "securityGroups":[
            "Demo-EC2-SecurityGroup"
         ],
         "instanceType":"m5.large",
         "virtualizationType":"hvm",
         "amiName":"'"$(aws ec2 describe-images --owners amazon --filters "Name=name,Values=amzn2-ami-hvm-2*x86_64-gp2" --query 'reverse(sort_by(Images, &CreationDate))[0].Name' --region ${AWS_REGION} --output text)"'",
         "targetGroups":[
            "demoapp-targetgroup"
         ],
         "base64UserData":"'"$(base64 user-data.sh)"'",,
        "associatePublicIpAddress":false,
         "instanceMonitoring":false
      }
   ],
   "application":"demoapp",
   "description":"Create New server group in cluster demoapp"
}'

Spin Create ServerGroup

Spinnaker 会创建一个 Amazon EC2 启动模板 和一个带有指定参数的 ASG,并等到 ALB 运行状况检查通过后再向 EC2 实例发送流量。

我们刚刚创建的服务器组和启动模板在 Spinnaker UI 中将如下所示:

Spin View ServerGroup

用户界面还显示容量类型,例如实例信息 部分中每种 实例类型的购买选项:

Spin View ServerGroup Purchase Options 1 Spin View ServerGroup Purchase Options 2

3。访问应用程序

选择服务器组右上角的树形图标复制应用程序负载均衡器 URL,然后在浏览器中进行访问。您可以多次刷新,以查看请求每次都会发送到不同的实例。

Spin Access App

恭喜!您成功地将演示应用程序部署到分散在多种实例类型和购买选项的 Amazon EC2 服务器组上。

此外,您可以克隆、修改、禁用和销毁这些服务器组,也可以将它们与 Spinnaker 管道 一起使用, 以有效发布应用程序的新版本。

节省成本

前往 EC2 控制台 > 竞价请求 > 保存摘要,查看在 EC2 竞价型实例上部署演示应用程序所节省的费用。

Spin Spot Savings

清理

为避免产生任何额外费用,请清理本教程中创建的资源。

首先,删除 Spinnaker 中的服务器组、应用程序负载均衡器和应用程序。

curl 'http://localhost:8084/tasks' \
-H 'Content-Type: application/json;charset=utf-8' \
--data-raw \
'{
   "job":[
      {
         "reason":"Cleanup",
         "asgName":"demoapp-v000",
         "moniker":{
            "app":"demoapp",
            "cluster":"demoapp",
            "sequence":0
         },
         "serverGroupName":"demoapp-v000",
         "type":"destroyServerGroup",
         "region":"'"${AWS_REGION}"'",
         "credentials":"my-aws-account",
         "cloudProvider":"aws"
      },
      {
         "cloudProvider":"aws",
         "loadBalancerName":"demoapp-lb",
         "loadBalancerType":"application",
         "regions":[
            "'"${AWS_REGION}"'"
         ],
         "credentials":"my-aws-account",
         "vpcId":"'"${VPC_ID}"'",
         "type":"deleteLoadBalancer"
      },
      {
         "type":"deleteApplication",
         "application":{
            "name":"demoapp",
            "cloudProviders":"aws"
         }
      }
   ],
   "application":"demoapp",
   "description":"Deleting ServerGroup, ALB and Application: demoapp"
}'

等待 Spinnaker 删除所有资源,然后再继续操作。您可以在 Spinnaker 用户界面或 亚马逊云科技 管理 控制台上确认这一点。

然后通过运行以下命令删除 Spinnaker 基础架构:

aws ec2 delete-key-pair --key-name ${EC2_KEYPAIR_NAME} --region ${亚马逊云科技_REGION}
rm ~/${EC2_KEYPAIR_NAME}.pem
aws s3api delete-objects \
--bucket ${S3_BUCKET_NAME} \
--delete "$(aws s3api list-object-versions \
--bucket ${S3_BUCKET_NAME} \
--query='{Objects: Versions[].{Key:Key,VersionId:VersionId}}')" #If error occurs, there are no Versions and is OK
aws s3api delete-objects \
--bucket ${S3_BUCKET_NAME} \
--delete "$(aws s3api list-object-versions \
--bucket ${S3_BUCKET_NAME} \
--query='{Objects: DeleteMarkers[].{Key:Key,VersionId:VersionId}}')" #If error occurs, there are no DeleteMarkers and is OK
aws s3 rb s3://${S3_BUCKET_NAME} --force #Delete Bucket
aws cloudformation delete-stack --region ${亚马逊云科技_REGION} --stack-name ${STACK_NAME}

结论

在这篇文章中,我们了解了最近添加到 Spinnaker 中的 Amazon EC2 新功能,以及如何使用它们来构建多元化和优化的自动扩展组。我们还讨论了 推荐的 EC2 Spot 最佳实践 ,以及它们如何改善您的使用体验。

我们很乐意听取你的意见! 通过在 Spot 集成路线图上添加问题,告诉我们您想在 EC2 Spot 和/或自动扩展组中使用的其他持续集成/持续交付 (CI/CD) 平台。