Как выполнить автоматическое масштабирование AWS CloudFormation для экземпляра ECS, когда в кластере недостаточно памяти - PullRequest
0 голосов
/ 27 апреля 2018

Я создал шаблон CloudFormation, который создает сервис и задачу ECS и имеет автоматическое масштабирование для задач. Это довольно просто - если MemoruUtilization для задач достигает определенного значения, тогда добавьте 1 задачу и наоборот. Вот некоторые из наиболее важных шаблонов деталей.

  EcsTd:
    Type: AWS::ECS::TaskDefinition
    DependsOn: LogGroup
    Properties:
      Family: !Sub ${EnvironmentName}-${PlatformName}-${Type}
      ContainerDefinitions:
      - Name: !Sub ${EnvironmentName}-${PlatformName}-${Type}
        Image: !Sub ${AWS::AccountId}.dkr.ecr.{AWS::Region}.amazonaws.com/${PlatformName}:${ImageVersion}
        Environment:
        - Name: APP_ENV
          Value: !If [isProd, "production", "staging"]
        - Name: APP_DEBUG
          Value: "false"
        ...

    PortMappings:
    - ContainerPort: 80
      HostPort: 0
    Memory: !Ref Memory
    Essential: true
  EcsService:
    Type: AWS::ECS::Service
    DependsOn: WaitForLoadBalancerListenerRulesCondition
    Properties:
      ServiceName: !Sub ${EnvironmentName}-${PlatformName}-${Type}
      Cluster:
        Fn::ImportValue: !Sub ${EnvironmentName}-ECS-${Type}
      DesiredCount: !Sub ${DesiredCount}
      TaskDefinition: !Ref EcsTd
      Role: "learningEcsServiceRole"
      LoadBalancers:
      - !If
        - isWeb
        - ContainerPort: 80
          ContainerName: !Sub ${EnvironmentName}-${PlatformName}-${Type}
          TargetGroupArn: !Ref AlbTargetGroup
        - !Ref AWS::NoValue
  ServiceScalableTarget:
    Type: "AWS::ApplicationAutoScaling::ScalableTarget"
    Properties:
      MaxCapacity: !Sub ${MaxCount}
      MinCapacity: !Sub ${MinCount}
      ResourceId: !Join
      - /
      - - service
        - !Sub ${EnvironmentName}-${Type}
        - !GetAtt EcsService.Name
      RoleARN: arn:aws:iam::645618565575:role/learningEcsServiceRole
      ScalableDimension: ecs:service:DesiredCount
      ServiceNamespace: ecs

  ServiceScaleOutPolicy:
    Type : "AWS::ApplicationAutoScaling::ScalingPolicy"
    Properties:
      PolicyName: !Sub ${EnvironmentName}-${PlatformName}-${Type}- ScaleOutPolicy
      PolicyType: StepScaling
      ScalingTargetId: !Ref ServiceScalableTarget
      StepScalingPolicyConfiguration:
        AdjustmentType: ChangeInCapacity
        Cooldown: 1800
        MetricAggregationType: Average
        StepAdjustments:
        - MetricIntervalLowerBound: 0
          ScalingAdjustment: 1
  MemoryScaleOutAlarm:
    Type: AWS::CloudWatch::Alarm
    Properties:
      AlarmName: !Sub ${EnvironmentName}-${PlatformName}-${Type}-MemoryOver70PercentAlarm
      AlarmDescription: Alarm if memory utilization greater than 70% of reserved memory
      Namespace: AWS/ECS
      MetricName: MemoryUtilization
      Dimensions:
      - Name: ClusterName
        Value: !Sub ${EnvironmentName}-${Type}
      - Name: ServiceName
        Value: !GetAtt EcsService.Name
      Statistic: Maximum
      Period: '60'
      EvaluationPeriods: '1'
      Threshold: '70'
      ComparisonOperator: GreaterThanThreshold
      AlarmActions:
      - !Ref ServiceScaleOutPolicy
      - !Ref EmailNotification

  ...

Так что, когда когда-либо задача начинает исчерпывать память, мы добавляем новую задачу. Однако в какой-то момент мы достигнем предела, сколько памяти доступно в нашем кластере.

Так, например, Cluster состоит из одного экземпляра t2.small, тогда у нас есть 2 Гб оперативной памяти. Небольшое количество этого используется в задаче ECS, работающей в инстансе, поэтому у нас меньше 2 ГБ ОЗУ. Если мы установим значение памяти Task в 512Mb, тогда мы сможем поместить только 3 задачи в этот кластер, если не будем увеличивать кластер.

По умолчанию служба ECS имеет метрики MemoryReservation, которые можно использовать для автоматического масштабирования кластера. Мы сказали бы, что когда MemoryReservation более чем на 75%, тогда добавьте 1 экземпляр в кластер. Это относительно просто.

