13

我最近开始使用 ECS。我能够在 ECR 中部署容器映像,并为我的容器创建具有 CPU/内存限制的任务定义。我的用例是每个容器都是一个长时间运行的应用程序(不需要网络服务器,不需要端口映射)。容器将一次按需求 1 生成,并按需求一次删除 1。

我能够创建一个包含 N 个服务器实例的集群。但我希望能够让服务器实例自动扩大/缩小。例如,如果集群中没有足够的 CPU/内存,我希望创建一个新实例。

如果有一个没有容器在其中运行的实例,我希望缩小/删除该特定实例。这是为了避免自动缩减终止其中具有正在运行的任务的服务器实例。

需要哪些步骤才能实现这一目标?

4

2 回答 2

7

考虑到您已经创建了 ECS 集群,AWS 提供了有关使用 CloudWatch 警报扩展集群实例的说明

假设您想根据内存预留来扩展集群,在较高级别上,您需要执行以下操作:

  1. 为您的 Auto Scaling 组创建启动配置。这个
  2. 创建一个 Auto Scaling Group,使集群的大小可以伸缩。
  3. 如果内存预留超过 70%,则创建 CloudWatch 警报以扩展集群
  4. 如果内存预留低于 30%,请创建 CloudWatch 警报以缩减集群

因为这更像是我的专长,所以我编写了一个示例CloudFormation模板,它应该可以帮助您开始了解其中的大部分内容:

Parameters:
  MinInstances:
    Type: Number
  MaxInstances:
    Type: Number
  InstanceType:
    Type: String
    AllowedValues:
      - t2.nano
      - t2.micro
      - t2.small
      - t2.medium
      - t2.large
  VpcSubnetIds:
    Type: String

Mappings:
  EcsInstanceAmis:
    us-east-2:
      Ami: ami-1c002379
    us-east-1:
      Ami: ami-9eb4b1e5
    us-west-2:
      Ami: ami-1d668865
    us-west-1:
      Ami: ami-4a2c192a
    eu-west-2:
      Ami: ami-cb1101af
    eu-west-1:
      Ami: ami-8fcc32f6
    eu-central-1:
      Ami: ami-0460cb6b
    ap-northeast-1:
      Ami: ami-b743bed1
    ap-southeast-2:
      Ami: ami-c1a6bda2
    ap-southeast-1:
      Ami: ami-9d1f7efe
    ca-central-1:
      Ami: ami-b677c9d2

