AWS ECS, EC2, and Warm Pools: advantages and gotchas

  • tutorial
Warmed up and ready to join the game

Fargate vs. EC2 Auto Scaling groups

Fantastic warm pools and where to find them

Configuring warm pools

Create warm pool button
Warm pool settings
Warm pool instances
EC2AutoScalingGroupWarmPool:
  Type: AWS::AutoScaling::WarmPool
  Properties:
    AutoScalingGroupName: !Ref 'EC2AutoScalingGroup'
    InstanceReusePolicy:
      ReuseOnScaleIn: false

Gotcha #1: Premature registration in ECS

Agent disconnected warning
echo "ECS_WARM_POOLS_CHECK=true" >> /etc/ecs/ecs.config
[settings.autoscaling]
should-wait = true

Gotcha #2: The trap of the “Reuse on scale in” option

Admiral Ackbar: It's A Trap

Gotcha #3: AWS CloudFormation and UpdatePolicy

The first try: AutoScalingRollingUpdate

EC2AutoScalingGroup:
  Type: AWS::AutoScaling::AutoScalingGroup
  Properties:
    ...
  UpdatePolicy:
    AutoScalingRollingUpdate:
      MinInstancesInService: 1
      MaxBatchSize: 1
      PauseTime: PT15M
      SuspendProcesses:
        - HealthCheck
        - ReplaceUnhealthy
        - AZRebalance
        - AlarmNotification
        - ScheduledActions
      WaitOnResourceSignals: true
Christopher Walken: I don't know

The second try: AutoScalingReplacingUpdate

EC2AutoScalingGroup:
  Type: AWS::AutoScaling::AutoScalingGroup
  Properties:
    ...
  UpdatePolicy:
    AutoScalingReplacingUpdate:
      WillReplace: true

A moment of despair

The third try: A custom resource

# The IAM role for the Lambda function.
# It should have permission to start instance refreshes.
InstanceRefresherLambdaRole:
  Type: AWS::IAM::Role
  Properties:
    RoleName: !Sub "${AWS::StackName}-instance-refresher"
    AssumeRolePolicyDocument:
      Version: "2012-10-17"
      Statement:
        - Effect: Allow
          Principal:
            Service: lambda.amazonaws.com
          Action: sts:AssumeRole
    ManagedPolicyArns:
      - arn:aws:iam::aws:policy/service-role/AWSLambdaBasicExecutionRole
    Policies:
      - PolicyName: "autoscaling-start-instance-refresh"
        PolicyDocument:
          Version: "2012-10-17"
          Statement:
            - Effect: Allow
              Action:
                - autoscaling:StartInstanceRefresh
              Resource: "*"

# The Lambda function that will start the instance refresh on update or create.
# It will be triggered by the custom resource and requires the
# AutoScalingGroupName parameter.
InstanceRefresherLambda:
  Type: AWS::Lambda::Function
  Properties:
    FunctionName: !Sub "${AWS::StackName}-instance-refresher"
    Runtime: "python3.12"
    Handler: "index.handler"
    Role: !GetAtt "InstanceRefresherLambdaRole.Arn"
    Timeout: 30
    Code:
      ZipFile: |
        import cfnresponse
        import json
        import boto3

        client = boto3.client('autoscaling')

        def handler(event, context):
          response_data = {}

          try:
            if event['RequestType'] != 'Create' and event['RequestType'] != 'Update':
              cfnresponse.send(event, context, cfnresponse.SUCCESS, response_data, 'InstanceRefresher')
              return

            response = client.start_instance_refresh(
              AutoScalingGroupName=event['ResourceProperties']['AutoScalingGroupName'],
              Preferences={
                'MinHealthyPercentage': 100,
                'MaxHealthyPercentage': 200,
                'SkipMatching': True,
                'ScaleInProtectedInstances': 'Ignore',
                'StandbyInstances': 'Ignore'
              }
            )
            response_data['InstanceRefreshId'] = response['InstanceRefreshId']
            cfnresponse.send(event, context, cfnresponse.SUCCESS, response_data, 'InstanceRefresher')

          except Exception as e:
            response_data['exception'] = e.__str__()
            cfnresponse.send(event, context, cfnresponse.FAILED, response_data, 'InstanceRefresher')
EC2InstanceRefresher:
  Type: Custom::InstanceRefresher
  Properties:
    ServiceToken: !GetAtt "InstanceRefresherLambda.Arn"
    ServiceTimeout: '60'
    AutoScalingGroupName: !Ref "EC2AutoScalingGroup"
    # The Lambda function doesn't actually need EC2LaunchTemplate.
    # But we include it here to force the custom resource to run
    # when the Launch Template is updated.
    LaunchTemplate: !Ref "EC2LaunchTemplate"
    LaunchTemplateVersion: !GetAtt "EC2LaunchTemplate.LatestVersionNumber"

Start your free trial today

Or get imgproxy Pro on Cloud Marketplace