EcsCluster:
    Type: AWS::ECS::Cluster
    Properties:
      ClusterName: !Sub ${EnvironmentName}-${Type}
  SgEcsHost:
    ...
  ECSLaunchConfiguration:
    Type: AWS::AutoScaling::LaunchConfiguration
    Properties:
      ImageId: !FindInMap [AWSRegionToAMI, !Ref 'AWS::Region', AMIID]
      InstanceType: !Ref InstanceType
      SecurityGroups: [ !Ref SgEcsHost ]
      AssociatePublicIpAddress: true
      IamInstanceProfile: "ecsInstanceRole"
      KeyName: !Ref KeyName
      UserData:
        Fn::Base64: !Sub |
          #!/bin/bash
          echo ECS_CLUSTER=${EnvironmentName}-${Type} >> /etc/ecs/ecs.config
  ECSAutoScalingGroup:
    Type: AWS::AutoScaling::AutoScalingGroup
    Properties:
      VPCZoneIdentifier:
      - Fn::ImportValue: !Sub ${EnvironmentName}-SubnetEC2AZ1
      - Fn::ImportValue: !Sub ${EnvironmentName}-SubnetEC2AZ2
      LaunchConfigurationName: !Ref ECSLaunchConfiguration
      MinSize: !Ref AsgMinSize
      MaxSize: !Ref AsgMaxSize
      DesiredCapacity: !Ref AsgDesiredSize
      Tags:
      - Key: Name
        Value: !Sub ${EnvironmentName}-ECS
        PropagateAtLaunch: true
  ScalePolicyUp:
    Type: AWS::AutoScaling::ScalingPolicy
    Properties:
      AdjustmentType: ChangeInCapacity
      AutoScalingGroupName:
        Ref: ECSAutoScalingGroup
      Cooldown: '1'
      ScalingAdjustment: '1'
  MemoryReservationAlarm:
    Type: AWS::CloudWatch::Alarm
    Properties:
      EvaluationPeriods: '1'
      Statistic: Average
      Threshold: '75'
      AlarmDescription: Alarm if MemoryReservation is more then 75%
      Period: '60'
      AlarmActions:
      - Ref: ScalePolicyUp
      - Ref: EmailNotification
      Namespace: AWS/EC2
      Dimensions:
      - Name: AutoScalingGroupName
        Value:
          Ref: ECSAutoScalingGroup
      ComparisonOperator: GreaterThanThreshold
      MetricName: MemoryReservation

Однако это не имеет смысла, потому что это произойдет, когда будет добавлено третье задание, поэтому новый экземпляр будет пустым до масштабирования четвертого задания. Это означает, что мы будем платить, например, за то, что мы не используем.

Я заметил, что когда служба ECS пытается добавить задачу в кластер, где недостаточно свободной памяти, я получаю

Служба Production-admin-worker не смогла разместить задачу из-за отсутствия экземпляр контейнера отвечал всем его требованиям. Самое близкое соответствие контейнер-экземпляр ################### имеет недостаточно памяти.

В этом примере параметры шаблона:

EnvironmentName=Production
PlatformName=Admin
Type=worker

Можно ли создать AWS :: CloudWatch :: Alarm, который просматривает события кластера ECS и ищет этот конкретный шаблон? Идея состоит в том, чтобы увеличить количество экземпляров в кластере, используя AWS::AutoScaling::AutoScalingGroup, только когда AWS::ApplicationAutoScaling::ScalingPolicy добавляет задачи, в которых нет места в кластере. И уменьшите размер кластера, когда MemoryReservation меньше 25% (это означает, что там нет запущенных задач - AWS::ApplicationAutoScaling::ScalingPolicy их удалило).

1 Ответ

0 голосов
/ 03 мая 2018

Это означает, что мы будем платить за то, что мы не используем.

Либо вы заранее платите за дополнительную / резервную емкость, либо внедряете логику, чтобы повторить попытки сбоев из-за низкой емкости.

Несколько способов придумать:

  • Вы можете создать собственный скрипт / лямбда (https://forums.aws.amazon.com/thread.jspa?threadID=94984)), который сообщает показатель метрики load_factor, рассчитанный как number of tasks / number of instances, а затем основывать свою политику автоматического масштабирования на этом. Лямбда может запускаться правилом CW ,
    • Вы также можете сообщить об этом из своей задачи вместо новой пользовательской лямбды / скрипта.
  • Создание фильтра метрики , который ищет определенный шаблон в файле / группе журналов и сообщает о метрике. Затем, конечно, используйте эту метрику для масштабирования.

Из документов:

Когда фильтр метрик находит одно из терминов, фраз или значений в ваших событиях журнала, вы можете увеличить значение метрики CloudWatch.

Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...