Resources:
  Cluster:
    Type: AWS::ECS::Cluster
  Role:
    Type: AWS::IAM::Role
    Properties:
      ManagedPolicyArns:
        - arn:aws:iam::aws:policy/service-role/AmazonEC2ContainerServiceforEC2Role
      AssumeRolePolicyDocument:
        Version: 2012-10-17
        Statement:
          -
            Effect: Allow
            Action:
              - sts:AssumeRole
            Principal:
              Service:
                - ec2.amazonaws.com    
  InstanceProfile:
    Type: AWS::IAM::InstanceProfile
    Properties:
      Path: /
      Roles:
        - !Ref Role    
  LaunchConfiguration:
    Type: AWS::AutoScaling::LaunchConfiguration
    Properties:
      ImageId: !FindInMap [EcsInstanceAmis, !Ref "AWS::Region", Ami]
      InstanceType: !Ref InstanceType
      IamInstanceProfile: !Ref InstanceProfile
      UserData:
        Fn::Base64: !Sub |
          #!/bin/bash
          echo ECS_CLUSTER=${Cluster} >> /etc/ecs/ecs.config  
  AutoScalingGroup:
    Type: AWS::AutoScaling::AutoScalingGroup
    Properties:
      MinSize: !Ref MinInstances
      MaxSize: !Ref MaxInstances
      LaunchConfigurationName: !Ref LaunchConfiguration
      HealthCheckGracePeriod: 300
      HealthCheckType: EC2
      VPCZoneIdentifier: !Split [",", !Ref VpcSubnetIds]
    ScaleUpPolicy:
      Type: AWS::AutoScaling::ScalingPolicy
      Properties:
        AdjustmentType: ChangeInCapacity
        AutoScalingGroupName: !Ref AutoScalingGroup
        Cooldown: '1'
        ScalingAdjustment: '1'
    MemoryReservationAlarmHigh:
      Type: AWS::CloudWatch::Alarm
      Properties:
        EvaluationPeriods: '2'
        Statistic: Average
        Threshold: '70'
        AlarmDescription: Alarm if Cluster Memory Reservation is to high
        Period: '60'
        AlarmActions:
        - Ref: ScaleUpPolicy
        Namespace: AWS/ECS
        Dimensions:
        - Name: ClusterName
          Value: !Ref Cluster
        ComparisonOperator: GreaterThanThreshold
        MetricName: MemoryReservation
    ScaleDownPolicy:
      Type: AWS::AutoScaling::ScalingPolicy
      Properties:
        AdjustmentType: ChangeInCapacity
        AutoScalingGroupName: !Ref AutoScalingGroup
        Cooldown: '1'
        ScalingAdjustment: '-1'
    MemoryReservationAlarmLow:
      Type: AWS::CloudWatch::Alarm
      Properties:
        EvaluationPeriods: '2'
        Statistic: Average
        Threshold: '30'
        AlarmDescription: Alarm if Cluster Memory Reservation is to Low
        Period: '60'
        AlarmActions:
        - Ref: ScaleDownPolicy
        Namespace: AWS/ECS
        Dimensions:
        - Name: ClusterName
          Value: !Ref Cluster
        ComparisonOperator: LessThanThreshold
        MetricName: MemoryReservation

这将创建一个 ECS 集群、一个启动配置、一个 AutoScaling 组以及基于 ECS 内存预留的警报。

现在我们可以进行有趣的讨论了。

为什么我们不能根据 CPU 利用率内存预留进行扩展?

简短的回答是你完全可以,你可能会为此付出很多。EC2 有一个已知属性,即当您创建实例时,您至少需要支付 1 小时的费用,因为部分实例小时数按完整小时数计费。为什么这很重要,假设您有多个警报。假设您有一堆当前空闲运行的服务,并且您填充了集群。CPU 警报会缩小集群,或者内存警报会扩大集群。其中之一可能会将集群扩展到不再触发警报的程度。在冷却时间之后,另一个警报将撤消它的最后一个动作,在下一个冷却时间之后,该动作可能会被重做。因此实例被创建,然后在每隔一个冷却时间重复销毁。

考虑了一番之后,我想出的策略是基于 CPU 使用率的 ECS 服务的应用程序自动缩放和基于集群的内存预留。因此,如果一个服务正在热运行,则会添加一个额外的任务来分担负载。这将慢慢填满集群内存预留容量。当内存已满时,集群会向上扩展。当服务冷却时,服务将开始关闭任务。随着集群上的内存预留下降,集群将按比例缩小。

CloudWatch 警报的阈值可能需要根据您的任务定义进行试验。这样做的原因是,如果你将扩展阈值设置得太高,它可能不会随着内存的消耗而扩展,然后当自动扩展去放置另一个任务时,它会发现任何可用的内存都不够集群中的实例,因此无法放置另一个任务。

于 2017-09-14T05:18:29.267 回答
3

作为今年re:Invent大会的一部分,AWS 宣布了 Amazon ECS 的集群自动扩展。配置了 Auto Scaling 的集群现在可以在需要时添加更多容量并删除不必要的容量。您可以在文档中找到有关此的更多信息。

但是,根据您尝试运行的内容,AWS Fargate可能是更好的选择。Fargate 允许您在不预置和管理底层基础架构的情况下运行容器;即,您不必处理任何 EC2 实例。使用 Fargate,您可以进行 API 调用来运行您的容器,容器可以运行,然后一旦容器停止运行,就没有什么需要清理的了。Fargate 按每秒计费(最少 1 分钟),并根据分配的 CPU 和内存量定价(有关详细信息,请参阅此处)。

于 2019-12-10T22:58:39.167 回答